J'essaie d'écrire un script JMP pour créer des correspondances mentoré / mentor pour un programme de mentorat dans mon entreprise. J'ai la partie qui tient compte des préférences de classement des mentorés et des mentors, ce qui donne une matrice de mentors préférés pour chaque mentoré par rang (1 étant le meilleur et 10 étant le pire). Le problème que je rencontre est de savoir comment le gérer s'il y a plusieurs mentorés avec le même mentor à un rang donné (par exemple, le mentoré 1, le mentoré 4 et le mentoré 7 ont tous un mentor 2 au rang 1). Les décisions ne sont pas difficiles à faire manuellement, mais je ne sais pas comment les écrire. Les décisions manuelles fonctionnent pour le pilote initial avec un petit groupe de participants au test, mais je voudrais écrire quelque chose si possible pour quand le programme est développé. Est-ce quelque chose qui est possible dans JMP?
Veuillez consulter le tableau ci-joint pour la structure du tableau de correspondance des matrices. Dans le tableau, j'ai utilisé M # pour désigner les mentors, E # pour désigner les mentorés et R # pour désigner les grades.
Cela ressemble à quelque chose de très possible, mais vous devez probablement définir toutes les étapes que vous avez indiquées comme «faciles» pour un utilisateur. Je suggère de commencer par écrire la méthode que vous utilisez pour faire correspondre les mentors et les mentorés à l'aide de «pseudo-code» ou de commentaires dans votre script, puis assurez-vous que vous pouvez suivre ce processus plusieurs fois avant de commencer à écrire le code JSL pour chaque étape. Voici un exemple de pseudo-code (très incomplet):
//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
....
Un avantage de cette technique est une fois que vous écrivez le code sous chaque commentaire, vous laisserez une bonne description de ce que fait ce code.
@ih décrit exactement ce que j'ai fait: faites-le manuellement, puis essayez de le coder.
Voici un script qui nécessite des tests supplémentaires. La section supérieure peut utiliser votre table avec des données de caractères ou générer des données de test. Plus bas, il y a un costfun , en deux variantes (moyenne, valeur efficace), qui décrit le coût d'un mauvais choix de mentor. Le tableau est coloré avec les affectations finales. Je suis à peu près certain que les échanges effectués par la JSL ne suffisent pas à trouver la meilleure réponse possible dans tous les cas (ce qui pourrait nécessiter trois lignes ou plus échangées, pas seulement une paire). Mais c'est assez proche.
Les mentorés sont bleus, les mentors sont jaunes
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 )
// )
// )
// );
//); Ce JSL a un mauvais comportement N ^ 2: pour chaque ligne, il étudie chaque ligne ... environ 1000 paires mentor / mentoré, il commence vraiment à ralentir ... juste au moment où vous en avez vraiment besoin pour travailler.
Merci pour le conseil! J'avais essayé de le coder avant, mais cela m'a fait revenir en arrière et repenser le processus et j'ai trouvé une solution à l'endroit le plus problématique.