用Python实战贾俊平《统计学》第八章:手把手教你用SciPy搞定假设检验课后题
2026/5/30 1:15:15 网站建设 项目流程

用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.484,n=9 mu = 4.55 sigma = 0.108 sample_mean = 4.484 n = 9

2. 单样本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(f"Z统计量: {z_score:.3f}") print(f"P值: {p_value:.4f}") # 使用scipy内置函数验证 result = stats.ztest([sample_mean], value=mu, sigma=sigma) print(f"SciPy Z检验结果: Z={result[0]:.3f}, P={result[1]:.4f}")

注意:当σ已知时使用Z检验,σ未知且小样本时使用t检验

对于类似结构的习题2和3,我们可以建立通用函数:

def z_test(sample_mean, mu, sigma, n, alternative='two-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(ddof=1) # 无偏估计 n = len(weights) # 执行t检验 t_stat, p_val = stats.ttest_1samp(weights, mu) print(f"t统计量: {t_stat:.3f}") print(f"P值: {p_val:.4f}")

对于方差检验(如习题8),我们需要使用卡方分布:

# 习题8解决方案 data = np.array([85, 59, 66, 81, 35, 57, 55, 63, 66]) sigma2_0 = 100 # 假设的方差 sample_var = data.var(ddof=1) # 样本方差 n = len(data) chi2_stat = (n - 1) * sample_var / sigma2_0 p_value = 1 - stats.chi2.cdf(chi2_stat, df=n-1) # 右尾检验 print(f"卡方统计量: {chi2_stat:.3f}") print(f"P值: {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(f"Z统计量: {z_stat:.3f}") print(f"P值: {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_var=True) print(f"t统计量: {t_stat:.3f}") print(f"P值: {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(f"Z统计量: {z_stat:.3f}") print(f"P值: {p_value:.4f}")

5. 高级应用与结果解读

在实际数据分析中,正确解读检验结果与选择适当的检验方法同样重要。让我们深入探讨几个关键点:

5.1 P值与显著性水平

P值是在原假设成立的情况下,观察到当前样本或更极端情况的概率。通常:

  • P值 < α:拒绝原假设
  • P值 ≥ α:不拒绝原假设
# 判断是否拒绝原假设的实用函数 def make_decision(p_value, alpha=0.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, nobs=20, alpha=0.05) print(f"检验力: {power:.3f}") # 计算所需样本量 required_n = power.tt_solve_power(effect_size=0.5, power=0.8, alpha=0.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(size=100) non_normal_data = np.random.exponential(size=100) # 正态性检验 _, 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.05

6.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(f"Mann-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_var=True) test_type = "等方差t检验" else: t_stat, p_val = stats.ttest_ind(male_scores, female_scores, equal_var=False) test_type = "异方差t检验" else: u_stat, p_val = stats.mannwhitneyu(male_scores, female_scores) test_type = "Mann-Whitney U检验" print(f"使用的检验: {test_type}") print(f"P值: {p_val:.4f}") print(f"结论: {make_decision(p_val)}")

这个完整的工作流程展示了如何在实际数据分析中应用假设检验。从数据检查到方法选择,再到结果解读,每一步都需要谨慎处理。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询