Estoy tratando de escribir un script JMP para crear coincidencias de mentoreado / mentor para un programa de mentoría en mi empresa. Tengo la parte que explica las preferencias de clasificación de mentoreado y mentoreado que resulta en una matriz de mentor preferido para cada mentoreado por rango (1 es el mejor y 10 es el peor). El problema con el que me encuentro es cómo manejarlo si hay varios aprendices con el mismo mentor en un rango determinado (por ejemplo, Mentee 1, Mentee 4 y Mentee 7, todos tienen Mentor 2 en el Rango 1). Las decisiones no son difíciles de hacer manualmente, pero no puedo entender cómo escribirlas. Las decisiones manuales funcionan para el piloto inicial con un pequeño grupo de participantes en la prueba, pero me gustaría escribir algo si es posible para cuando se amplíe el programa. ¿Es esto algo que es posible en JMP?
Consulte la tabla adjunta para ver la estructura de la tabla de coincidencia de matrices. En la tabla, utilicé M # para designar mentores, E # para designar mentoreados y R # para designar rangos.
Suena como algo que es muy posible, pero probablemente necesite definir todos los pasos que indicó que son "fáciles" para un usuario. Sugiero comenzar escribiendo el método que usa para unir a los mentores y aprendices usando 'pseudocódigo' o comentarios en su script, y luego asegúrese de que puede seguir ese proceso varias veces antes de comenzar a escribir el código JSL para cada paso. Aquí hay un ejemplo de un pseudocódigo (muy incompleto):
//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
....
Una ventaja de esta técnica es que una vez que escriba el código debajo de cada comentario, dejará una buena descripción de lo que hace ese código.
@ih describe exactamente lo que hice: hacerlo manualmente y luego intentar codificarlo.
Aquí hay un script que necesita más pruebas. La sección superior puede usar su tabla con datos de caracteres o generar algunos datos de prueba. Más abajo, hay un divertido , en dos variaciones (media, rms), que describe el costo de obtener una mala elección de mentor. La tabla está coloreada con las tareas finales. Estoy bastante seguro de que los intercambios que hace JSL no son suficientes para encontrar la mejor respuesta posible en todos los casos (lo que podría requerir el intercambio de tres o más filas, no solo un par). Pero está bastante cerca.
Los aprendices son azules, los mentores son amarillos
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 )
// )
// )
// );
//); Ese JSL tiene un mal comportamiento N ^ 2: por cada fila estudia cada fila ... alrededor de 1000 pares de mentor / aprendiz realmente está empezando a disminuir ... justo cuando realmente necesita que funcione.
¡Gracias por el consejo! Había intentado psuedocoding antes, pero esto me hizo volver y repensar el proceso y encontré una solución para el lugar más problemático.