我正在嘗試編寫一個JMP腳本來為我公司的指導計劃創建指導者/指導者匹配項。我已經說明了受訓者和受訓者的排名偏好,該部分會得出每個受訓者按等級排列的優先受訓者矩陣(1為最佳,10為最差)。我遇到的問題是,如果在給定級別上有多名同一個指導者的指導者(例如,指導1,指導4和指導7都具有指導2排在第1位),該如何處理。手動決定並不難,但是我不知道如何編寫決定。手動決策適用於一小部分測試參與者的初始飛行員,但是我希望在擴展程序時編寫一些腳本。這在JMP中是可能的嗎?
矩陣匹配表的結構請參見附件。在表中,我使用M#來指定指導者,使用E#來指定指導者,使用R#來指定等級。
聽起來這很有可能,但是您可能需要定義您認為對用戶而言“容易”執行的所有步驟。 我建議首先寫出用於使用'pseudo-code'或腳本中的註釋匹配指導者和受指導者的方法,然後確保在開始為每種方法編寫JSL代碼之前,您可以遵循該過程幾次。步。 這是一些(非常不完整)偽代碼的示例:
//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
....
該技術的一個好處是,一旦您在每個註釋下方編寫了代碼,就將對該代碼的功能進行詳盡的描述。
@ih 詳細描述我的工作:手動執行,然後嘗試對其進行編碼。
這是一個需要更多測試的腳本。頂部可以將表與字符數據一起使用或生成一些測試數據。再往下走,有一個好玩的 ,有兩個變體(均值,均方根),描述了選擇導師的差額成本。表格上有最終作業的顏色。我敢肯定,JSL所做的交換不足以在所有情況下都找到最佳的答案(這可能需要交換三行或更多行,而不僅僅是一對。)但這非常接近。
導板為藍色,導板為黃色
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 )
// )
// )
// );
//); 該JSL具有不良的N ^ 2行為:對於每一行,它研究每行...大約1000對導師/受訓者對,它確實開始變慢了……僅在您真正需要它時才起作用。
謝謝你的提示!我之前曾嘗試過偽編碼,但這使我回過頭來重新考慮該過程,並找到了最有問題的解決方案。