分享SCAU统计学实验解题思路,代码
实验一
描述:
第一次实验有 n 个人抛掷硬币,若有一人的硬币与其它 n−1 人的不同,则游戏结束。
问:第一次就结束的概率是多少?求游戏结束时抛掷硬币的平均次数。请结合概率的统计定义,编程仿真实现并求解以上问题。
已知: n=6 时,概率为 0.1875 (仅用于仿真比较)
分析:
p(第一次结束概率)=2×Cn1⋅0.5′⋅(1−0.5)n−1
抛掷硬币的平均次数,即求抛掷硬币次数的数学期望,当 n 足够大时,期望 ≈ 平均次数。
E(x)=i=1∑ni⋅p(第 i-1 轮未结束)⋅p(第 i 轮结束)
由于每次抛掷硬币都是独立的,所以 p(第 i 轮结束)=p(第一次结束概率)。
以上思路是基于概率学的推导计算,也可以采用蒙特卡罗法,用 random
模拟每次的结果,从而计算出结果。
实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| from math import *
def p_end(n): return 2 * comb(n, 1) * pow(0.5, n)
def train(n, epoch): p_i_exit = p_end(n) p_i_1_run = 1 Ex = 1 for i in range(1, epoch): p_i_1_run *= (1 - p_i_exit) Ex += i * p_i_exit * p_i_1_run return Ex
if __name__ == "__main__": n = 6 print("第一次结束概率:", p_end(n)) print("抛掷硬币的平均次数:{:.6f}".format(train(n, 1000000)))
|
输出结果:
第一次结束概率: 0.1875
抛掷硬币的平均次数:5.333333
实验二
描述:验证中心极限定理。
分析:
step 1:首先生成一个总体(约10000个数据),计算出总体的均值与方差
step 2:指定一个自然数 n(n可分别取2,3,5,15,25,30 …)
step 3:从总体中抽取 n 个数据组成一个样本,计算出样本的均值
step 4:重复step 3 m 次(例如:m=1000)
step 5:计算 m 个样本均值的平均值和方差
step 6:验证 m 个样本均值的平均值和方差与总体的均值、方差的数理关系
step 7:重复step 2到step 6的过程, n 取不同的对应值
step 8:生成不一样的总体数据,重复step 1到step 7的过程
实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import numpy as np
def test2(): size = 10000 data = np.random.normal(loc=100, scale=10, size=size) tot_mean = np.mean(data) tot_var = np.var(data)
batch_size = [2, 3, 5, 15, 25, 30, 50] epoch = 1000
for n in batch_size: print("批次大小为", n, "时:") sample_means = [] for i in range(epoch): sample = np.random.choice(data, size=n, replace=True) sample_means.append(np.mean(sample)) sample_means_mean = np.mean(sample_means) sample_means_var = np.var(sample_means) print(f" 总体均值: {tot_mean:.2f}, 样本均值的平均值: {sample_means_mean:.2f}") print(f" 总体方差: {tot_var:.2f}, 样本均值的方差: {sample_means_var:.2f}") print()
if __name__ == "__main__": for _ in range(100): print(f"************第{_ + 1}次实验************") test2()
|
输出结果:
第1次实验
批次大小为 2 时:
总体均值: 100.09, 样本均值的平均值: 100.12
总体方差: 98.84, 样本均值的方差: 51.28
批次大小为 3 时:
总体均值: 100.09, 样本均值的平均值: 100.17
总体方差: 98.84, 样本均值的方差: 33.31
批次大小为 5 时:
总体均值: 100.09, 样本均值的平均值: 99.95
总体方差: 98.84, 样本均值的方差: 19.90
批次大小为 15 时:
总体均值: 100.09, 样本均值的平均值: 100.09
总体方差: 98.84, 样本均值的方差: 6.29
批次大小为 25 时:
总体均值: 100.09, 样本均值的平均值: 100.22
总体方差: 98.84, 样本均值的方差: 4.03
批次大小为 30 时:
总体均值: 100.09, 样本均值的平均值: 100.08
总体方差: 98.84, 样本均值的方差: 3.20
批次大小为 50 时:
总体均值: 100.09, 样本均值的平均值: 100.13
总体方差: 98.84, 样本均值的方差: 1.90
…
第100次实验
批次大小为 2 时:
总体均值: 100.02, 样本均值的平均值: 99.95
总体方差: 97.85, 样本均值的方差: 50.26
批次大小为 3 时:
总体均值: 100.02, 样本均值的平均值: 100.21
总体方差: 97.85, 样本均值的方差: 33.85
批次大小为 5 时:
总体均值: 100.02, 样本均值的平均值: 99.96
总体方差: 97.85, 样本均值的方差: 19.24
批次大小为 15 时:
总体均值: 100.02, 样本均值的平均值: 100.05
总体方差: 97.85, 样本均值的方差: 6.40
批次大小为 25 时:
总体均值: 100.02, 样本均值的平均值: 100.01
总体方差: 97.85, 样本均值的方差: 3.79
批次大小为 30 时:
总体均值: 100.02, 样本均值的平均值: 100.13
总体方差: 97.85, 样本均值的方差: 3.26
批次大小为 50 时:
总体均值: 100.02, 样本均值的平均值: 99.95
总体方差: 97.85, 样本均值的方差: 2.05
实验三
描述:
根据自己手机微信每月支付的数据计算出微信支付的月支付95%的置信区间
并画出近三年来月支付金额的分布图(为避免隐私问题,数据可以自己构造)
分析:
首先我们需要自己构造数据,并且近三年内月支付只有 3 * 12 = 36
个数据,属于小样本量,并且大概率不属于正态分布。
于是我们假设数据服从T分布,来计算置信区间。
这种方法适用于样本量较小或者数据不满足正态分布的情况。
实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| import numpy as np from scipy import stats import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimSun']
data = np.array([ 1326, 1032, 1445, 1612, 1455, 2176, 2172, 1508, 1593, 2356, 1713, 1871, 1934, 1421, 2149, 1791, 1648, 1477, 1716, 1279, 1755, 1657, 1712, 1950, 1577, 2005, 1787, 1768, 1837, 1823, 1325, 2145, 2050, 1901, 1908, 1744 ])
mean = np.mean(data) std = np.std(data) se = std / np.sqrt(len(data))
confidence = 0.95 critical_value = stats.t.ppf((1 + confidence) / 2, len(data) - 1) * se lower_limit = mean - critical_value upper_limit = mean + critical_value
print(f"微信月支付\n" f"置信区间:[{lower_limit:.4f}, {upper_limit:.4f}]\n" f"置信度:95%")
data_sorted = np.sort(data)
bin_size = 200 hist, bins = np.histogram(data_sorted, bins=np.arange(data_sorted.min(), data_sorted.max() + bin_size, bin_size))
plt.bar(bins[:-1], hist, width=bin_size, align='edge', edgecolor='black', color='skyblue', label='频数')
plt.axvline(lower_limit, color='red', linestyle='--', label='置信区间下限') plt.axvline(upper_limit, color='green', linestyle='--', label='置信区间上限')
plt.title('月支付金额分布图') plt.xlabel('金额') plt.ylabel('频数') plt.legend()
plt.show()
|
输出结果:
微信月支付
置信区间:[1642.3460, 1836.4318]
置信度:95%
实验四
编码实现单个总体的假设检验
描述:
某地区小麦的一般生产水平为亩产 250 千克,其标准差为 30 千克。现用一种化肥进行试验, 从 25 个地块抽样,平均亩产量为 270 千克。
这种化肥是否使小麦明显增产(α=0.05)?
分析:
总体平均值(μ):250 kg
总体标准差(σ2):30kg
样本平均值(xˉ):270 kg
样本大小(n):25
我们已经知道小麦亩产的总体方差(σ2),所以应该使用 Z 检验。
需要检验使用化肥后平均亩产是否增产(μ>250),即右侧检验。
H0:μ≤250 H1:μ>250
Z 检验统计量:
Z=σ/nx−μ
实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import math import numpy as np from scipy.stats import norm
def z_test(tot_mean, tot_var, sample_mean, n): SE = tot_var / math.sqrt(n) z_score = (sample_mean - tot_mean) / SE
p_value = 1 - norm.cdf(np.abs(z_score))
return z_score, p_value
if __name__ == "__main__": tot_mean = 250 tot_var = 30 sample_mean = 270 n = 25 alpha = 0.05
z_score, p_value = z_test(tot_mean, tot_var, sample_mean, n)
print(f"Z值: {z_score:.4f}") print(f"P值: {p_value:.4f}")
if p_value < alpha: print("拒绝原假设,使用化肥后平均亩产增产") else: print("接受原假设,使用化肥后平均亩产未增产")
|
输出结果:
Z值: 3.3333
P值: 0.0004
拒绝原假设,使用化肥后平均亩产增产
经过Z 检验后,拒绝原假设,该化肥能使小麦明显增产。
描述:
某种电子元件的寿命 x 服从正态分布。现测得 16 只元件的寿命(单位:小时)如下:
159 |
280 |
101 |
212 |
224 |
379 |
179 |
264 |
222 |
362 |
168 |
250 |
149 |
260 |
485 |
170 |
是否有理由认为元件的平均寿命显著地大于225 小时(α=0.05)?
分析:
电子元件的寿命总体均值 μ 未知,故可以采用 T 检验。
需要检验元件的平均寿命是否大于225小时(μ>225),即右侧检验。
H0:μ≤225 H1:μ>225
T=s/nx−μ
需要自己计算出寿命 x 的样本均值、样本标准差。
实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| import math import numpy as np from scipy import stats
def t_test(data, n, test_time): sample_mean = np.mean(data) sample_std = np.std(data, ddof=1)
SE = sample_std / math.sqrt(n) t_score = (sample_mean - test_time) / SE
alpha = 0.05 df = n - 1 critical_value = stats.t.ppf(1 - alpha, df)
p_value = stats.t.sf(np.abs(t_score), df)
return t_score, critical_value, p_value
if __name__ == "__main__": data = [159, 280, 101, 212, 224, 379, 179, 264, 222, 362, 168, 250, 149, 260, 485, 170] test_time = 225 n = 16 alpha = 0.05
t_score, critical_value, p_value = t_test(data, n, test_time)
print(f"T值: {t_score:.4f}") print(f"临界值: {critical_value:.4f}") print(f"P值: {p_value:.4f}")
print() print("从临界值角度:") if t_score < critical_value: print("落在非拒绝域,接受原假设,元件的平均寿命 ≤ 225小时") else: print("落在拒绝域,拒绝原假设,元件的平均寿命 > 225小时")
print("从P值角度:") if p_value < alpha: print("拒绝原假设,元件的平均寿命 > 225小时") else: print("接受原假设,元件的平均寿命 ≤ 225小时")
|
输出结果:
T值: 0.6685
临界值: 1.7531
P值: 0.2570
从临界值角度:
落在非拒绝域,接受原假设,元件的平均寿命 ≤ 225小时
从P值角度:
接受原假设,元件的平均寿命 ≤ 225小时
经过T 检验后,
从临界值角度:
t=s/nx−μ0=0.669<t0.05(16)=1.753
t值小于自由度为16的 T 分布的上0.05分位点,落在非拒绝域,故接受原假设。
从P值角度:
Pvalue=P(T>0.669)=0.257>α=0.05
如果拒接原假设,犯弃真错误的概率达0.257,大于 α=0.05 ,故接受原假设。
综上,接受原假设,元件的平均寿命 ≤ 225小时。
实验五
描述:给出两个.csv文件,数据分别为某两股票为期一年的日交易信息
请根据每只股票的收盘价与开盘价计算相应每天的波动状况,计算一年来那只股票的每天差额波动大?
每天差额值的分布是否服从正态分布,是否是对称的?
分析:
数据的离散程度:
要比较股票的差额波动程度,可以计算差额的方差和变异系数。
方差:
σ2=N∑(X−μ)2
标准差:
σ=σ
平均值:
μ=n∑i=1nxi
变异系数:
cv=μσ
正态分布检验:
通过 cipy.stats.normaltest 计算 p 值
通过 .skew() 计算 symmetry
p⎩⎨⎧<0.05 不服从正态分布≥0.05 服从正态分布
symmetry⎩⎨⎧>0=0<0右偏对称左偏
实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| import numpy as np import pandas as pd from matplotlib import pyplot as plt from scipy.stats import normaltest, norm
def stock_analysis(path, num): df = pd.read_csv(path, encoding='GBK') df['差额'] = df['收盘价'] - df['开盘价']
var = df['差额'].var() std = df['差额'].std() mean = df['差额'].mean() cv = (std - mean) * 100 if mean else 0
stat, p_value = normaltest(df['差额']) symmetry = df['差额'].skew()
print(f"股票{num}的波动情况:") print(f"方差: {var:.4f}") print(f"变异系数: {cv:.4f}") print()
plt.figure() plt.hist(df['差额'], bins=30, density=True, alpha=0.6, color='g') xmin, xmax = plt.xlim() x = np.linspace(xmin, xmax, 100) p = norm.pdf(x, mean, std) plt.plot(x, p, 'k', linewidth=2) title = f'股票{num}的差额正态分布图' plt.title(title) plt.show()
return var, cv, p_value, symmetry
def normal_analysis(p_value, symmetry, num): if p_value < 0.05: print(f"股票{num}:差额不服从正态分布") else: print(f"股票{num}:差额服从正态分布")
if symmetry == 0: print(f"股票{num}:差额对称") elif symmetry > 0: print(f"股票{num}:差额右偏") else: print(f"股票{num}:差额左偏") print()
if __name__ == "__main__":
plt.rcParams['font.sans-serif'] = ['SimSun'] plt.rcParams["axes.unicode_minus"] = False
path1 = 'daily_20240428200156.csv' var1, cv1, p_value1, symmetry1 = stock_analysis(path1, 1) path2 = 'daily_20240428200125.csv' var2, cv2, p_value2, symmetry2 = stock_analysis(path2, 2)
print("结论:", end="") if var1 > var2: print("股票1每天差额波动较大\n") elif var1 < var2: print("股票2每天差额波动较大\n") else: print("两只股票每天差额波动相同\n")
print("正态分析:") normal_analysis(p_value1, symmetry1, 1) normal_analysis(p_value2, symmetry2, 2)
|
输出结果:
股票1的波动情况:
方差: 0.0670
变异系数: 22.6865
股票2的波动情况:
方差: 5.0120
变异系数: 202.7938
结论:股票2每天差额波动较大
正态分析:
股票1:差额不服从正态分布
股票1:差额右偏
股票2:差额不服从正态分布
股票2:差额右偏
最后画出两只股票的正态分布图:
实验六
描述:
根据方差分析的描述,编写一个单因素方差分析的函数。
输入为某二维数据(列代表因素各水平值)
输出为检验统计量 F 的值
分析:
0.数据结构
A1 |
A2 |
··· |
Ak |
x11 |
x21 |
··· |
xk1 |
x12 |
x12 |
··· |
xk2 |
⋮ |
⋮ |
⋮ |
⋮ |
x1n1 |
x2n2 |
··· |
xknk |
在单因素方差分析中,用 A 表示因素,因素的 k 个水平 (总体)分别用 A1,A2,⋅⋅⋅,Ak 表示,每个观测值用 xij ( i=1,2,⋅⋅⋅,k;j=1,2,⋅⋅⋅,ni )表示,即 xij 表示第 i 个水平(总体)的第 j 个观测值。值得注意的是,每个因素的观测值数量可能不同,即 ni 不同。
1.提出假设
H0:μ1=μ2=⋯=μi=⋯=μk 自变量对因变量没有显著影响
H1:μi(i=1,2,⋯,k) 自变量对因变量有显著影响
式中,μi为第 i 个总体的均值。
2.构造检验的统计量
(1) 计算各样本的均值
假定从第 i 个总体中抽取一个容量为 ni 的简单随机样本,令 xi 为第 i 个总体的样本均值,则有
xˉi=ni∑j=1nixij,i=1,2,⋯,k
式中, ni 为第 i 个总体的样本量; xij 为第 i 个总体的第 j 个观测值。
(2) 计算全部观测值的总均值
全部观测值的总和除以观测值总个数的结果。令总均值为 x ,则有
x=n∑i=1k∑j=1nixij=n∑i=1knixi
式中, n=n1+n2+⋅⋅⋅+nk
(3) 计算各误差平方和
分别计算三个误差平方和,它们是总平方和、组间平方和(因素平方和)、组内平方和(误差平方和或残差平方和)。
- 总平方和
记为 SST ,它是全部观测值 xij 与总均值 x 的误差平方和,反映各所有观测值与总均值之间的差异
SST=i=1∑kj=1∑ni(xij−x)2
- 组间平方和
记为 SSA ,它是各组均值 xi ( i=1,2,⋅⋅⋅,k ) 与总均值 x 的误差平方和,反映各样本均值之间的差异程度
SSA=i=1∑kni(xi−x)2
- 组内平方和
记为 SSE ,它是每个水平或组的各样本数据与其组均值的误差平方和,反映每个样本各观测值的离散状况
SSE=i=1∑ki=1∑ni(xij−xi)2
- 计算统计量
为了消除观测值多少对误差平方和大小的影响,需要将其平均,也就是用各平方和除以它们所对应的自由度,这一结果称为均方。
SST 的自由度为 n−1 ,其中 n 为全部观测值的个数。
SSA 的自由度为 k−1 ,其中 k 为因素水平(总体)的个数。
SSE 的自由度为 n−k 。
由于要比较的是组间均方和组内均方之间的差异,所以通常只计算 SSA 的均方和 SSE 的均方。
SSA 的均方也称组间均方或组间方差,记为 MSA
MSA=自由度组间平方和=k−1SSA
SSE 的均方也称为组内均方或组内方差,记为 MSE
MSE=自由度组内平方和=n−kSSE
将上述 MSA 和 MSE 进行对比,即得到所需要的检验统计量 F 。
当 H0 为真时,二者的比值服从分子自由度为 k−1 、分母自由度为 n−k 的 F 分布,即
F=MSEMSA∼F(k−1,n−k)
3.作出统计决策
正常的单因素方差分析还需根据 F 分布表,作出对原假设 H0 的决策,此处只需求出统计量 F 的值即可,不过多赘述。
实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| import numpy as np
def one_way_analysis_of_variance(data): SSA = 0 SSE = 0
nonzero_group_num = np.count_nonzero(data != 0, axis=0) nonzero_total_num = data.size - np.count_nonzero(data == 0) nonzero_total_mean = np.mean(data[data != 0])
for i, group_data in enumerate(data.T): group_nonzero_data = group_data[group_data != 0] group_mean = np.mean(group_nonzero_data)
if group_nonzero_data.size > 0: SSA += group_nonzero_data.size * (group_mean - nonzero_total_mean) ** 2 SSE += np.sum((group_nonzero_data - group_mean) ** 2)
SSA_freedon_degree = data.shape[1] - 1 SSE_freedon_degree = nonzero_total_num - data.shape[1]
MSA = SSA / SSA_freedon_degree MSE = SSE / SSE_freedon_degree
F_value = MSA / MSE
return F_value
data = np.array([ [57, 68, 31, 44], [66, 39, 49, 51], [49, 29, 21, 65], [40, 45, 34, 77], [34, 56, 40, 58], [53, 51, 0, 0], [44, 0, 0, 0] ])
if __name__ == "__main__": F_value = one_way_analysis_of_variance(data) print(f"检验统计量 F 的值为: {F_value:.6f}")
|
输出结果:
检验统计量 F 的值为: 3.406643
实验七
描述:
编写两个 一元线性回归中的函数
第一个函数求相关系数
第二个函数求一次项系数
分析:
输入两个一维向量序列,分别求出相关系数和一次项系数
1.相关系数
相关系数是研究变量之间线性相关程度的量。
r(X,Y)=Var[X]Var[Y]Cov(X,Y)
其中 Cov(X,Y) 是协方差, Var 是方差。
2.一次项系数
参数的最小二乘估计
y^i=β^0+β^1xi
β^1=n∑i=1nxi2−(∑i=1nxi)2n∑i=1nxiyi−∑i=1nxi∑i=1nyi
其中 β^1 即为一次项系数
实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| def correlation_coefficient(x, y): mean_x = sum(x) / len(x) mean_y = sum(y) / len(y)
covariance = sum((x[i] - mean_x) * (y[i] - mean_y) for i in range(len(x)))
var_x = sum((x[i] - mean_x) ** 2 for i in range(len(x))) var_y = sum((y[i] - mean_y) ** 2 for i in range(len(y))) denominator = (var_x * var_y) ** 0.5
r = covariance / denominator return r
def linear_regression(x, y): sum_x = sum(x) sum_y = sum(y) sum_xy = sum(x[i] * y[i] for i in range(len(x))) sum_x_square = sum(x[i] ** 2 for i in range(len(x)))
a = (len(x) * sum_xy - sum_x * sum_y) / (len(x) * sum_x_square - sum_x ** 2)
return a
x = [67.3, 111.3, 173.0, 80.8, 199.7, 16.2, 107.4, 185.4, 96.1, 72.8, 64.2, 132.2, 58.6, 174.6, 263.5, 79.3, 14.8, 73.5, 24.7, 139.4, 368.2, 95.7, 109.6, 196.2, 102.2] y = [0.9, 1.1, 4.8, 3.2, 7.8, 2.7, 1.6, 12.5, 1.0, 2.6, 0.3, 4.0, 0.8, 3.5, 10.2, 3.0, 0.2, 0.4, 1.0, 6.8, 11.6, 1.6, 1.2, 7.2, 3.2]
if __name__ == "__main__": print(f"相关系数为:{correlation_coefficient(x, y):.6f}") print(f"一次项系数为:{linear_regression(x, y):.6f}")
|
输出结果:
相关系数为:0.843571
一次项系数为:0.037895