今までのコードに、提案側と応答側を入れ替えてマッチングするコードを付け加えました。(今まではOne=>ManyだったがMany=>Oneでマッチングさせることもできるように。)
新しいmatchingはreverse = true/false で提案する側を入れ替えます。
提案側と応答側を入れ替えたとき、マッチングの質に変化があるかを調べます。 まずはOne-to-oneについて。
In [1]:
using MyMatching
In [2]:
using Matching
function mat2vecs{T<:Integer}(prefs::Matrix{T})
return [prefs[1:findfirst(prefs[:, j], 0)-1, j] for j in 1:size(prefs, 2)]
end
Out[2]:
In [3]:
m = 10
n = 10
prop_prefs, resp_prefs = mat2vecs.(random_prefs(m, n))
reverse = false
matching(prop_prefs,resp_prefs,reverse) #男性 → 女性のとき
Out[3]:
In [4]:
reverse = true
matching(prop_prefs,resp_prefs,reverse) #女性 → 男性のとき
Out[4]:
In [5]:
m = 10 #女性を減らしてみる
n = 4
prop_prefs, resp_prefs = mat2vecs.(random_prefs(m, n))
reverse = false
matching(prop_prefs,resp_prefs,reverse) #男性 → 女性のとき
Out[5]:
In [6]:
reverse = true
matching(prop_prefs,resp_prefs,reverse) #女性 → 男性のとき
Out[6]:
提案する側を入れ替えてもマッチング結果は安定的に同じでした。次はMany-to-manyについて。
(capsは各大学にk個の受け入れ枠を与えます。)
In [7]:
m = 30
n = 6
prop_prefs, resp_prefs = mat2vecs.(random_prefs(m, n))
k = 3
caps = k*ones(Int64,n)
reverse = false
matching(prop_prefs,resp_prefs,caps,reverse) #学生 → 大学のとき
Out[7]:
In [8]:
reverse = true
matching(prop_prefs,resp_prefs,caps,reverse) #大学 → 学生のとき
Out[8]:
In [9]:
m = 50
n = 10
prop_prefs, resp_prefs = mat2vecs.(random_prefs(m, n))
k = 3
caps = k*ones(Int64,n)
reverse = false
result1 = matching(prop_prefs,resp_prefs,caps,reverse) #学生 → 大学のとき
Out[9]:
In [10]:
reverse = true
result2 = matching(prop_prefs,resp_prefs,caps,reverse) #大学 → 学生のとき
Out[10]:
In [11]:
result1[1] -result2[1] #提案を入れ替えたときどこに違いがあるか
Out[11]:
In [12]:
a = [prop_prefs,resp_prefs,count(i -> (i != 0),result1[1] -result2[1]),find(result1[1]-result2[1].>0)]
#[propの選好,respの選好,propのマッチで変化した数,変化したpropのインデックス]
Out[12]:
In [13]:
m = 50
n = 10
prop_prefs, resp_prefs = mat2vecs.(random_prefs(m, n))
k = 3
caps = k*ones(Int64,n)
reverse = false
result1 = matching(prop_prefs,resp_prefs,caps,reverse) #学生 → 大学のとき
reverse = true
result2 = matching(prop_prefs,resp_prefs,caps,reverse) #大学 → 学生のとき
b =[prop_prefs,resp_prefs,count(i -> (i != 0),result1[1] -result2[1]),find(result1[1]-result2[1].>0)]
Out[13]:
In [14]:
m = 50
n = 10
prop_prefs, resp_prefs = mat2vecs.(random_prefs(m, n))
k = 3
caps = k*ones(Int64,n)
reverse = false
result1 = matching(prop_prefs,resp_prefs,caps,reverse) #学生 → 大学のとき
reverse = true
result2 = matching(prop_prefs,resp_prefs,caps,reverse) #大学 → 学生のとき
c =[prop_prefs,resp_prefs,count(i -> (i != 0),result1[1] -result2[1]),find(result1[1]-result2[1].>0)]
Out[14]:
In [15]:
m = 50
n = 10
prop_prefs, resp_prefs = mat2vecs.(random_prefs(m, n))
k = 3
caps = k*ones(Int64,n)
reverse = false
result1 = matching(prop_prefs,resp_prefs,caps,reverse) #学生 → 大学のとき
reverse = true
result2 = matching(prop_prefs,resp_prefs,caps,reverse) #大学 → 学生のとき
d =[prop_prefs,resp_prefs,count(i -> (i != 0),result1[1] -result2[1]),find(result1[1]-result2[1].>0)]
Out[15]:
In [16]:
m = 50
n = 10
prop_prefs, resp_prefs = mat2vecs.(random_prefs(m, n))
k = 3
caps = k*ones(Int64,n)
reverse = false
result1 = matching(prop_prefs,resp_prefs,caps,reverse) #学生 → 大学のとき
reverse = true
result2 = matching(prop_prefs,resp_prefs,caps,reverse) #大学 → 学生のとき
e =[prop_prefs,resp_prefs,count(i -> (i != 0),result1[1] -result2[1]),find(result1[1]-result2[1].>0),result1[1]]
Out[16]:
Many-to-oneでは提案を入れ替えるとマッチング結果が少しだけ変わったり、変わらなかったりします。どうして一見安定そうな結果にわずかな違いが生じるのかについて調べてみます。
上のa,b,c,d,eの5つは選好以外は条件が同じなので理由として選好の違いが考えられます。各選好についての特徴を見てみます。
In [17]:
[[sum(length(a[1][i]) for i in 1:m),sum(length(b[1][i]) for i in 1:m),sum(length(c[1][i]) for i in 1:m),
sum(length(d[1][i]) for i in 1:m),sum(length(e[1][i]) for i in 1:m)],[a[3],b[3],c[3],d[3],e[3]]] #[propの選好の数]
Out[17]:
In [18]:
[[sum(length(a[2][i]) for i in 1:n),sum(length(b[2][i]) for i in 1:n),sum(length(c[2][i]) for i in 1:n),
sum(length(d[2][i]) for i in 1:n),sum(length(e[2][i]) for i in 1:n)],[a[3],b[3],c[3],d[3],e[3]]] #[respの選好の数]
Out[18]:
各主体が対象とする相手の数が多ければ多いほどマッチングが変化する余地が多そうな気がしましたが、 prop,respの選好の数が多い(=各主体がより多くの相手とマッチングできる可能性をもつ)ことはあまりマッチング結果と関係がなさそうです。
In [19]:
prop_popa = [[count(p-> i<=p<i+1,a[1][j]) for i in 1:n] for j in 1:m] #resp[i]がpropの選好の中に何回登場するか
prop_popb = [[count(p-> i<=p<i+1,b[1][j]) for i in 1:n] for j in 1:m]
prop_popc = [[count(p-> i<=p<i+1,c[1][j]) for i in 1:n] for j in 1:m]
prop_popd = [[count(p-> i<=p<i+1,d[1][j]) for i in 1:n] for j in 1:m]
prop_pope = [[count(p-> i<=p<i+1,e[1][j]) for i in 1:n] for j in 1:m]
resp_popa = [[count(p-> i<=p<i+1,a[2][j]) for i in 1:m] for j in 1:n] #prop[i]がrespの選好の中に何回登場するか
resp_popb = [[count(p-> i<=p<i+1,b[2][j]) for i in 1:m] for j in 1:n]
resp_popc = [[count(p-> i<=p<i+1,c[2][j]) for i in 1:m] for j in 1:n]
resp_popd = [[count(p-> i<=p<i+1,d[2][j]) for i in 1:m] for j in 1:n]
resp_pope = [[count(p-> i<=p<i+1,e[2][j]) for i in 1:m] for j in 1:n]
Out[19]:
In [20]:
prop_numa = [sum(prop_popa[i])for i in 1:m] #propの選好に1 ~ nまでが何回ふくまれていたか
prop_numb = [sum(prop_popb[i])for i in 1:m]
prop_numc = [sum(prop_popc[i])for i in 1:m]
prop_numd = [sum(prop_popd[i])for i in 1:m]
prop_nume = [sum(prop_pope[i])for i in 1:m]
resp_numa = [sum(resp_popa[i])for i in 1:n]
resp_numb = [sum(resp_popb[i])for i in 1:n]
resp_numc = [sum(resp_popc[i])for i in 1:n]
resp_numd = [sum(resp_popd[i])for i in 1:n]
resp_nume = [sum(resp_pope[i])for i in 1:n]
Out[20]:
In [21]:
[[sum(prop_numa)/n,sum(prop_numb)/n,sum(prop_numc)/n,sum(prop_numd)/n,sum(prop_nume)/n],
[sum(resp_numa)/m,sum(resp_numb)/m,sum(resp_numc)/m,sum(resp_numd)/m,sum(resp_nume)/m]] #各選好の出方の平均
Out[21]:
In [22]:
[[var(prop_numa),var(prop_numb),var(prop_numc),var(prop_numd),var(prop_nume)],
[var(resp_numa),var(resp_numb),var(resp_numc),var(resp_numd),var(resp_nume)]] #各選好にどの程度出方のばらつきがあるか
Out[22]:
In [23]:
[a[3],b[3],c[3],d[3],e[3]]
Out[23]:
平均的にどれだけ相手グループの選好に入るかや、どれだけ選好の入り方にばらつきがあるかといったこともマッチング結果に関係がなさそうです。
最後に実際にマッチング結果が変化したケースについて、変化したprop(resp)の相手と志望順位との関係について調べてみます。
In [24]:
change = [[result1[1][e[4][i]] for i in 1:length(e[4])],[result2[1][e[4][i]] for i in 1:length(e[4])]]
#eにおいてのマッチングの変化
Out[24]:
このケースにおいてpropにとってより良い結果になったかどうか調べます。
In [25]:
[findfirst(e[1][e[4][1]],change[1][1]),findfirst(e[1][e[4][1]],change[2][1])] #propのマッチ相手の志望順位の変化
Out[25]:
変化したpropのマッチング相手はpropにとってより志望順位の低い相手となってしまいました。 最後に各マッチング相手の志望順位の和をprop,respそれぞれ出してみます。(小さいほど平均的により志望度の高い相手とマッチングしているといえる)
In [26]:
prop_ranking = [findfirst(prop_prefs[i],result1[1][i]) for i in 1:m]
#学生 → 大学のとき 学生
resp_ranking = [[findfirst(resp_prefs[i],result1[2][j]) for j in result1[3][i]:result1[3][i+1]-1] for i in 1:n]
#学生 → 大学のとき 大学
prop_ranking_r = [findfirst(prop_prefs[i],result2[1][i]) for i in 1:m]
#大学 → 学生のとき 学生
resp_ranking_r = [[findfirst(resp_prefs[i],result2[2][j]) for j in result2[3][i]:result2[3][i+1]-1] for i in 1:n]
#大学 → 学生のとき 大学
[sum(prop_ranking),sum(prop_ranking_r),sum(prop_ranking)-sum(prop_ranking_r),
sum([sum(resp_ranking[i])for i in 1:n]),sum([sum(resp_ranking_r[i])for i in 1:n]),
sum([sum(resp_ranking[i])for i in 1:n])-sum([sum(resp_ranking_r[i])for i in 1:n])]
Out[26]:
prop、resp両社にとってマッチング相手の平均的な志望度が下がってしまいました。提案入れ替え後のマッチング結果は、提案入れ替え前のマッチング結果に対してパレート劣位ということになります。(eのケースにおいて。他のケースだとpropとrespの結果にトレードオフがあったりもする。)
全体を通してマッチング結果がなぜ、どのように変わるかを調べてみましたが解明できませんでした。 ただマッチング結果は想像よりも入れ替え前後で共通した部分が多く、時には完全に一致していることが見て取れます。 そこにノイズ(と見て良いのかも不明)が加わる理由はよくわかりませんでした。
マッチング結果はprop、respの選好の具合に強く影響されるので、選好を固定することなく調べてみるのは良くない方針でした。