セットがあるとします の 質問とあります 学生 そして 。
しましょう 確率である 質問に答えます 正しく、そして 同じ 。
すべて そして のために与えられています 。
試験を想定する 取ることによって作られています からのランダムな質問 。
どのように私はの確率を見つけることができます より良いスコアを得る ?
組み合わせのチェックと確率の比較を考えたのですが、数が多くて時間がかかるのでアイデアが足りませんでした。
セットがあるとします の 質問とあります 学生 そして 。
しましょう 確率である 質問に答えます 正しく、そして 同じ 。
すべて そして のために与えられています 。
試験を想定する 取ることによって作られています からのランダムな質問 。
どのように私はの確率を見つけることができます より良いスコアを得る ?
組み合わせのチェックと確率の比較を考えたのですが、数が多くて時間がかかるのでアイデアが足りませんでした。
回答:
動的プログラムは、これを短時間で処理します。
生徒へのすべての質問を管理し、ランダムにサブセットを選択するとします の 全部なくなって 質問。確率変数を定義しましょう 問題の2人の生徒を比較する に設定 学生Aが正しく、学生Bが正しくない場合、 学生Bが正しく、学生Aが正しくない場合 さもないと。合計
の質問のスコアの違いです 計算したい この確率は、との結合分布から得られ
の分布関数は、学生が独立して応答するという仮定の下で容易に計算されます。
簡略化して、これらの確率をそれぞれと呼びます。書く
この多項式は、確率生成関数です
有理関数を考える
(実際には、は多項式です。非常に単純な有理関数です。)
が多項式として展開される場合、係数は異なるのすべての可能な積の合計から構成され これが唯一の力のための非ゼロ係数を有する有理関数となるから介しては一様にランダムに選択されるため、これらのべき乗の係数は合計が1になるように正規化すると、スコアの差の確率生成関数になります。 べき乗はサイズに対応し
この分析のポイントは、簡単かつ合理的な効率で計算できることです多項式を順番に乗算するだけです。これを行うことの係数保持する必要でするために(もちろん、これらの部分積のいずれかに現れるすべての高次のべき乗を無視することもできます)。したがって、すべての必要な情報は、によって運ばで表すことができるの電力によってインデックス付け行と、行列(から貫通によってインデックス付け)と列 使って 。
計算の各ステップには、この行列のサイズに比例する作業が必要です。 ステップ数を説明すると、これは -時間、 -空間アルゴリズム。それは小さいためにそれはかなり速くなります 私はそれをR
(過度の速度で知られていない)のために実行しました まで そして まで (シングルコアで)9秒かかります。との設定で そして 計算には 秒。
ここに例があります の間の一様なランダム値です そして そしてその それらの正方形です(これは常に 、それによって学生A)を強く支持します。この正味スコアのヒストグラムで要約されているように、私は100,000の試験をシミュレートしました。
青いバーは、学生AがBよりも良いスコアを出した結果を示しています。赤い点は、動的プログラムの結果です。彼らはシミュレーションに美しく同意します( テスト、 )。 この場合、すべての正の確率を合計すると答えが得られます。
この計算は求められた以上の結果をもたらすことに注意してください:すべての試験のスコアの差の確率分布全体を生成します 以下のランダムに選択された質問。
機能する実装を使用または移植したい人のためにR
、シミュレーションを生成し(vectorに格納Simulation
)、動的プログラムを実行する(結果は配列P
)コードを次に示します。repeat
最後のブロックは、すべての非常にまれな結果を集約するだけであり、テストは明らかに信頼できるようになります。(ほとんどの場合、これは問題ではありませんが、ソフトウェアが文句を言うのを防ぎます。)
n <- 100
k <- 10
p <- runif(n) # Student A's chances of answering correctly
q <- p^2 # Student B's chances of answering correctly
#
# Compute the full distribution.
#
system.time({
P <- matrix(0, 2*k+1, k+1) # Indexing from (-k,0) to (k,k)
rownames(P) <- (-k):k
colnames(P) <- 0:k
P[k+1, 1] <- 1
for (i in 1:n) {
a <- p[i] * (1 - q[i])
b <- q[i] * (1 - p[i])
d <- (1 - a - b)
P[, 1:k+1] <- P[, 1:k+1] +
a * rbind(0, P[-(2*k+1), 1:k]) +
b * rbind(P[-1, 1:k], 0) +
d * P[, 1:k]
}
P <- apply(P, 2, function(x) x / sum(x))
})
#
# Simulation to check.
#
n.sim <- 1e5
set.seed(17)
system.time(
Simulation <- replicate(n.sim, {
i <- sample.int(n, k)
sum(sign((runif(k) <= p[i]) - (runif(k) <= q[i]))) # Difference in scores, A-B
})
)
#
# Test the calculation.
#
counts <- tabulate(Simulation+k+1, nbins=2*k+1)
n <- sum(counts)
k.min <- 5
repeat {
probs <- P[, k+1]
i <- probs * n.sim >= k.min
z <- sum(probs[!i])
if (z * n >= 5) break
if (k.min * (2*k+1) >= n) break
k.min <- ceiling(k.min * 3/2)
}
probs <- c(z, probs[i])
counts <- c(sum(counts[!i]), counts[i])
chisq.test(counts, p=probs)
#
# The answer.
#
sum(P[(1:k) + k+1, k+1]) # Chance that A-B is positive
各反復で、
なぜなら、Aは、Aが正しく、Bが間違っている場合にのみ優れているからです。したがって、特定の質問について、Aが90%の確率で正しく、Bが80%の確率で正しい場合、Aが正しく、Bが間違っているという共同確率は
これで、選択した10個すべての質問を通過し、この同時確率に基づいてポイントをAまたはBに割り当てるコードを記述できます。各試験の終わりに、勝者は最も多くのポイントを持つものです。これを何度も行い、AがBに勝つ確率を確認します。
これを行ういくつかのコードをここに書きました:https : //nbviewer.jupyter.org/github/kevinmcinerney/exam_probabilities/blob/master/exam_probabilities.ipynb
グラフはリンクに表示されませんが、次のようになります。
このシミュレーションは値を使用しました
この例では、それぞれが25の質問で構成される1000の試験を実行しましたが、すべてが同じ100の質問のセットを形成します。Y軸は、試験でAがBよりも優れていた確率です。(0-1000)の検査番号はX軸に沿っています
AとBの両方がランダムなPで問題を正解したため、グラフは50%に収束しました。私は25の質問を使用しました。10は100の質問を含む母集団の代表ではないためです。10個の質問を使用すると、グラフは50%近くまたは50%前後に収束する可能性が高くなります。3つの行は3つの個別の試験です。