Sto cercando di scrivere uno script JMP per creare corrispondenze mentee / mentor per un programma di mentoring presso la mia azienda. Ho la parte che tiene conto delle preferenze di classifica di allievo e mentore che si traduce in una matrice di mentore preferito per ogni allievo per grado (1 è il migliore e 10 il peggiore). Il problema che sto affrontando è come gestirlo se ci sono più allievi con lo stesso mentore in un determinato rango (ad esempio Mentee 1, Mentee 4 e Mentee 7 hanno tutti Mentor 2 al Rango 1). Le decisioni non sono difficili da prendere manualmente, ma non riesco a capire come scriverle. Le decisioni manuali funzionano per il pilota iniziale con un piccolo gruppo di partecipanti al test, ma vorrei scrivere qualcosa se possibile per quando il programma viene espanso. È qualcosa che è possibile in JMP?
Vedere la tabella allegata per la struttura della tabella di corrispondenza matrice. Nella tabella ho usato M # per designare i mentori, E # per designare gli allievi e R # per designare i ranghi.
Sembra qualcosa che è molto possibile, ma probabilmente devi definire tutti quei passaggi che hai indicato sono "facili" per un utente. Ti suggerisco di iniziare scrivendo il metodo che usi per abbinare i mentori e gli allievi usando 'pseudo-codice', o commenti nel tuo script, e quindi assicurati di poter seguire quel processo alcune volte prima di iniziare a scrivere il codice JSL per ogni passo. Ecco un esempio di alcuni pseudo-codici (molto incompleti):
//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 vantaggio di questa tecnica è una volta che scrivi il codice sotto ogni commento, lascerai una buona descrizione di ciò che fa quel codice.
@ih descrive esattamente quello che ho fatto: farlo manualmente e quindi provare a codificarlo.
Ecco uno script che necessita di ulteriori test. La sezione superiore può utilizzare la tabella con i dati dei caratteri o generare alcuni dati di test. Più in basso, c'è un costfun , in due varianti (media, valore efficace), che descrive il costo per ottenere una cattiva scelta del mentore. La tabella è colorata con gli incarichi finali. Sono abbastanza sicuro che gli swap della JSL non siano sufficienti per trovare la migliore risposta possibile in tutti i casi (che potrebbe richiedere tre o più righe scambiate, non solo una coppia). Ma è abbastanza vicino.
Gli allievi sono blu, i mentori sono gialli
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 )
// )
// )
// );
//); Che JSL abbia qualche cattivo comportamento N ^ 2: per ogni riga studia ogni riga ... circa 1000 coppie mentore / mentee sta davvero iniziando a rallentare ... proprio quando ne hai davvero bisogno per funzionare.
Grazie per il consiglio! In precedenza avevo provato a psuedocoding, ma questo mi ha fatto tornare indietro e ripensare il processo e ho trovato una soluzione al punto più problematico.