用Python实战贾俊平《统计学》第四章:手把手教你用NumPy/Pandas搞定描述性统计(附代码)
用Python实战贾俊平《统计学》第四章手把手教你用NumPy/Pandas搞定描述性统计附代码统计学教材中的公式和概念常常让学习者感到抽象难懂而实际数据分析工作中又迫切需要这些统计工具。本文将贾俊平《统计学》第四章的核心知识点与Python的NumPy、Pandas库相结合通过代码示例让描述性统计变得直观可操作。1. 环境准备与数据加载在开始之前确保已安装Python基础数据科学栈。推荐使用Anaconda发行版它包含了我们所需的大部分工具conda install numpy pandas matplotlib jupyter假设我们有一个班级30名学生的考试成绩数据集模拟贾俊平教材中的案例我们将用Pandas加载并查看数据import numpy as np import pandas as pd import matplotlib.pyplot as plt # 模拟创建数据集 data { 姓名: [f学生{i} for i in range(1, 31)], 数学成绩: [78, 85, 92, 65, 88, 72, 95, 81, 63, 70, 82, 89, 76, 91, 84, 77, 69, 83, 90, 74, 86, 79, 93, 68, 80, 87, 75, 94, 67, 71], 统计成绩: [85, 76, 90, 68, 82, 73, 88, 79, 65, 71, 84, 87, 77, 92, 80, 75, 70, 83, 89, 72, 86, 78, 91, 69, 81, 85, 74, 93, 66, 70] } df pd.DataFrame(data) print(df.head())2. 集中趋势度量2.1 均值、中位数与众数教材中介绍的三大集中趋势指标用Python实现只需一行代码# 计算数学成绩的集中趋势指标 mean_math np.mean(df[数学成绩]) median_math np.median(df[数学成绩]) mode_math df[数学成绩].mode()[0] # 众数可能有多个取第一个 print(f数学成绩均值: {mean_math:.2f}) print(f数学成绩中位数: {median_math}) print(f数学成绩众数: {mode_math})注意当数据中存在多个众数时mode()方法会返回所有众数需要根据实际情况处理。2.2 加权平均数教材中提到的加权平均计算在实际业务场景中很常见。假设数学成绩的期中考试占40%期末考试占60%midterm np.random.randint(50, 100, size30) # 模拟期中成绩 final df[数学成绩] # 使用之前的成绩作为期末成绩 weighted_avg np.average([midterm, final], weights[0.4, 0.6], axis0) df[数学加权成绩] weighted_avg3. 离散程度度量3.1 极差与四分位距离散程度指标帮助我们了解数据的波动情况# 极差全距 math_range np.ptp(df[数学成绩]) # peak to peak # 四分位数和四分位距 q1 np.percentile(df[数学成绩], 25) q3 np.percentile(df[数学成绩], 75) iqr q3 - q1 print(f数学成绩极差: {math_range}) print(f数学成绩四分位距(IQR): {iqr})3.2 方差与标准差方差和标准差是最常用的离散程度指标# 总体方差与样本方差 population_var np.var(df[数学成绩]) # 总体方差 sample_var df[数学成绩].var(ddof1) # 样本方差无偏估计 # 标准差 population_std np.std(df[数学成绩]) sample_std df[数学成绩].std(ddof1) print(f数学成绩总体标准差: {population_std:.2f}) print(f数学成绩样本标准差: {sample_std:.2f})提示ddof参数代表自由度调整计算样本方差时通常设为1n-14. 分布形状分析4.1 偏态系数偏态系数衡量数据分布的不对称性from scipy.stats import skew math_skew skew(df[数学成绩]) stats_skew skew(df[统计成绩]) print(f数学成绩偏态系数: {math_skew:.2f}) print(f统计成绩偏态系数: {stats_skew:.2f}) # 可视化对比 plt.figure(figsize(12, 5)) plt.subplot(1, 2, 1) plt.hist(df[数学成绩], bins10, edgecolorblack) plt.title(数学成绩分布) plt.subplot(1, 2, 2) plt.hist(df[统计成绩], bins10, edgecolorblack) plt.title(统计成绩分布) plt.show()4.2 峰态系数峰态系数反映数据分布的尖峰或扁平程度from scipy.stats import kurtosis math_kurtosis kurtosis(df[数学成绩]) stats_kurtosis kurtosis(df[统计成绩]) print(f数学成绩峰态系数: {math_kurtosis:.2f}) print(f统计成绩峰态系数: {stats_kurtosis:.2f})5. 综合应用完整描述性统计报告Pandas提供了describe()方法快速生成全面的描述性统计# 基本描述统计 desc_stats df[[数学成绩, 统计成绩]].describe() print(desc_stats) # 添加额外的统计量 desc_stats.loc[var] df[[数学成绩, 统计成绩]].var() desc_stats.loc[skew] df[[数学成绩, 统计成绩]].skew() desc_stats.loc[kurtosis] df[[数学成绩, 统计成绩]].kurtosis() print(\n扩展描述统计:) print(desc_stats)对于更专业的分析报告可以自定义函数def extended_describe(data): 生成扩展描述统计报告 stats data.describe() additional { 方差: data.var(), 偏度: data.skew(), 峰度: data.kurtosis(), IQR: stats.loc[75%] - stats.loc[25%], 变异系数: data.std() / data.mean() } for name, value in additional.items(): stats.loc[name] value return stats.sort_index() print(extended_describe(df[数学成绩]))6. 实际案例教材习题Python实现以贾俊平教材第四章课后习题为例演示如何用Python解决统计计算问题。假设有一道求分组数据众数的题目原始数据成绩区间频数60以下360-70770-801280-90890以上5# 构建分组数据 bins [0, 60, 70, 80, 90, 100] labels [60以下, 60-70, 70-80, 80-90, 90以上] frequencies [3, 7, 12, 8, 5] # 计算分组数据的众数 max_freq_index np.argmax(frequencies) mode_class labels[max_freq_index] print(f众数所在组: {mode_class})对于更复杂的分组数据统计计算可以构建虚拟数据集# 根据频数表创建虚拟数据集 all_scores [] for i in range(len(frequencies)): lower bins[i] upper bins[i1] if i len(bins)-1 else 100 # 在每个区间内生成均匀分布的点 scores np.random.uniform(lower, upper, sizefrequencies[i]) all_scores.extend(scores) virtual_data pd.Series(all_scores) print(\n基于虚拟数据计算的统计量:) print(extended_describe(virtual_data))7. 效率对比手动计算 vs 编程计算为了展示Python在统计分析中的效率优势我们比较两种计算方式import time # 手动计算均值 start time.time() manual_mean sum(df[数学成绩]) / len(df[数学成绩]) manual_time time.time() - start # Python计算均值 start time.time() python_mean df[数学成绩].mean() python_time time.time() - start print(f手动计算均值: {manual_mean:.2f}, 耗时: {manual_time:.6f}秒) print(fPython计算均值: {python_mean:.2f}, 耗时: {python_time:.6f}秒) print(f速度提升: {manual_time/python_time:.1f}倍)即使是这个简单例子Python的向量化运算通常也能带来数十倍的性能提升。对于更复杂的统计量和大数据集优势会更加明显。