Ich versuche, ein JMP-Skript zu schreiben, um Mentee / Mentor-Übereinstimmungen für ein Mentoring-Programm in meinem Unternehmen zu erstellen. Ich habe den Teil, der die Rangfolgepräferenzen von Mentee und Mentor berücksichtigt, der zu einer Matrix bevorzugter Mentoren für jeden Mentee nach Rang führt (1 ist der beste und 10 ist der schlechteste). Das Problem, auf das ich stoße, ist, wie ich damit umgehen soll, wenn es mehrere Mentees mit demselben Mentor in einem bestimmten Rang gibt (Beispiel Mentee 1, Mentee 4 und Mentee 7 haben alle Mentor 2 auf Rang 1). Die Entscheidungen sind nicht schwer manuell zu treffen, aber ich kann nicht herausfinden, wie man sie schreibt. Manuelle Entscheidungen funktionieren für den ersten Piloten mit einer kleinen Gruppe von Testteilnehmern, aber ich möchte, wenn möglich, ein Skript für die Erweiterung des Programms erstellen. Ist das in JMP möglich?
Die Struktur der Matrix-Matching-Tabelle finden Sie in der beigefügten Tabelle. In der Tabelle habe ich M # verwendet, um Mentoren zu bezeichnen, E #, um Mentees zu bezeichnen, und R #, um Ränge zu bestimmen.
Es klingt nach etwas, das sehr gut möglich ist, aber Sie müssen wahrscheinlich alle Schritte definieren, die Sie angegeben haben und die für einen Benutzer "einfach" sind. Ich schlage vor, zunächst die Methode zu schreiben, mit der Sie die Mentoren und Mentees mithilfe von 'Pseudocode' oder Kommentaren in Ihrem Skript abgleichen, und dann sicherzustellen, dass Sie diesen Prozess einige Male befolgen können, bevor Sie mit dem Schreiben des JSL-Codes für jeden beginnen Schritt. Hier ist ein Beispiel für einen (sehr unvollständigen) Pseudocode:
//Find the highest ranked requests by mentees
//for each one
//check if any other mentee request the same person
//if so see if any mentors requested the same mentee
//if so...
//if not....
//if no mentors requested the same mentee then randomly pick a match
....
Ein Vorteil dieser Technik besteht darin, dass Sie nach dem Schreiben des Codes unter jedem Kommentar eine gute Beschreibung der Funktionsweise dieses Codes hinterlassen.
@ich h beschreibt genau, was ich getan habe: mache es manuell und versuche dann, es zu codieren.
Hier ist ein Skript, das noch getestet werden muss. Der obere Bereich kann Ihre Tabelle mit Zeichendaten verwenden oder einige Testdaten generieren. Weiter unten gibt es eine costfun In zwei Varianten (Mittelwert, Effektivwert) werden die Kosten für eine schlechte Wahl des Mentors beschrieben. Die Tabelle ist mit den endgültigen Zuordnungen gefärbt. Ich bin mir ziemlich sicher, dass die Swaps, die die JSL durchführt, nicht ausreichen, um in allen Fällen die bestmögliche Antwort zu finden (was möglicherweise drei oder mehr vertauschte Zeilen erfordert, nicht nur ein Paar). Aber es ist ziemlich nah.
Mentees sind blau, Mentoren sind gelb
If( 1, // use original file?
dt = Open( "z:/match lists.jmp" );
// load the numeric mentee names
e = J( N Rows( dt ), 1, . );// matrix to hold numeric names
Parallel Assign( {charnames = dt[0, 1]}, e[r] = Num( Substr( charnames[r], 2 ) ) );
// load the numeric mentor names
m = J( N Rows( dt ), N Cols( dt ) - 1, . );// matrix to hold numeric names
Parallel Assign( {charnames = dt[0, 2 :: N Cols( dt )]}, m[r, c] = Num( Substr( charnames[r][c], 2 ) ) );
, // else make up some test data
n = 50;// N^2...1000 takes 2 minutes
m = J( n, n, . );
For( i = 1, i <= N Rows( m ), i += 1,
m[i, 0] = Random Shuffle( 1 :: N Rows( m ) )
);
e = (1 :: N Rows( m ))`;
dt = As Table( e || m );
);
// check:
If( !Min( e ) == 1 | !Min( m ) == 1 | !Max( e ) == N Rows( e ) | !Max( m ) == N Rows( e ),
Throw( "the E and M suffixes are not 1..nrows" )
);
// make an initial assignment of mentors to mentees
cost = J( N Rows( e ), 1, . );// 1..nMentors, index into this mentee's ranked list of mentors
used = J( N Rows( e ), 1, . );// for initial assignment, has this mentor been used?
For( menteeIndex = 1, menteeIndex <= N Rows( e ), menteeIndex += 1,
For( candidateIndex = 1, candidateIndex <= N Cols( m ), candidateIndex += 1,
candidate = m[menteeIndex, candidateIndex];
If( Is Missing( used[candidate] ), //
used[candidate] = 1;
cost[menteeIndex] = candidateIndex;
candidateIndex = 9e99;// terminate the loop AND indicate found
);
);
If( candidateIndex < 9e99,
Throw( "no candidate found for row " || Char( menteeIndex ) )
);
);
If( !All( used == 1 ),
Throw( "some mentors were not used" )
);// this might be acceptable, test carefully
// rms error cost function means first+third choices is worse than second+second choices
// ... you might not agree and might want a different cost function
//cost=[2,2]; // -> 2
//cost=[1,3]; // -> 2.236
// in particular, you might not like...
//cost=[1,10]; // -> 7.1
//cost=[4,9]; // -> 6.96
// maybe you want a simpler mean of the individual costs?
costfun = Function( {c}, Sqrt( Mean( c :*</img> c ) ) );
//costfun = Function( {c}, Mean( c ) );
// try doing some swaps to improve the costs
// this gets really close to a best answer but may not
// be perfect if a 3-swap is needed; also there may
// be two equal scores (esp with simple mean) that have
// different worst case assignments (1,3 vs 2,2 for example).
gotBetter = 1;
While( gotBetter,
gotBetter = 0;
Show( costfun( cost ) );
For( myMenteeIndex = 1, myMenteeIndex <= N Rows( e ), myMenteeIndex += 1,
myCandidateIndex = cost[myMenteeIndex];
If( myCandidateIndex > 1,
myCandidate = m[myMenteeIndex, myCandidateIndex];
oldcost = costfun( cost );
// look for a swap
For( hisMenteeIndex = 1, hisMenteeIndex <= N Rows( e ), hisMenteeIndex += 1,
If( myMenteeIndex != hisMenteeIndex,
hisCandidateIndex = cost[hisMenteeIndex];
hisCandidate = m[hisMenteeIndex, hisCandidateIndex];
hisSwap = Loc( m[hisMenteeIndex, 0] == myCandidate );
mySwap = Loc( m[myMenteeIndex, 0] == hisCandidate );
// trial:
cost[myMenteeIndex] = mySwap;
cost[hisMenteeIndex] = hisSwap;
newcost = costfun( cost );
If( newcost < oldcost,
gotBetter = 1;// another round might get even better
//show(costfun(cost));wait(0);
Break();// resets myCandidate
, // revert
cost[myMenteeIndex] = myCandidateIndex;
cost[hisMenteeIndex] = hisCandidateIndex;
//
);
)
);
);
);
);
//worstMentee = 1;
Column( dt, 1 ) << colorcells( "cyan" );
For( menteeIndex = 1, menteeIndex <= N Rows( e ), menteeIndex += 1,
Column( dt, cost[menteeIndex] + 1 ) << colorcells( "yellow", menteeIndex );
// If( cost[worstMentee] < cost[menteeIndex],
// worstMentee = menteeIndex
// );// well, one of the worst, could be ties
);
//worstMentor = m[worstMentee, cost[worstMentee]];
//For( mentorIndex = 1, mentorIndex <= N Cols( m ), mentorIndex += 1,
// col = Column( dt, mentorIndex + 1 );
// For( menteeIndex = 1, menteeIndex <= N Rows( e ), menteeIndex += 1,
// If( menteeIndex != worstMentee,
// If( col[menteeIndex] == worstMentor,
// col << colorcells( "lightred", menteeIndex )
// )
// )
// );
//); Diese JSL hat ein schlechtes N ^ 2-Verhalten: Für jede Zeile, in der jede Zeile untersucht wird ... ungefähr 1000 Mentor / Mentee-Paare beginnt sie sich wirklich zu verlangsamen ... genau dann, wenn Sie es wirklich brauchen, um zu funktionieren.
Danke für den Tipp! Ich hatte zuvor versucht, es pseudocodiert zu haben, aber dies brachte mich dazu, den Prozess zu überdenken, und ich fand eine Lösung für die problematischste Stelle.