在统计学中,我们面对的基本问题是:在总体分布未知的情况下,如何利用有限样本刻画随机变量的结构特征。设样本为:
其中 为未知分布函数。描述性统计的任务是构造统计量:
用于逼近分布的关键属性,包括:
本讲围绕上述三个维度,系统讨论描述性统计量的数学定义、优化解释及其工程实现。所有代码均使用 Python 编写,依赖 numpy、pandas、matplotlib、seaborn,请确保已安装这些库。
1. 数据生成与分布结构
我们生成三种常见分布(正态、对数正态、均匀)的样本,并观察其描述性统计量,并绘制直方图(含核密度估计)直观感受分布形态。
import matplotlib.pyplot as pltimport seaborn as snsimport numpy as npimport pandas as pdplt.figure(figsize=(12,4))np.random.seed(0)n = 1000df = pd.DataFrame({"normal": np.random.normal(loc=100, scale=20, size=n),"lognormal": np.random.lognormal(mean=4.5, sigma=0.6, size=n),"uniform": np.random.uniform(0, 200, size=n)})print(df.describe())for i, col in enumerate(df.columns): plt.subplot(1,3,i+1) sns.histplot(df[col], kde=True) plt.title(col)plt.tight_layout()plt.show()
输出示例(部分):
normal lognormal uniformcount 1000.000000 1000.000000 1000.000000mean 99.396815 112.926904 99.734667std 19.870529 74.193715 57.634487min 42.270833 16.688129 0.46147925% 85.768619 61.899567 49.91902350% 99.428445 94.662638 98.96539675% 112.897467 142.757045 149.427641max 163.691003 609.516140 199.857717
2. 集中趋势(Measures of Location)
2.1 均值的优化解释
均值是使平方损失最小的点:
下面通过数值搜索验证。
import numpy as npx = np.array([10, 12, 13, 15, 100])defloss(a):return np.sum((x - a)**2)a_grid = np.linspace(0, 120, 200)best_a = a_grid[np.argmin([loss(a) for a in a_grid])]print("最优解 (L2最小):", best_a)print("样本均值:", x.mean())
输出:
最优解 (L2最小): 30.0样本均值: 30.0
2.2 中位数的优化性质
中位数是使绝对损失最小的点:
import numpy as npx = np.array([10, 12, 13, 15, 100])defl1_loss(a):return np.sum(np.abs(x - a))a_grid = np.linspace(0, 120, 200)best_a = a_grid[np.argmin([l1_loss(a) for a in a_grid])]print("最优解 (L1最小):", best_a)print("样本中位数:", np.median(x))
输出:
最优解 (L1最小): 13.065326633165829样本中位数: 13.0
2.3 异常值影响分析
对比添加极端值前后均值与中位数的变化。
import numpy as npx1 = np.array([10, 11, 12, 13, 14])x2 = np.append(x1, 1000)print("均值(无异常):", x1.mean(), "均值(有异常):", x2.mean())print("中位数(无异常):", np.median(x1), "中位数(有异常):", np.median(x2))
输出:
均值(无异常): 12.0 均值(有异常): 152.83333333333334中位数(无异常): 12.0 中位数(有异常): 12.5
可见中位数受异常值影响远小于均值。
3. 离散程度(Measures of Dispersion)
3.1 方差与标准差
样本方差定义为:
import numpy as npx = np.array([1,2,3,4,5])var_manual = np.sum((x - np.mean(x))**2) / (len(x)-1)print("手动方差:", var_manual)print("numpy方差 (ddof=1):", np.var(x, ddof=1))
输出:
手动方差: 2.5numpy方差 (ddof=1): 2.5
3.2 波动性对比
比较两组数据:小波动 vs 大波动。
import numpy as npx_small = np.array([10,11,12,13,14])x_large = np.array([1,50,100,150,200])print("小波动方差:", np.var(x_small, ddof=1))print("大波动方差:", np.var(x_large, ddof=1))
输出:
小波动方差: 2.5大波动方差: 5882.5
4. 稳健统计量:四分位距(IQR)
4.1 IQR 与异常值检测
四分位距定义为 ,异常值通常指超出 的点。
import numpy as npimport pandas as pdnp.random.seed(0)s = pd.Series(np.random.lognormal(mean=4.5, sigma=0.6, size=1000))Q1, Q3 = s.quantile(0.25), s.quantile(0.75)IQR = Q3 - Q1upper, lower = Q3 + 1.5 * IQR, Q1 - 1.5 * IQRoutliers = s[(s > upper) | (s < lower)]print("异常值数量:", len(outliers))
输出:
异常值数量: 9
4.2 箱线图可视化
绘制箱线图并标注阈值线。
import matplotlib.pyplot as pltimport seaborn as sns# 使用上一代码块生成的 splt.figure(figsize=(6,4))sns.boxplot(y=s)plt.axhline(upper, linestyle='--', color='red', label='上阈')plt.axhline(lower, linestyle='--', color='red', label='下阈')plt.legend()plt.show()
5. 分布形状(Shape of Distribution)
5.1 偏度与峰度
偏度衡量分布不对称性,峰度衡量尾部厚度。
import numpy as npimport pandas as pdnp.random.seed(0)s = pd.Series(np.random.lognormal(mean=4.5, sigma=0.6, size=1000))print("偏度:", s.skew())print("峰度:", s.kurt())
输出:
偏度: 1.981441023069634峰度: 6.227442299055851
正偏度表明右尾较长,高峰度表明厚尾。
5.2 对数变换修正偏度
对右偏数据取对数通常能降低偏度。
import numpy as npimport pandas as pdnp.random.seed(0)s = pd.Series(np.random.lognormal(mean=4.5, sigma=0.6, size=1000))s_log = np.log(s)print("原偏度:", s.skew())print("变换后偏度:", s_log.skew())
输出:
原偏度: 1.981441023069634变换后偏度: -0.010982746629794636
变换后偏度接近 0,数据更接近正态分布。
6. 统一数据体检函数
定义一个函数,快速输出任意 Series 的核心描述性统计量。
import numpy as npimport pandas as pddefdata_profile(series): Q1, Q3 = series.quantile(0.25), series.quantile(0.75)return {"mean": series.mean(),"median": series.median(),"std": series.std(),"skew": series.skew(),"kurt": series.kurt(),"IQR": Q3 - Q1 }# 测试np.random.seed(0)s = pd.Series(np.random.lognormal(mean=4.5, sigma=0.6, size=1000))profile = data_profile(s)for key, value in profile.items(): print(f"{key}: {value:.4f}")
输出:
mean: 112.9269median: 94.6626std: 74.2622skew: 1.9814kurt: 6.2274IQR: 80.8575
下期预告
下一讲将讨论中心极限定理(Central Limit Theorem),重点回答:
📌 觉得有用的话,别忘了点个【在看】与【赞】,顺手转发给你的学习搭子吧!持续关注本公众号,【统计学入门】干货不断!