LoginSignup
11
12

More than 5 years have passed since last update.

「基礎からのベイズ統計学」の入社試験問題で考えたこと

Last updated at Posted at 2016-03-30

お題「入社試験問題」

基礎からのベイズ統計学を読んで考えたことです。
59ページより引用

入社試験問題:ある企業の入社試験では、毎年、同じ難しさの問題を7問出題します。
X大学のxさんは3問正解、4問不正解でした。正解率を$\theta_x$とします。
Y大学のyさんは4問正解、3問不正解でした。正解率を$\theta_y$とします。
X大学とY大学からは、毎年たくさんの受験者がいます。調べてみると、
X大学の受験者の正解率は平均0.8、分散0.04のベータ分布で近似され、
Y大学の受験者の正解率は平均0.4、分散0.04のベータ分布で近似されることがわかりました。
$\theta_x$と$\theta_y$を推定し、母数の値の大きな受験者を1人だけ入社させるとしたら、
xさんとyさんのどちらでしょう。

「試験の結果だけでなく、その人の所属するグループの能力も併せて評価すると、より精度のよい推定ができる」ことの是非に関する考察になります。

ここでは、この問題をそのまま解くのではなく、以下のように条件を変えて検討します。

  • 学生の能力は1人1つの値とし、その能力値の高い方を選択できるか どうかを目的とします。
  • X大学出身の受験者の能力は、平均105、標準偏差10の正規分布に従うとします。
  • Y大学出身の受験者の能力は、平均100、標準偏差10の正規分布に従うとします。
  • 入社試験の成績である観測値は、平均が自分の能力値、標準偏差10の正規分布に従うとします。
  • 試験成績方式では、観測値のみで評価します。
  • グループ併用方式では、$補正値 \equiv \frac{グループの平均値+観測値}{2}$ で評価することにします。

Pythonで確認してみる

各値を計算します。能力値でXが高いのはは63.8%、観測値でXが高いのは59.9%です。

python3
import numpy as np, pandas as pd
np.random.seed(1)
n = 1000000 # 評価回数
xave, yave, std = 105, 100, 10 # Xの平均、Yの平均、標準偏差
gx = np.random.normal(xave, std, (n)) # グループXの能力値
gy = np.random.normal(yave, std, (n)) # グループYの能力値
ox = np.random.normal(gx, std) # グループXの観測値
oy = np.random.normal(gy, std) # グループYの観測値
ax = (xave + ox) / 2 # グループXの補正値
ay = (yave + oy) / 2  # グループXの補正値

gf = gx > gy # 能力値でXが高い
of = ox > oy # 観測値でXが高い
af = ax > ay # 補正値でXが高い

print(gf.sum() / n, of.sum() / n)
>>>
0.638318 0.598666

試験成績方式

観測値による評価では、75.9%の正解率です。

python3
print(pd.DataFrame([[(gf&of).sum(), ((~gf)&of).sum()],
                    [(gf&(~of)).sum(), ((~gf)&(~of)).sum()]],
                  columns=['能力X', '能力Y'], index=['観測X', '観測Y']) / n)
print('正解率 = ', (gf==of).sum() / n)
>>>
          能力X       能力Y
観測X  0.498147  0.100519
観測Y  0.140171  0.261163
正解率 =  0.75931

グループ併用方式

補正値による評価では、76.8%の正解率です。

python3
print(pd.DataFrame([[(gf&af).sum(), ((~gf)&af).sum()],
                    [(gf&(~af)).sum(), ((~gf)&(~af)).sum()]],
                  columns=['能力X', '能力Y'], index=['補正X', '補正Y']) / n)
print('正解率 = ', (gf==af).sum() / n)
>>>
          能力X       能力Y
補正X  0.549088  0.142374
補正Y  0.089230  0.219308
正解率 =  0.768396

考察

確かに、自分の能力だけでなく所属グループの能力を使うと、精度良く評価できました。
しかし、このような方法が本当に良いのでしょうか?
例えば、大学ではなく性別を使うのは、どうでしょうか?
おそらく男女差で合格可否を変えるのは、問題があるでしょう。

提案方式1

そこで、新たな方法を提案します。その方法は、以下のようなものです。

  • 事前に別途試験を受けます。その結果を事前観測値とします。
  • その試験の成績が気に入らない場合(事前観測値が自分の能力値以下の場合)は、何もしないとします。
  • 気に入った場合は、自ら登録処理をします。登録されている場合、入社試験では、観測値と事前観測値の両方を使わなければいけないこととします。(登録されていなければ、観測値のみで構いません。)
  • 全員が別途試験を受けられない可能性も考慮して、登録制を取り入れています。
python3
bx = np.random.normal(gx, std) # グループXの事前観測値
by = np.random.normal(gy, std) # グループYの事前観測値
# 事前観測値が自分の能力値以下であれば、元々の観測値とする
px = ox*(bx < gx) + (ox+bx)/2*(bx >= gx) # グループXの提案値1
py = oy*(by < gy) + (oy+by)/2*(by >= gy) # グループYの提案値1

pf = px > py # 提案値1でXが高い

print(pd.DataFrame([[(gf&pf).sum(), ((~gf)&pf).sum()],
                    [(gf&(~pf)).sum(), ((~gf)&(~pf)).sum()]],
                  columns=['提案1X', '提案1Y'], index=['観測X', '観測Y']) / n)
print('正解率 = ', (gf==pf).sum() / n)
>>>
         提案1X      提案1Y
観測X  0.518089  0.088829
観測Y  0.120229  0.272853
正解率 =  0.790942

79.1%の正解率となり、精度がよくなりました。
ただし、別途試験を受けるためコストがかかります。

提案方式2

別途試験しない方法も考えてみます。

  • 試験の成績が所属グループの平均以上の場合: 観測値を使ってもらう。
  • 試験の成績が所属グループの平均未満の場合: 補正値を使ってもらう。
python3
qx = ox*(ox >= xave) + ax*(ox < xave) # グループXの提案値2
qy = oy*(oy >= yave) + ay*(oy < yave) # グループYの提案値2

qf = qx > qy # 提案値2でXが高い

print(pd.DataFrame([[(gf&qf).sum(), ((~gf)&qf).sum()],
                    [(gf&(~qf)).sum(), ((~gf)&(~qf)).sum()]],
                  columns=['提案2X', '提案2Y'], index=['観測X', '観測Y']) / n)
print('正解率 = ', (gf==qf).sum() / n)
>>>
         提案2X      提案2Y
観測X  0.521504  0.119074
観測Y  0.116814  0.242608
正解率 =  0.764112

観測値だけの推定より、多少よくなりました。

提案方式3

提案方式2でも、所属グループの上位能力者は不満かもしれません。次の方法は、どうでしょうか。

  • ユーザごとに自ら登録するかどうかを試験時に決めてもらう。
  • 能力値が所属グループの平均以上の場合: 登録しない。→ 観測値を使ってもらう。
  • 能力値が所属グループの平均未満の場合: 登録する。→ 補正値を使ってもらう。
python3
rx = ox*(gx >= xave) + ax*(gx < xave) # グループXの提案値3
ry = oy*(gy >= yave) + ay*(gy < yave) # グループYの提案値3

rf = rx > ry # 提案値3でXが高い

print(pd.DataFrame([[(gf&rf).sum(), ((~gf)&rf).sum()],
                    [(gf&(~rf)).sum(), ((~gf)&(~rf)).sum()]],
                  columns=['提案3X', '提案3Y'], index=['観測X', '観測Y']) / n)
print('正解率 = ', (gf==rf).sum() / n)
>>>
         提案3X      提案3Y
観測X  0.518967  0.119357
観測Y  0.119351  0.242325
正解率 =  0.761292
  • 観測値だけの推定より、多少よくなる。
  • 受験者が主体的に関われるので、差別されているわけではない。
  • コストもほとんどかからない。

提案3(あるいは、提案1と提案3のハイブリッド)が、よいように思われます。

以上

11
12
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
12