数据科学入门课程第 4 课:用 Python 掌握概率、统计推断与假设检验基础
【免费下载链接】Data-Science-For-Beginners10 Weeks, 20 Lessons, Data Science for All!项目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners
概率论与数理统计是数据科学的两大数学支柱。即使不掌握高深数学也能处理数据,但理解随机变量、概率分布、均值与方差、置信区间、假设检验与相关性这些基础概念,能让你在面对真实数据时做出严谨的推断,而不是凭直觉下结论。本课(Data-Science-For-Beginners 课程的第 4 课《统计与概率入门》,配套孟加拉语翻译位于 translations/bn/1-Introduction/04-stats-and-probability/README.md,英文原版位于 1-Introduction/04-stats-and-probability/README.md)以棒球运动员的真实数据为案例,带你从随机变量出发,一路走到用 SciPy 完成 t 检验与相关性分析,最终有能力独立完成"小型糖尿病研究"实战作业。
概率与随机变量:一切推断的起点
概率(Probability)是介于 0 到 1 之间的数字,用来表示某个**事件(event)**发生的可能性大小。它的定义是"导致该事件的有利结果数除以总结果数",前提是所有结果等可能发生。例如掷一枚骰子,得到偶数的概率是 3/6 = 0.5。
讨论事件时我们会使用随机变量(random variable)。例如"掷骰子得到的点数"这个随机变量取值从 1 到 6,这组取值构成的集合称为样本空间(sample space)。我们可以谈论随机变量取某个具体值的概率,比如 P(X=3)=1/6。
随机变量分为两类:
- 离散随机变量:样本空间可数,即存在可枚举的独立取值。掷骰子结果就是典型例子。
- 连续随机变量:样本空间是一段实数区间甚至整个实数集 ℝ。公交车到达时间就是很好的例子——对任何一个精确的时刻 t,公交车"恰好在该时刻到达"的概率都是 0!
现在你知道了:概率为 0 的事件不但存在,而且经常发生——至少每次公交车到站时都发生了一次!
概率分布:描述随机变量取值的规律
对于离散随机变量,可以用函数 P(X) 描述每个事件的概率:对样本空间S中的每个值s,它给出一个 0 到 1 之间的数,且所有 P(X=s) 之和为 1。最著名的离散分布是均匀分布(uniform distribution):样本空间含 N 个元素,每个元素概率相等,均为 1/N。
连续变量的概率分布更难描述。我们只能谈论变量落入某个取值区间的概率,例如 P(t₁≤X<t₂)。此时概率分布由概率密度函数(probability density function)p(x) 描述:
均匀分布的连续版本称为连续均匀分布,定义在有限区间上:X 落入长度为 l 的区间的概率与 l 成正比,最高可达 1。另一个极为重要的分布是正态分布(normal distribution),下文将详细展开。
均值、方差与标准差:刻画数据中心与离散程度
假设我们从随机变量 X 中抽取 n 个样本:x₁, x₂, ..., xₙ。序列的均值(mean,又称算术平均)传统上定义为 (x₁+x₂+...+xₙ)/n。当样本量趋于无穷(n→∞)时,我们得到分布的均值,也称期望(expectation),记为E(x)。
可以证明:对于任意离散分布,若取值为 {x₁, x₂, ..., xₙ}、对应概率为 p₁, p₂, ..., pₙ,则期望 E(X) = x₁p₁ + x₂p₂ + ... + xₙpₙ。
为刻画数值的离散程度,可以计算方差(variance)σ² = ∑(xᵢ - μ)²/n,其中 μ 是序列均值。σ 称为标准差(standard deviation),σ² 称为方差。
在配套的 教学 Notebook 中,这些概念被直接落地为代码:先用random.randint生成 30 个均匀随机样本,再用np.mean与np.var计算均值和方差;随后加载真实棒球数据SOCR_MLB.tsv,对身高列计算均值、方差与标准差:
import numpy as np import pandas as pd df = pd.read_csv("data/SOCR_MLB.tsv", sep='\t', header=None, names=['Name','Team','Role','Weight','Height','Age']) mean = df['Height'].mean() var = df['Height'].var() std = df['Height'].std() print(f"Mean = {mean}\nVariance = {var}\nStandard Deviation = {std}")注意这里的数据文件位于仓库根目录下的 data/SOCR_MLB.tsv,字段依次为球员姓名、球队、场上角色、体重(英寸)、身高(磅)与年龄,与names参数一一对应。
众数、中位数与四分位数:抗离群值的"典型值"
有时均值并不能很好地代表数据的"典型"水平。比如存在少数完全超出范围的极端值时,它们会拉偏均值。更好的指标是中位数(median):一半数据点低于它,另一半高于它。
为了理解数据分布,引入四分位数(quartile):
- 第一四分位数 Q1:25% 的数据低于它;
- 第三四分位数 Q3:75% 的数据低于它。
中位数与四分位数之间的关系可以用**箱线图(box plot)**直观呈现:
箱线图还定义了两个衍生量:四分位距(inter-quartile range)IQR = Q3 - Q1,以及所谓的离群值(outliers)——落在边界 [Q1-1.5×IQR, Q3+1.5×IQR] 之外的值。
当有限分布的可能取值很少时,出现频率最高的值称为众数(mode),常用于颜色等类别型数据。设想两组人——一组强烈偏爱红色,另一组偏爱蓝色。若把颜色编码为数字,偏好颜色的均值会落在橙绿光谱的某个中间位置,完全无法反映任何一组的真实偏好;而众数则要么是红色要么是蓝色——如果两方人数相同,众数会同时是两个颜色,此时称样本为多模态(multimodal)。
Notebook 中同样给出了实操代码:用plt.boxplot绘制身高的水平箱线图(showmeans=True会同时标出均值),再用df.boxplot(column='Height', by='Role')按场上角色分组绘制,直观对比不同位置球员的身高分布。
真实世界数据:把棒球运动员当作随机样本
分析真实数据时,它们严格来说并不是随机变量——我们并没有做结果未知的实验。以棒球队球员的身体数据(身高、体重、年龄)为例,这些数字并非完全随机,但我们仍可套用同样的数学工具:把一组人的体重视为从某个随机变量中抽取的样本序列。下面这组数据来自美国职棒大联盟(MLB),取自 SOCR 的 MLB 身高体重数据集(为方便展示,仅列出前 20 个值):
[180.0, 215.0, 210.0, 210.0, 188.0, 176.0, 209.0, 200.0, 231.0, 180.0, 188.0, 180.0, 185.0, 160.0, 180.0, 185.0, 197.0, 189.0, 185.0, 219.0]注意:处理该数据集的完整示例见 配套 Notebook,课程中还有若干挑战,你可以在其中补充代码完成。若还不熟悉在 Jupyter Notebook 中运行代码,可以稍后随课程第 7 课(07-python)系统学习。
这份数据的均值、中位数与四分位数可以用箱线图呈现:
由于数据包含不同球员**角色(role)**信息,我们还可以按角色绘制箱线图——这能直观看出参数取值如何随角色变化。这次我们考察身高:
这幅图提示:平均而言,一垒手的身高高出二垒手。本课稍后我们将学习如何用更正式的方式检验这一假设,并证明数据在统计上显著。
处理真实数据时,我们假定所有数据点都是从某个概率分布中抽取的样本。这一假设使我们能够应用机器学习技术、构建可用的预测模型。
为观察数据分布,可以绘制直方图(histogram):X 轴是若干体重区间(称为箱/bins),纵轴表示随机变量样本落入该区间的次数:
从直方图可以看出,所有值都围绕某个平均体重居中分布,离均值越远,出现该体重的人越少。也就是说,棒球球员的体重极不可能与平均体重相差悬殊;方差的大小则表明体重偏离均值的可能程度。
如果取棒球联盟之外人群的体重,分布很可能不同——但形状保持不变,只是均值和方差会改变。因此,若用棒球球员训练模型再套用到大学生身上,结果很可能是错的,因为底层分布不同。
正态分布:用 NumPy 生成符合现实的样本
上面体重数据的分布非常典型,现实中大量测量值遵循同类型分布,只是均值与方差不同,这就是正态分布——统计学中举足轻重的角色。
利用正态分布,我们可以正确生成潜在棒球球员的随机体重:只要知道平均体重mean和标准差std,就能这样生成 1000 个体重样本:
samples = np.random.normal(mean, std, 1000)绘制生成样本的直方图,会得到与上图几乎相同的形态;若继续增大样本数与箱数,得到的直方图将越来越接近理想的正态分布钟形曲线:
均值为 0、标准差为 1 的正态分布
Notebook 还演示了一个经典反例:真实世界大部分数据服从正态分布,因此不应使用均匀随机数生成器生成样本数据——np.random.rand生成的均匀分布样本(如np.random.rand(1000)*2*std+mean-std)画出的直方图形态与真实体重分布明显不符。
置信区间:用样本估计总体均值
讨论棒球球员体重时,我们假定存在某个随机变量 W,对应全体棒球球员体重的理想概率分布(即总体/population);我们手上的体重序列是全体球员的一个子集,称为样本(sample)。一个有意思的问题是:能否知道 W 的分布参数——即总体的均值与方差?
最直接的回答是计算样本的均值和方差。但随机样本未必能准确代表完整总体,因此引入**置信区间(confidence interval)**的概念。
置信区间是依据样本对总体真实均值做出的估计,它以某个概率(即置信水平/level of confidence)成立。
假设从分布中抽取样本 X₁, ..., Xₙ。每次抽样得到的均值 μ 都不同,因此 μ 本身可视为随机变量。置信水平为 p 的置信区间是一对值 (Lₚ, Rₚ),满足P(Lₚ ≤ μ ≤ Rₚ) = p,即测得的均值落入该区间的概率等于 p。
置信区间如何计算超出了本入门课的范围,简言之:我们定义"样本均值相对于总体真实均值"的分布,称为学生分布(Student distribution)。
有趣的事实:学生分布以数学家威廉·西利·戈塞特(William Sealy Gosset)命名,他以笔名"Student"发表论文。他在吉尼斯啤酒厂工作,据其中一种说法,他的雇主不希望公众知道他们在用统计检验判断原材料质量。
若要以置信度 p 估计总体均值 μ,需要取学生分布的(1-p)/2 分位数A——可以从统计表中查,或用统计软件(Python、R 等)内置函数计算。则 μ 的区间为 X ± A·D/√n,其中 X 是样本均值,D 是标准差。
注:这里略过了与**自由度(degrees of freedom)**相关的重要概念,更深入的理解可参考完整统计学教材。
配套 Notebook 中封装了一个计算均值置信区间的函数,内部使用scipy.stats.sem计算标准误、用scipy.stats.t.ppf查学生分布分位数:
import scipy.stats def mean_confidence_interval(data, confidence=0.95): a = 1.0 * np.array(data) n = len(a) m, se = np.mean(a), scipy.stats.sem(a) h = se * scipy.stats.t.ppf((1 + confidence) / 2., n - 1) return m, h for p in [0.85, 0.9, 0.95]: m, h = mean_confidence_interval(df['Weight'].ffill(), p) print(f"p={p:.2f}, mean = {m:.2f} ± {h:.2f}")对棒球球员体重计算置信区间的结果如下:
| p | 体重均值 |
|---|---|
| 0.85 | 201.73±0.94 |
| 0.90 | 201.73±1.08 |
| 0.95 | 201.73±1.28 |
注意到:置信概率越高,置信区间越宽。
假设检验:用 t 检验证明"一垒手比二垒手高"
棒球球员数据集中包含不同场上角色,汇总如下表(如何计算这张表见 配套 Notebook):
| 角色 | 身高 | 体重 | 人数 |
|---|---|---|---|
| Catcher | 72.723684 | 204.328947 | 76 |
| Designated_Hitter | 74.222222 | 220.888889 | 18 |
| First_Baseman | 74.000000 | 213.109091 | 55 |
| Outfielder | 73.010309 | 199.113402 | 194 |
| Relief_Pitcher | 74.374603 | 203.517460 | 315 |
| Second_Baseman | 71.362069 | 184.344828 | 58 |
| Shortstop | 71.903846 | 182.923077 | 52 |
| Starting_Pitcher | 74.719457 | 205.163636 | 221 |
| Third_Baseman | 73.044444 | 200.955556 | 45 |
可以看到一垒手的平均身高高于二垒手,于是我们可能忍不住得出结论:一垒手比二垒手高。
这句话之所以叫假设(hypothesis),是因为我们并不知道它是否真的成立。
然而下这个结论并不总是显而易见的:每个均值都关联一个置信区间,二者差异可能只是统计误差,因此需要更正式的方法来检验假设。先分别计算一垒手与二垒手身高的置信区间:
| 置信水平 | 一垒手 | 二垒手 |
|---|---|---|
| 0.85 | 73.62..74.38 | 71.04..71.69 |
| 0.90 | 73.56..74.44 | 70.99..71.73 |
| 0.95 | 73.47..74.53 | 70.92..71.81 |
可以看到,任何置信水平下两个区间都不重叠,这证明了一垒手高于二垒手的假设。
更形式化地看,我们实际要解决的是两个概率分布是否相同(或至少参数相同)的问题。分布不同需要选用不同检验;若已知分布为正态,可以应用学生 t 检验(Student t-test)。
在学生 t 检验中,我们计算所谓的t 值(t-value),它在考虑方差的前提下反映均值之间的差异。可以证明 t 值服从学生分布,这使我们能为给定置信水平 p 获取阈值(可计算或查数值表),再比较 t 值与阈值来接受或拒绝假设。
在 Python 中,可以用SciPy包——它提供ttest_ind函数(此外还有大量实用统计函数),自动计算 t 值,并反向查表得到置信度对应的 p 值,直接看 p 值即可下结论。例如比较一垒手与指定打者的身高:
from scipy.stats import ttest_ind tval, pval = ttest_ind(df.loc[df['Role']=='First_Baseman',['Height']], df.loc[df['Role']=='Designated_Hitter',['Height']], equal_var=False) print(f"T-value = {tval[0]:.2f}\nP-value: {pval[0]}")T-value = 7.65 P-value: 9.137321189738925e-12在本例中 p 值极低,意味着一垒手更高的证据非常强。(ttest_ind返回的两个值中:p 值可视为两个分布均值相同的概率;t 值是归一化均值差的中间量,需要与给定置信水平的阈值比较。)
除均值比较外,假设检验还能回答更多问题,例如:
- 证明某个样本服从某种分布(本例中我们假设身高正态分布,但这需要正式统计检验);
- 证明样本均值等于某个预设值;
- 比较多组样本的均值(例如不同年龄段的幸福水平差异)。
大数定律与中心极限定理
正态分布如此重要的原因之一是中心极限定理(central limit theorem):假设我们有 N 个独立值 X₁, ..., Xₙ 的大样本,取自均值 μ、方差 σ² 的任意分布。那么当 N 足够大(即 N→∞)时,ΣᵢXᵢ 的均值将服从正态分布,均值 μ、方差 σ²/N。
中心极限定理的另一种解读是:无论分布如何,当你计算任意随机变量值之和的均值时,最终都会得到正态分布。
由中心极限定理还可推出:当 N→∞ 时,样本均值等于 μ 的概率趋近于 1,这就是大数定律(law of large numbers)。
Notebook 用一段巧妙代码印证了这一定理:Python 的伪随机生成器只给出均匀分布,若想构造正态分布生成器,可直接利用中心极限定理——对均匀样本取均值即可得到近似正态的随机值:
def normal_random(sample_size=100): sample = [random.uniform(0, 1) for _ in range(sample_size)] return sum(sample) / sample_size sample = [normal_random() for _ in range(100)] plt.hist(sample) plt.show()协方差与相关性:寻找变量间的关系
数据科学的一项重要工作是在数据中寻找关系。当两个序列在相同时刻表现出相似行为——同时上升/下降,或一个上升而另一个下降——我们就说它们相关(correlate),即两个序列之间似乎存在某种联系。
相关性并不必然意味着两个序列之间存在因果关系:有时两个变量都取决于某个外部原因,有时两个序列相关纯属巧合。但强的数学相关性仍是两个变量存在某种关联的良好信号。
从数学上看,刻画两个随机变量关系的主要概念是协方差(covariance):Cov(X,Y) =E[(X-E(X))(Y-E(Y))]。我们计算两个变量相对于各自均值的偏差,再求这些偏差的乘积:若两个变量同步偏离,乘积恒为正,累加得到正协方差;若两者偏离不同步(一个低于均值时另一个高于均值),乘积恒为负,累加得到负协方差;若偏差相互独立,则大致累加为零。
协方差的绝对值并不能说明相关性强弱,因为它取决于实际数值的量级。为将其归一化,可以把协方差除以两个变量的标准差,得到相关性(correlation)。它的优点是始终落在 [-1, 1]:1 表示强正相关,-1 表示强负相关,0 表示完全无关(变量独立)。
示例:用上面的数据集计算棒球球员体重与身高之间的相关性:
print(np.corrcoef(weights, heights))结果得到一个相关矩阵(correlation matrix):
array([[1. , 0.52959196], [0.52959196, 1. ]])相关矩阵 C 可对任意数量的输入序列 S₁, ..., Sₙ 计算:Cᵢⱼ 是 Sᵢ 与 Sⱼ 的相关性,对角线元素恒为 1(即 Sᵢ 的自相关)。
本例中 0.53 表明人的体重与身高之间存在一定相关性。还可以绘制散点图直观查看:
Notebook 还通过一个"邪恶棒球公司"的玩具示例深化理解:该公司按身高发薪——底薪 1000 美元,再按身高加 0~100 美元。线性公式下np.corrcoef接近 1;把公式换成np.sin引入非线性后相关性略降但依然较高;再叠加 ±10 的随机噪声后相关性进一步下降。最后演示了真实的体重-身高相关性:由于序列中存在nan缺失值,直接计算会得到nan,必须先调用ffill()/fillna补齐数据——这直观说明了数据准备与清洗的重要性。关于数据清洗与准备的完整方法论,可进一步学习课程第 8 课(08-data-preparation)。
实战挑战:验证更多假设
利用 Notebook 中的示例代码,尝试检验以下假设:
- 一垒手比二垒手年龄更大;
- 一垒手比三垒手更高;
- 游击手比二垒手更高。
检验思路与课程完全一致:先按角色分组查看各列的均值,再分别计算两组的置信区间看是否重叠,最后用scipy.stats.ttest_ind计算 t 值与 p 值作出统计推断。
课程作业:小型糖尿病研究
本课作业(assignment.md,孟加拉语版见 translations/bn/1-Introduction/04-stats-and-probability/assignment.md)要求你独立完成一次完整的数据统计实践:使用 data/diabetes.tsv 中的糖尿病病人小数据集(取自 NCSU 公开数据集),并在 assignment.ipynb 中完成任务。数据列说明:
- AGE:年龄;SEX:性别;
- BMI:身体质量指数;BP:平均血压;
- S1~S6:六项血液生化指标;
- Y:一年内疾病进展的定量度量(目标变量)。
具体任务清单:
- 计算所有变量的均值与方差;
- 按性别分组,为 BMI、BP 和 Y 绘制箱线图;
- 分析 AGE、SEX、BMI 和 Y 的分布形态;
- 检验各变量与疾病进展 Y 之间的相关性(提示:相关矩阵能给出最有用的依赖关系信息);
- 检验"糖尿病进展程度在男性和女性之间存在差异"这一假设。
Notebook 骨架已给出数据加载代码pd.read_csv("data/diabetes.tsv", sep='\t')与各任务标题占位,评分标准(Rubric)要求所有任务完成、绘图并给出结论性解释:全部完成且图文并茂为"优秀",仅完成均值/方差与基础绘图而未得出结论则评为"需改进"。
小结
本课为你建立了统计与概率的完整入门框架,内容包括:
- 数据的基本统计量:均值、方差、众数与四分位数;
- 随机变量的各类分布,尤其是正态分布;
- 如何发现不同属性之间的相关性;
- 如何用严谨的数学与统计工具证明假设;
- 如何基于数据样本计算随机变量的置信区间。
虽然这远非概率与统计的全部主题,但足以支撑你在这门课程后续(数据可视化、数据生命周期、机器学习)中顺利前行。若想深入理论,可继续阅读 NYU Carlos Fernandez-Granda 的《Probability and Statistics for Data Science》讲义、Peter 与 Andrew Bruce 的《Practical Statistics for Data Scientists》、James D. Miller 的《Statistics for Data Science》等经典资料,本课还提供了课前/课后测验与配套 Notebook 用于自测。
【免费下载链接】Data-Science-For-Beginners10 Weeks, 20 Lessons, Data Science for All!项目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考