用Python实战贾俊平《统计学》第八章手把手教你用SciPy搞定假设检验课后题假设检验是统计学中最重要的方法论之一但很多学习者在从理论转向实践时常常感到无从下手。本文将带你用Python的SciPy库完整复现贾俊平《统计学》第八章的所有课后习题通过代码实现各种假设检验场景包括Z检验、t检验、卡方检验等。不同于传统教材的纯理论推导我们将重点关注如何用现代数据科学工具解决实际问题。1. 环境准备与数据加载在开始之前我们需要确保Python环境中已安装必要的科学计算库。推荐使用Anaconda发行版它已经集成了我们所需的大部分工具。# 安装必要库如果尚未安装 !pip install numpy scipy pandas matplotlib # 导入库 import numpy as np from scipy import stats import pandas as pd对于假设检验问题数据准备通常有两种形式一种是已知总体参数和样本统计量如均值、方差另一种是需要从原始数据计算统计量。我们先处理第一种情况# 习题1的参数已知总体N(4.55,0.108²)样本均值4.484n9 mu 4.55 sigma 0.108 sample_mean 4.484 n 92. 单样本Z检验实战习题1是一个典型的单样本Z检验案例我们需要检验样本均值是否等于总体均值。SciPy的stats模块提供了便捷的检验函数。# 习题1解决方案 z_score (sample_mean - mu) / (sigma / np.sqrt(n)) p_value 2 * (1 - stats.norm.cdf(abs(z_score))) # 双侧检验 print(fZ统计量: {z_score:.3f}) print(fP值: {p_value:.4f}) # 使用scipy内置函数验证 result stats.ztest([sample_mean], valuemu, sigmasigma) print(fSciPy Z检验结果: Z{result[0]:.3f}, P{result[1]:.4f})注意当σ已知时使用Z检验σ未知且小样本时使用t检验对于类似结构的习题2和3我们可以建立通用函数def z_test(sample_mean, mu, sigma, n, alternativetwo-sided): 执行单样本Z检验 alternative: two-sided, less, greater z_score (sample_mean - mu) / (sigma / np.sqrt(n)) if alternative two-sided: p_value 2 * (1 - stats.norm.cdf(abs(z_score))) elif alternative less: p_value stats.norm.cdf(z_score) else: # greater p_value 1 - stats.norm.cdf(z_score) return z_score, p_value # 习题2应用示例 z, p z_test(680, 700, 60, 36, less) print(f习题2结果: Z{z:.3f}, P{p:.4f})3. 单样本t检验与方差检验当总体标准差未知时我们需要使用t检验。习题4提供了原始数据这是一个很好的实践案例。# 习题4数据准备 weights np.array([99.3, 98.7, 100.5, 101.2, 98.3, 99.7, 99.5, 102.1, 100.5]) mu 100 # 标准重量 # 计算样本统计量 sample_mean weights.mean() sample_std weights.std(ddof1) # 无偏估计 n len(weights) # 执行t检验 t_stat, p_val stats.ttest_1samp(weights, mu) print(ft统计量: {t_stat:.3f}) print(fP值: {p_val:.4f})对于方差检验如习题8我们需要使用卡方分布# 习题8解决方案 data np.array([85, 59, 66, 81, 35, 57, 55, 63, 66]) sigma2_0 100 # 假设的方差 sample_var data.var(ddof1) # 样本方差 n len(data) chi2_stat (n - 1) * sample_var / sigma2_0 p_value 1 - stats.chi2.cdf(chi2_stat, dfn-1) # 右尾检验 print(f卡方统计量: {chi2_stat:.3f}) print(fP值: {p_value:.4f})4. 双样本检验实战双样本检验在比较两个群体时非常有用。习题9-11展示了不同场景下的双样本检验方法。4.1 独立样本Z检验方差已知# 习题9参数 mu_a, mu_b 1070, 1020 sigma_a, sigma_b 63, 57 n_a, n_b 81, 64 # 计算Z统计量 z_num mu_a - mu_b z_den np.sqrt(sigma_a**2/n_a sigma_b**2/n_b) z_stat z_num / z_den # 计算P值双侧 p_value 2 * (1 - stats.norm.cdf(abs(z_stat))) print(fZ统计量: {z_stat:.3f}) print(fP值: {p_value:.4f})4.2 独立样本t检验方差未知但相等# 习题10数据准备 method_a np.array([...]) # 填入实际数据 method_b np.array([...]) # 填入实际数据 # 执行独立样本t检验 t_stat, p_val stats.ttest_ind(method_a, method_b, equal_varTrue) print(ft统计量: {t_stat:.3f}) print(fP值: {p_val:.4f})4.3 比例检验# 习题11解决方案 n1, n2 205, 134 # 吸烟者和不吸烟者数量 x1, x2 43, 13 # 患病数量 # 计算比例和合并比例 p1, p2 x1/n1, x2/n2 p_pool (x1 x2) / (n1 n2) # 计算Z统计量 z_num p1 - p2 z_den np.sqrt(p_pool * (1 - p_pool) * (1/n1 1/n2)) z_stat z_num / z_den # 计算P值右尾 p_value 1 - stats.norm.cdf(z_stat) print(fZ统计量: {z_stat:.3f}) print(fP值: {p_value:.4f})5. 高级应用与结果解读在实际数据分析中正确解读检验结果与选择适当的检验方法同样重要。让我们深入探讨几个关键点5.1 P值与显著性水平P值是在原假设成立的情况下观察到当前样本或更极端情况的概率。通常P值 α拒绝原假设P值 ≥ α不拒绝原假设# 判断是否拒绝原假设的实用函数 def make_decision(p_value, alpha0.05): if p_value alpha: return 拒绝原假设 else: return 不拒绝原假设 # 示例习题1结果 print(make_decision(0.0674)) # 输出不拒绝原假设5.2 检验力与样本量计算检验力(1-β)是正确拒绝错误原假设的概率。我们可以使用statsmodels进行检验力分析from statsmodels.stats import power # 计算Z检验的检验力 effect_size 0.5 # 效应量 power power.ttest_power(effect_size, nobs20, alpha0.05) print(f检验力: {power:.3f}) # 计算所需样本量 required_n power.tt_solve_power(effect_size0.5, power0.8, alpha0.05) print(f所需样本量: {int(required_n)})5.3 多重检验校正当进行多次假设检验时误报率会增加。常用的校正方法包括Bonferroni校正# 原始P值 p_values [0.01, 0.04, 0.03, 0.2] # Bonferroni校正 adjusted np.array(p_values) * len(p_values) print(f校正后P值: {adjusted})6. 常见问题与调试技巧在实际应用中你可能会遇到各种问题。以下是几个常见场景的解决方案6.1 数据正态性检验许多假设检验要求数据服从正态分布。我们可以使用Shapiro-Wilk检验# 生成正态和非正态数据 normal_data np.random.normal(size100) non_normal_data np.random.exponential(size100) # 正态性检验 _, p_normal stats.shapiro(normal_data) _, p_non_normal stats.shapiro(non_normal_data) print(f正态数据P值: {p_normal:.4f}) # 应0.05 print(f非正态数据P值: {p_non_normal:.4f}) # 应0.056.2 方差齐性检验独立样本t检验通常要求两组方差相等。可以使用Levene检验# 生成两组数据 group1 np.random.normal(0, 1, 50) group2 np.random.normal(0, 1.5, 50) # 方差齐性检验 _, p_var stats.levene(group1, group2) print(f方差齐性P值: {p_var:.4f}) # 0.05表示方差不齐6.3 非参数检验替代方案当数据不满足参数检验假设时可以使用非参数检验参数检验非参数替代单样本t检验Wilcoxon符号秩检验独立样本t检验Mann-Whitney U检验配对t检验Wilcoxon符号秩检验单因素ANOVAKruskal-Wallis检验# Mann-Whitney U检验示例 _, p_mw stats.mannwhitneyu(group1, group2) print(fMann-Whitney U检验P值: {p_mw:.4f})7. 综合案例与扩展应用让我们通过一个综合案例巩固所学内容。假设我们有一组学生的考试成绩数据# 生成模拟数据 np.random.seed(42) male_scores np.random.normal(75, 10, 100) female_scores np.random.normal(78, 8, 80) # 1. 正态性检验 _, p_male stats.shapiro(male_scores) _, p_female stats.shapiro(female_scores) # 2. 方差齐性检验 _, p_var stats.levene(male_scores, female_scores) # 3. 选择适当的检验并执行 if p_male 0.05 and p_female 0.05: if p_var 0.05: t_stat, p_val stats.ttest_ind(male_scores, female_scores, equal_varTrue) test_type 等方差t检验 else: t_stat, p_val stats.ttest_ind(male_scores, female_scores, equal_varFalse) test_type 异方差t检验 else: u_stat, p_val stats.mannwhitneyu(male_scores, female_scores) test_type Mann-Whitney U检验 print(f使用的检验: {test_type}) print(fP值: {p_val:.4f}) print(f结论: {make_decision(p_val)})这个完整的工作流程展示了如何在实际数据分析中应用假设检验。从数据检查到方法选择再到结果解读每一步都需要谨慎处理。