第11章 数据分析与统计方法(入门)¶

主题:11.1 描述性统计(均值 / 中位数 / 标准差)

“数据是海,分析是舟”。本章用人文社科友好的语言与例子,带你用 Python 完成最常见的描述性统计。
目标:能看懂指标含义、会用 numpy 与 pandas 计算,并能避开常见坑。

学习目标¶

  • 理解 均值(Mean)、中位数(Median)、标准差(Standard Deviation) 的含义与用途。
  • 掌握用 NumPy 与 Pandas 计算这些指标的基本语法。
  • 能在小型社会科学数据中正确解释这些指标。
  • 避开常见错误(如样本/总体标准差、缺失值 NaN、极端值影响等)。

11.1.1 语法要点(先记住这些就够了)¶

1) 三个核心指标的直觉¶

  • 均值:把所有值“抹平”后的共同水平(对极端值很敏感)。
  • 中位数:把数据从小到大排好,处在正中间的那个值(对极端值不敏感,更稳健)。
  • 标准差:衡量“波动程度”。标准差小 → 更集中;标准差大 → 更分散。

2) NumPy 与 Pandas 的常用函数¶

  • NumPy:np.mean(x), np.median(x), np.std(x, ddof=0)
    • ddof=0(默认)是总体标准差;如需样本标准差,用 np.std(x, ddof=1)。
  • Pandas(Series/DataFrame):s.mean(), s.median(), s.std(ddof=1)
    • Pandas 的 std() 默认 ddof=1,即样本标准差(和 NumPy 默认不一样)。

3) 四舍五入与打印¶

  • round(value, 2) 保留 2 位小数;或用 print(f"{value:.2f}")。

4) 缺失值与极端值¶

  • 缺失值(NaN)会让计算结果变成 NaN。要先清理或用 skipna=True(Pandas)。
  • 极端值会“拉动”均值,但对中位数影响有限。实际研究中要结合箱线图/分位数等方法一起看。

11.1.2 示范(用最小例子跑通)¶

我们用一组小数据:[85, 90, 78, 92, 88]。

In [1]:
# 示范:使用 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
In [2]:
# 示范:使用 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

11.1.3 举例(从研究问题出发)¶

例1:偶数个数据时的中位数¶

当数据个数是偶数时,中位数 = 中间两个数的平均数。
例:[60, 80, 85, 90, 100, 110] 的中位数是 (85 + 90) / 2 = 87.5。

In [3]:
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

例2:极端值如何影响均值 vs. 中位数?¶

在社会经济数据中,经常会出现“少量特别高/低”的极端值。我们比较:

  • A 组:收入(千元)[5, 6, 6, 7, 7]
  • B 组:收入(千元)[5, 6, 6, 7, 70](加入一个极高值 70)
In [4]:
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)。
在不均衡分布(如收入、粉丝量)中,用中位数更能反映“典型水平”。

11.1.4 注意事项(常见坑与小贴士)¶

  1. 样本 vs. 总体标准差:
    • 学术研究中最常用的是样本标准差(ddof=1)。NumPy np.std 默认 ddof=0,要自己改;Pandas 默认 ddof=1。
  2. 缺失值 NaN:
    • Pandas:s.mean(skipna=True);NumPy:用 np.nanmean 等函数处理含 np.nan 的数组。
  3. 数据类型:
    • 确保数据是数值型(int/float)。字符串会导致计算报错或被忽略。
  4. 四舍五入:
    • 论文或报告中请统一保留小数位(如 2 位),保证可读性与一致性。
  5. 解释要贴近问题:
    • 仅有数值不够,报告时要用自然语言说明“这代表什么”,例如:
      • “平均分 86.6,标准差 5.1,说明大多数同学的成绩集中在 86.6±5.1 的范围内。”

11.1.5 练习(建议独立完成,再看答案)¶

练习1:期末成绩(基础)¶

数据:[85, 90, 78, 92, 88]
任务:用 NumPy 和 Pandas 分别计算 均值 / 中位数 / 样本标准差(ddof=1),并保留 2 位小数。

练习2:收入样本(极端值的影响)¶

数据A:[5, 6, 6, 7, 7],数据B:[5, 6, 6, 7, 70]
任务:分别计算均值/中位数/样本标准差,比较差异,并用 1–2 句话解释:哪一个指标更稳健?为什么?

练习3:含缺失值的数据¶

数据:[60, 75, None, 90, 85](其中 None 表示缺失)
任务:用 Pandas 计算均值与中位数,跳过缺失值;再尝试用 NumPy 处理这组数据(提示:np.nan 与 np.nanmean)。

In [5]:
# === 在此动手做题(你可以多建几个单元格)===

# 练习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 处理

11.1.6 参考答案(对照自检)¶

建议先独立完成练习再看答案。

In [6]:
# 练习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
In [7]:
# 练习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 的“均值”被大幅拉高,但“中位数”变化小 → 中位数更稳健。
In [8]:
# 练习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

11.1 小结¶

  • 均值反映整体水平,对极端值敏感;中位数更稳健;标准差描述波动性。
  • NumPy 与 Pandas 的默认标准差不同(np.std 默认总体,Series.std 默认样本)。研究报告里通常用样本标准差。
  • 真实世界数据常有缺失与极端值,计算前要检查与清洗,解释时要结合情境。

下一步可延伸:分位数/四分位距(IQR)、箱线图、组别比较(t 检验 / 非参检验)等。