Um programa dinâmico fará pouco trabalho com isso.
Suponha que administremos todas as perguntas aos alunos e depois selecionemos aleatoriamente um subconjunto I do k=10 dentre todos n=100questões. Vamos definir uma variável aleatóriaXi comparar os dois alunos em questão i: configure para 1 se o aluno A estiver correto e o aluno B não, −1 se o aluno B estiver correto e o aluno A não, e 0de outra forma. O total
XI=∑i∈IXi
é a diferença nas pontuações para as perguntas em I. Desejamos calcular Pr(XI>0). Essa probabilidade é assumida sobre a distribuição conjunta de eIXi.
A função de distribuição de é prontamente calculadaXi sob a suposição de que os alunos respondem independentemente:
Pr(Xi=1)Pr(Xi=−1)Pr(Xi=0)=Pai(1−Pbi)=Pbi(1−Pai)=1−Pr(Xi=1)−Pr(Xi=0).
Como uma abreviação, vamos chamar essas probabilidades de e respectivamente. Escrevaai, bi,di,
fi(x)=aix+bix−1+di.
Esse polinômio é uma função geradora de probabilidade para oXi.
Considere a função racional
ψn(x,t)=∏i=1n(1+tfi(x)).
(Na verdade, é um polinômio: é uma função racional bastante simples.) xnψn(x,t)
Quando é expandido como um polinômio em , o coeficiente de consiste na soma de todos os produtos possíveis de distintos Essa será uma função racional com coeficientes diferentes de zero apenas para potências de de aComo é selecionado uniformemente aleatoriamente, os coeficientes desses poderes de quando normalizados para somar à unidade, fornecem a função geradora de probabilidade para a diferença nas pontuações. Os poderes correspondem ao tamanho deψnttkkfi(x).xx−kxk. Ix,I.
O ponto desta análise é que podemos calcular facilidade e eficiência razoável:ψ(x,t) basta multiplicar os polinômios sequencialmente. Para isso, é necessário reter os coeficientes de em para(é claro que podemos ignorar todos os poderes superiores de que aparecem em qualquer um desses produtos parciais). Assim, todas as informações necessárias transportadas por podem ser representadas por uma matriz , com linhas indexadas pelos poderes de (de a ) e colunas indexadas porn1,t,…,tkψj(x,t)j=0,1,…,n.tψj(x,t)2k+1×n+1x−kk0 a .k
Cada etapa da computação requer um trabalho proporcional ao tamanho dessa matriz, escalando como Contabilizando o número de etapas, esse é um algoritmo de espaço , espaço . Isso torna muito rápido para pequeno Isso foi executado com em (não conhecido para o excesso de velocidade) para a -se a e -se a onde leva nove segundos (em um único núcleo). Na configuração da questão com e o cálculo leva segundos.O(k2).O(k2n)O(kn)k.R
k100n105,n=100k=10,0.03
Aqui está um exemplo em que são valores aleatórios uniformes entre e e são seus quadrados (que são sempre menores que , favorecendo fortemente o aluno A). Simulei 100.000 exames, como resumido por este histograma das pontuações líquidas:Pai01PbiPai
As barras azuis indicam os resultados nos quais o aluno A obteve uma pontuação melhor que B. Os pontos vermelhos são o resultado do programa dinâmico. Eles concordam lindamente com a simulação ( , ). A soma de todas as probabilidades positivas fornece a resposta neste caso,χ2p=51%0.7526….
Observe que esse cálculo gera mais do que o solicitado: produz toda a distribuição de probabilidade da diferença de pontuação em todos os exames de ou menos perguntas selecionadas aleatoriamente.k
Para aqueles que desejam uma implementação de trabalho para usar ou portar, aqui está o R
código que produziu a simulação (armazenada no vetor Simulation
) e executou o programa dinâmico (com resultados na matriz P
). O repeat
bloqueio no final existe apenas para agregar todos os resultados raros, de modo que o se torne obviamente confiável. (Na maioria das situações, isso não importa, mas evita que o software se queixe.)χ2
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