虽然很容易想到,这种对关系在某种程度上是自相关的,这会导致推理问题,但直截了当的答案是,这在这里不是问题。
它背后的基本原理接近典型的聚类问题。聚类不会破坏在单元级别变化的变量的重要性,它会产生太重要的变量,仅在集群级别变化。如果我们引入了学生级别的变量,而不是配对级别的变量,那么它应该经常很重要。
由于这是潜在的自相关问题,所讨论的值将是感兴趣参数的估计量的 p 值:β1. 我们担心False Positives的潜在错误数量。
为了检查误报率,我提出了蒙特卡罗模拟,并给出了假设:
- 学生不作弊。我们检查误报率,则不需要引入作弊机制。
- n (
250
) 学生排成一排,每个学生有两个邻居(第一个和最后一个)。
- 学生有k (
20
) 个答案的测试,每个答案都有( )个2
可能性。答案是随机的,概率相等。
- 学生成对配对,如果他们坐在一起,则被标记为邻居。计算每对相似答案的数量。
然后进行蒙特卡罗模拟(单位:一对):
- 回归s i m i l a r _ a n s w e rs一世=β0+β1n e g _兄弟_ _ _ _s一世+ε一世被评估。P值b1估计器被保存。
- 过程重复N (
10000
) 次。
- 份额,p 值小于
0.5
, 0.2
, 0.1
,0.05
的次数:
p < 0.50: 0.5227
p < 0.20: 0.2166
p < 0.10: 0.1147
p < 0.05: 0.0511
10000
蒙特卡洛模拟的份额并没有太大的不同。看起来很公平的论点,即误报率没有被破坏。
复制代码(python):
import pandas as pd
import random
import numpy as np
from multiprocessing import Pool
# number of students:
n = 250
# number of possible answers and length of the test:
a = 2
k = 20
# number of monte carlo sims:
N = 10000
# number of processors:
cpu = 2
def get_pvals(iter = 0):
print(iter)
answers = []
for i in range(n):
answers.append(np.random.choice(range(a),k))
pairs = []
for i1 in range(n):
for i2 in range(i1+1, n):
neigh = 0
sim_ans = sum(answers[i1] == answers[i2])
if i1 != i2:
if i1 == i2-1:
neigh = 1
if i2 == i1-1:
neigh = 1
pairs.append({"sim_ans":sim_ans, "neigh":neigh})
d = pd.DataFrame(rows)
import statsmodels.formula.api as sm
result = sm.ols(formula = "sim_ans ~ neigh", data = d).fit()
p = result.pvalues['neigh']
return p
pvals = []
if __name__ == '__main__':
with Pool(cpu) as p:
pvals = p.map(get_pvals, range(N))
print(pvals)
print(sum(np.array(pvals) < 0.5)/N)
print(sum(np.array(pvals) < 0.2)/N)
print(sum(np.array(pvals) < 0.1)/N)
print(sum(np.array(pvals) < 0.05)/N)