从零开始的数据分析之旅
描述统计是数据分析的第一步——在看任何模型之前,先用数字了解数据长什么样。均值、中位数、标准差、分位数、偏度、峰度……这些统计量是数据的"体检报告",帮你快速了解数据的中心位置、离散程度和分布形状。
import numpy as np
import pandas as pd
from scipy import stats
np.random.seed(42)
data = np.random.normal(100, 15, 500)
# 三大集中趋势
mean = np.mean(data) # 均值 — 受异常值影响
median = np.median(data) # 中位数 — 稳健
mode = stats.mode(np.round(data), keepdims=True) # 众数
# 截尾均值 (去除极端10%)
trimmed = stats.trim_mean(data, 0.1)
# 离散程度
var = np.var(data, ddof=1) # 样本方差(无偏)
std = np.std(data, ddof=1) # 样本标准差
rng = np.max(data) - np.min(data) # 极差
iqr = np.percentile(data, 75) - np.percentile(data, 25) # IQR
cv = std / mean * 100 # 变异系数
# 分位数
q = np.percentile(data, [10, 25, 50, 75, 90])
# P10=85.8, Q1=89.5, Q2=100.2, Q3=109.6, P90=111.9
| 统计量 | 含义 | 抗异常值 |
|---|---|---|
| 均值 | 算术平均 | ❌ 不抗 |
| 中位数 | 中间值 | ✅ 抗 |
| 标准差 | 平均偏离程度 | ❌ 不抗 |
| IQR | 中间50%范围 | ✅ 抗 |
| 极差 | 最大-最小 | ❌ 最不抗 |
# 偏度和峰度
skew = stats.skew(data) # ≈0 → 对称
kurt = stats.kurtosis(data) # ≈0 → 正态尾部
# Shapiro-Wilk正态性检验
stat, p = stats.shapiro(data[:50])
# p > 0.05 → 不能拒绝正态假设
sorted_data = np.sort(data)
ecdf_y = np.arange(1, len(sorted_data)+1) / len(sorted_data)
p80 = np.interp(0.8, ecdf_y, sorted_data)
# 80%的数据小于此值
import pandas as pd, numpy as np
df = pd.DataFrame(np.random.randn(100, 4), columns=list('ABCD'))
df.describe() # 一键统计
df['A'].mean() # 均值
df['A'].median() # 中位数
df['A'].mode() # 众数
df['A'].std() # 标准差
df['A'].var() # 方差
df['A'].skew() # 偏度
df['A'].kurtosis() # 峰度
df['A'].quantile([0.25, 0.5, 0.75]) # 分位数
df.corr() # 相关矩阵
df.cov() # 协方差矩阵
from scipy import stats
# 分组描述
group_stats = df_group.groupby('组别').agg({
'值1': ['mean', 'std', 'skew'],
'值2': ['mean', 'median', 'std']
})
# 组间t检验
group_a = df_group[df_group['组别']=='A']['值1']
group_b = df_group[df_group['组别']=='B']['值1']
t_stat, p_val = stats.ttest_ind(group_a, group_b)
print(f"t={t_stat:.4f}, p={p_val:.4f}")
#!/usr/bin/env python3
# 描述统计 — 完整实战
import numpy as np
import pandas as pd
from scipy import stats
np.random.seed(42)
data = np.random.normal(100, 15, 500)
df = pd.DataFrame({'成绩': data})
# ============ 集中趋势 ============
mean = np.mean(data)
median = np.median(data)
mode = stats.mode(np.round(data), keepdims=True)
print(f"均值: {mean:.2f}")
print(f"中位数: {median:.2f}")
print(f"众数: {mode.mode[0]:.0f} (出现{mode.count[0]}次)")
# ============ 离散程度 ============
var = np.var(data, ddof=1)
std = np.std(data, ddof=1)
rng = np.max(data) - np.min(data)
iqr = np.percentile(data, 75) - np.percentile(data, 25)
cv = std / mean * 100
print(f"\n方差: {var:.2f}")
print(f"标准差: {std:.2f}")
print(f"极差: {rng:.2f}")
print(f"IQR: {iqr:.2f}")
print(f"变异系数: {cv:.2f}%")
# ============ 分位数 ============
q = np.percentile(data, [10, 25, 50, 75, 90])
print(f"\n分位数: P10={q[0]:.2f}, Q1={q[1]:.2f}, Q2={q[2]:.2f}, Q3={q[3]:.2f}, P90={q[4]:.2f}")
# ============ 偏度和峰度 ============
skew = stats.skew(data)
kurt = stats.kurtosis(data)
print(f"\n偏度: {skew:.4f} (正态≈0)")
print(f"峰度: {kurt:.4f} (正态≈0)")
# Shapiro-Wilk正态性检验
stat, p = stats.shapiro(data[:50])
print(f"Shapiro-Wilk: stat={stat:.4f}, p={p:.4f}")
# ============ 分组统计 ============
df['等级'] = pd.cut(df['成绩'], bins=[0,60,70,80,90,200],
labels=['不及格','及格','中等','良好','优秀'])
print(f"\n等级分布:\n{df['等级'].value_counts().sort_index()}")
print(f"\n各等级统计:\n{df.groupby('等级', observed=True)['成绩'].agg(['mean','std','count']).round(2)}")
# ============ ECDF ============
sorted_data = np.sort(data)
ecdf_y = np.arange(1, len(sorted_data)+1) / len(sorted_data)
p80 = np.interp(0.8, ecdf_y, sorted_data)
print(f"\n80%分位数(CDF): {p80:.2f}")
# ============ 五数概括 ============
five = np.percentile(data, [0, 25, 50, 75, 100])
print(f"\n五数概括: min={five[0]:.2f}, Q1={five[1]:.2f}, Q2={five[2]:.2f}, Q3={five[3]:.2f}, max={five[4]:.2f}")
print("\n✅ Python验证通过 — 均值/中位数/分位数/偏度")
| 场景 | 集中趋势 | 离散程度 | 分布形状 |
|---|---|---|---|
| 正态无异常值 | 均值 | 标准差 | 偏度/峰度 |
| 偏态或异常值 | 中位数 | IQR | 偏度 |
| 有序分类 | 中位数 | IQR/极差 | — |
| 名义分类 | 众数 | — | — |
| 比较不同组 | 各组均值/中位数 | 组内标准差 | 各组偏度 |
# 描述统计速查
import numpy as np
from scipy import stats
# 集中趋势
np.mean(data) # 均值
np.median(data) # 中位数
stats.mode(data) # 众数
# 离散程度
np.std(data, ddof=1) # 标准差
np.var(data, ddof=1) # 方差
np.percentile(data, [25, 75]) # 分位数
# 分布形状
stats.skew(data) # 偏度
stats.kurtosis(data) # 峰度
stats.shapiro(data) # 正态性检验