主题:11.1 描述性统计(均值 / 中位数 / 标准差)
“数据是海,分析是舟”。本章用人文社科友好的语言与例子,带你用 Python 完成最常见的描述性统计。
目标:能看懂指标含义、会用numpy与pandas计算,并能避开常见坑。
np.mean(x), np.median(x), np.std(x, ddof=0) ddof=0(默认)是总体标准差;如需样本标准差,用 np.std(x, ddof=1)。s.mean(), s.median(), s.std(ddof=1) std() 默认 ddof=1,即样本标准差(和 NumPy 默认不一样)。round(value, 2) 保留 2 位小数;或用 print(f"{value:.2f}")。NaN)会让计算结果变成 NaN。要先清理或用 skipna=True(Pandas)。我们用一组小数据:[85, 90, 78, 92, 88]。
# 示范:使用 NumPy 计算
import numpy as np
scores = [85, 90, 78, 92, 88]
mean_score = np.mean(scores) # 均值(NumPy,默认总体)
median_score = np.median(scores) # 中位数
std_pop = np.std(scores, ddof=0) # 总体标准差
std_sample = np.std(scores, ddof=1) # 样本标准差(研究中更常见)
print("【NumPy】")
print("均值:", round(mean_score, 2))
print("中位数:", round(median_score, 2))
print("总体标准差 (ddof=0):", round(std_pop, 2))
print("样本标准差 (ddof=1):", round(std_sample, 2))
【NumPy】 均值: 86.6 中位数: 88.0 总体标准差 (ddof=0): 4.88 样本标准差 (ddof=1): 5.46
# 示范:使用 Pandas 计算
import pandas as pd
s = pd.Series([85, 90, 78, 92, 88])
print("【Pandas】")
print("均值:", round(s.mean(), 2))
print("中位数:", round(s.median(), 2))
print("标准差(默认样本标准差 ddof=1):", round(s.std(), 2))
print("总体标准差:", round(s.std(ddof=0), 2))
C:\Users\Zhouq\AppData\Roaming\Python\Python39\site-packages\pandas\core\computation\expressions.py:21: UserWarning: Pandas requires version '2.8.4' or newer of 'numexpr' (version '2.8.3' currently installed). from pandas.core.computation.check import NUMEXPR_INSTALLED C:\Users\Zhouq\AppData\Roaming\Python\Python39\site-packages\pandas\core\arrays\masked.py:60: UserWarning: Pandas requires version '1.3.6' or newer of 'bottleneck' (version '1.3.5' currently installed). from pandas.core import (
【Pandas】 均值: 86.6 中位数: 88.0 标准差(默认样本标准差 ddof=1): 5.46 总体标准差: 4.88
data_even = [60, 80, 85, 90, 100, 110]
print("数据(偶数个):", data_even)
print("中位数(NumPy):", np.median(data_even))
数据(偶数个): [60, 80, 85, 90, 100, 110] 中位数(NumPy): 87.5
在社会经济数据中,经常会出现“少量特别高/低”的极端值。我们比较:
[5, 6, 6, 7, 7] [5, 6, 6, 7, 70](加入一个极高值 70)A = np.array([5, 6, 6, 7, 7], dtype=float)
B = np.array([5, 6, 6, 7, 70], dtype=float)
def summary(x):
return {
"均值": float(np.mean(x)),
"中位数": float(np.median(x)),
"样本标准差": float(np.std(x, ddof=1))
}
print("A组:", summary(A))
print("B组:", summary(B))
A组: {'均值': 6.2, '中位数': 6.0, '样本标准差': 0.8366600265340756}
B组: {'均值': 18.8, '中位数': 6.0, '样本标准差': 28.630403420140627}
观察: 加入极端值后,B 组的均值被明显拉高,但中位数变化很小 → 中位数更稳健(robust)。
在不均衡分布(如收入、粉丝量)中,用中位数更能反映“典型水平”。
ddof=1)。NumPy np.std 默认 ddof=0,要自己改;Pandas 默认 ddof=1。s.mean(skipna=True);NumPy:用 np.nanmean 等函数处理含 np.nan 的数组。int/float)。字符串会导致计算报错或被忽略。数据:[85, 90, 78, 92, 88]
任务:用 NumPy 和 Pandas 分别计算 均值 / 中位数 / 样本标准差(ddof=1),并保留 2 位小数。
数据A:[5, 6, 6, 7, 7],数据B:[5, 6, 6, 7, 70]
任务:分别计算均值/中位数/样本标准差,比较差异,并用 1–2 句话解释:哪一个指标更稳健?为什么?
数据:[60, 75, None, 90, 85](其中 None 表示缺失)
任务:用 Pandas 计算均值与中位数,跳过缺失值;再尝试用 NumPy 处理这组数据(提示:np.nan 与 np.nanmean)。
# === 在此动手做题(你可以多建几个单元格)===
# 练习1
import numpy as np
import pandas as pd
scores = [85, 90, 78, 92, 88]
# TODO: 在这里写出 NumPy 与 Pandas 的计算代码,并打印结果
# 练习2
A = [5, 6, 6, 7, 7]
B = [5, 6, 6, 7, 70]
# TODO: 分别计算 A、B 的均值/中位数/样本标准差并比较
# 练习3(缺失值)
data_with_nan = [60, 75, None, 90, 85]
# TODO: Pandas 跳过缺失值;NumPy 用 np.nan 与 np.nanmean 处理
建议先独立完成练习再看答案。
# 练习1 参考答案
import numpy as np
import pandas as pd
scores = [85, 90, 78, 92, 88]
# NumPy(样本标准差 ddof=1)
mean_np = np.mean(scores)
median_np = np.median(scores)
std_np = np.std(scores, ddof=1)
# Pandas(std 默认 ddof=1)
s = pd.Series(scores)
mean_pd = s.mean()
median_pd = s.median()
std_pd = s.std()
print("【练习1】")
print("NumPy → 均值/中位数/样本标准差:", round(mean_np,2), round(median_np,2), round(std_np,2))
print("Pandas → 均值/中位数/样本标准差:", round(mean_pd,2), round(median_pd,2), round(std_pd,2))
【练习1】 NumPy → 均值/中位数/样本标准差: 86.6 88.0 5.46 Pandas → 均值/中位数/样本标准差: 86.6 88.0 5.46
# 练习2 参考答案
import numpy as np
A = np.array([5, 6, 6, 7, 7], dtype=float)
B = np.array([5, 6, 6, 7, 70], dtype=float)
def stat3(x):
return round(np.mean(x),2), round(np.median(x),2), round(np.std(x, ddof=1),2)
a_mean, a_med, a_std = stat3(A)
b_mean, b_med, b_std = stat3(B)
print("【练习2】")
print("A → 均值/中位数/样本标准差:", a_mean, a_med, a_std)
print("B → 均值/中位数/样本标准差:", b_mean, b_med, b_std)
print("\n解释:加入极端值后,B 的“均值”被大幅拉高,但“中位数”变化小 → 中位数更稳健。")
【练习2】 A → 均值/中位数/样本标准差: 6.2 6.0 0.84 B → 均值/中位数/样本标准差: 18.8 6.0 28.63 解释:加入极端值后,B 的“均值”被大幅拉高,但“中位数”变化小 → 中位数更稳健。
# 练习3 参考答案(缺失值)
import numpy as np
import pandas as pd
data_with_nan = [60, 75, None, 90, 85]
# Pandas:None 会自动当作缺失值 NaN,默认会跳过(skipna=True)
s = pd.Series(data_with_nan)
print("【练习3 - Pandas】")
print("均值:", round(s.mean(skipna=True), 2))
print("中位数:", round(s.median(skipna=True), 2))
# NumPy:需要把 None 显式替换为 np.nan,并使用 nan 系列函数
arr = np.array([np.nan if v is None else v for v in data_with_nan], dtype=float)
print("\n【练习3 - NumPy】")
print("均值(np.nanmean):", round(np.nanmean(arr), 2))
print("中位数(忽略nan的简便做法:用 pandas 或自己筛掉 nan):", np.nanmedian(arr))
【练习3 - Pandas】 均值: 77.5 中位数: 80.0 【练习3 - NumPy】 均值(np.nanmean): 77.5 中位数(忽略nan的简便做法:用 pandas 或自己筛掉 nan): 80.0
np.std 默认总体,Series.std 默认样本)。研究报告里通常用样本标准差。 下一步可延伸:分位数/四分位距(IQR)、箱线图、组别比较(t 检验 / 非参检验)等。