目录
  1. 1. 数学建模
  2. 2. 使用Python求解
    1. 2.1. 直接计算
    2. 2.2. 概率模拟
  3. 3. 概率与统计原理
    1. 3.1. 二次分布与正态分布的关系
    2. 3.2. 场景应用
  4. 4. 彩蛋:怎么才能通过考试?
考试通过率如何判断?——概率与统计很有用

小明在准备某学科考试,经过多次自我测试,发现做题正确率为60%,已知做对60%的题目即为考试通过,那么小明考试通过的概率是多少?(假设考题数量足够多)

A. 60%     B. 50%

数学建模

60%?还是50%?

这是个考验直觉的问题,做题正确率为60%,直觉上考试通过概率也就是60%!

先来建模看看——

假设每道题目都是伯努利重复独立事件

做题正确率: p
考试题目总数: n
考试分数:k

那么很显然:

$$P(k)=C_n^i \times p^i \times (1-p)^{n-i}$$

所以,考试通过的概率为:

$$\sum_{i=0.6n}^{n}C_n^i \times p^i \times (1-p)^{n-i}$$

这是一个高中数学的题目,看起来没有任何挑战,是典型的的二项分布

不过,在高中时代,列式,但是没法求解

假设考试题目是100道题,那么结果是——

$$\sum_{i=60}^{100}C_{100}^i \times {0.6}^i \times 0.4^{100-i}$$

除非使用专业的数学软件,否则无法求解

使用Python求解

直接计算

为什么选择Python,唯一的答案就是

Python社区提供了很多开源库,下载后使用简单的import命令,就可以调用大神们写好的函数和算法

scipy是专门用于科学计算的一个常用的库,他于Numpy有着密切的关系,是需要通过Numpy做为scipy的基础,同时也是通过Numpy数据来操控科学计算

scipy的安装非常简单,借助Python包管理工具pip,在命令行中输入:

1
2
pip install numpy
pip install scipy

还是那句话,生命短暂,没有梯子请切换国内源

1
2
pip install numpy -i https://mirrors.aliyun.com/pypi/simple
pip install scipy -i https://mirrors.aliyun.com/pypi/simple

笔者在安装时出现了奇怪的错误,提示需要C环境,于是先安装了VS才搞定

1
2
3
4
5
6
7
8
9
10
11
12
from scipy.special import comb

total_score = 100
pass_sore = int(0.6*total_score)
p = 0.6

p_pass = 0.0 # 初始通过概率都是0
for i in range(pass_sore, total_score+1):
# 累加通过的概率
p_pass = p_pass + comb(total_score, i) * pow(p, i) * pow(1 - p, total_score - i)

print("通过的概率为", p_pass)

输出结果简单粗暴——

通过的概率为 0.5432944858820687

54.33%,既不是60%,也不是50%!

是不是100道题目太少了?

来,换成1000道!

1
total_score = 1000  #其他代码维持不变即可

通过的概率为 0.5137298582873664

不仅没能向60%靠近,反而通过概率更低了!

来个10000道题目试试——

好吧,试不了,溢出了

概率模拟

所谓的概率模拟,就是用随机的方式,模拟考试过程,增加实验次数,来接近实际的考试通过率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import random

#初始条件定义
total_score = 100 #总分数
p = 0.6
times = 1000000

#随机实验开始

def smulation_exam(times, total_score, p):
pass_times = 0
for i in range(0, times):
score = 0
for j in range(0, total_score):
if random.random() <= p:
score = score + 1
if score >= 0.6 * total_score:
pass_times = pass_times + 1 #考试通过次数加1
return pass_times


for total_score in range(100, 1100, 100):
print(total_score,smulation_exam(times, total_score, p)/times)

从直接算法和概率模拟的对比图可以清晰的看出,在重复实验100万次的情况,两者之间的拟合非常完美

那么我们继续将试题数量从1000向更大值扩展!

为了加快软件运行速度,可以借助多线程_thread功能,将100万次模拟分为多个线程运行

可以做一个大胆的推测,那就是考试通过的概率将无限趋近于50%

概率与统计原理

二次分布与正态分布的关系

看到50%,就会联想到正态分布

概率教科书上写的明明白白——

当n充分大时,二项分布趋近于正态分布

在实际使用中:当p<q且np≥5,或p>q且nq≥5,这时的n就被认为很大,可以用正态分布的概率作为近似值,期望与方差如下:

$$E(X)=\sum_{i=1}^{n}E(X_i)=np$$

$$D(X)=\sum_{i=1}^{n}D(X_i)=npq$$

场景应用

对于做题正确率为60%的考试,p=60%,q=40%,那么当题目数量>5/40%=125题时,此时二项分布可以近似为正态分布——

$$\mu=np=125\times 0.6= 75$$

$$\sigma=\sqrt {npq}=\sqrt {125\times 0.6\times0.4}= 5.48$$

于是,可以将其转化为标准正态分布,应用于查表分析——

$$\frac{X-\mu}{\sigma}= \frac{X-75}{5.48} \rightarrow N(0,1)$$

于是,借助标准正态分数表,我们可以快速求出分数75-85分的概率

X (X-μ)/δ 查表值 得分>X概率
75 0.00 0.5 50.0%
76 0.18 0.5714 42.9%
77 0.36 0.6406 35.9%
78 0.55 0.7088 29.1%
79 0.73 0.7673 23.3%
80 0.91 0.8186 18.1%
81 1.09 0.8621 13.8%
82 1.28 0.8997 10.0%
83 1.46 0.9278 7.2%
84 1.64 0.9484 5.2%
85 1.82 0.9656 3.4%

快速的查表方法是否准确呢?我们还是用python来计算理论值,对刚才的代码做简单的修改——

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from scipy.special import comb, perm
import math

total_score = 125
p = 0.6

for pass_sore in range(75,86,1):
i = total_score # 每次循环从都是满分向下遍历
p_pass = 0.0 # 每次循环初始通过概率都是0
while i >= pass_sore: # 遍历可以通过的场景
p_pass = p_pass + comb(total_score, i) * pow(p, i) * pow(1-p, total_score-i) # 累加通过的概率
if i == pass_sore:
break
i = i - 1
print(pass_sore, p_pass)

我们将查表值和理论值对比,两者非常的接近——

更何况125道题还是“当p<q且np≥5,或p>q且nq≥5”的最不精确的场景

当n充分大后,采用转换为正态分布的方法,可以快速获得近似结果

不管用什么方法,我们已经知道,直觉不够准确

小明在准备某学科考试,经过多次自我测试,发现做题正确率为60%,已知做对60%的题目即为考试通过,那么小明考试通过的概率是多少?(假设考题数量足够多)
A. 60% B. 50%

答案应该是B

彩蛋:怎么才能通过考试?

在统计学中,发生<=5%的事件通常被称为小概率事件

所以,当通过考试的概率至少为95%,基本可以认为可以通过考试

查表可知,0.95对应的Z=1.65,同样对于125道题目的例子,可以列出以下方程——

$$\frac{125 \times p-75}{\sqrt{125\times p \times (1-p)}} = 1.65$$

对这个简单的一元二次方程求解可得:

$$p=0.66924$$

也就是说,要达到67%的正确率,才能说是可以通过考试

查表计算的数字是否正确呢?

我们来用python检验一下

1
2
3
4
5
6
7
8
9
10
11
12
13
from scipy.special import comb

total_score = 125
pass_sore = int(0.6*total_score)
p = 0.6

for i in range(60,100,1):
p = i/100.0
p_pass = 0.0 # 初始通过概率都是0
for i in range(pass_sore, total_score+1):
# 累加通过的概率
p_pass = p_pass + comb(total_score, i) * pow(p, i) * pow(1 - p, total_score - i)
print("正确率", p, ",通过的概率为", p_pass)

正确率达到67%时,通过概率超过95%,python理论计算的结果和查表不谋而合!

文章作者: 西门吹风
文章链接: http://blog.fight365.cn/2019/11/11/考试通过率如何判断?——概率与统计很有用/
版权声明: 本博客所有文字除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 我的足迹 | 铁匠铺
本博客所有图片除特别声明外,均引用网络链接,如侵犯您的权益,请留言声明,我们将在第一时间删除

评论