1. 这不是数学课,是机器学习里真正要用到的概率“地基”
你打开任何一本机器学习教材,第一页可能写着“线性回归”,第三页就突然冒出个 $p(x, y)$——联合分布;翻两页又看到 $p(x)$ 和 $p(y)$——边缘分布。没人告诉你为什么非得先啃这个,更没人说清:为什么训练一个图像分类模型时,你调参调得再猛,如果对联合分布和边缘分布的理解还停留在“把Y轴积分掉就是边缘”这种机械记忆层面,那你的模型永远在靠运气泛化。
我带过不少刚转行的学员,他们能熟练写出 PyTorch 的nn.Linear层,却在调试一个异常检测系统时卡死三天:明明训练集上 AUC 0.98,部署后线上误报率飙升到 40%。最后发现,问题出在数据采样逻辑上——训练用的是实验室环境下的联合分布 $p_{\text{lab}}(x, y)$,而线上真实场景的联合分布 $p_{\text{prod}}(x, y)$ 已经发生偏移(covariate shift),但团队只做了 $p(x)$ 的边缘校准,完全忽略了 $y$ 在不同 $x$ 区域下的条件分布变化。这不是代码 bug,是概率直觉的断层。
这篇笔记不讲测度论,不推勒贝格积分,也不堆符号游戏。它只回答三个你在真实项目里每天都会撞上的问题:
- 当你说“这个特征很重要”,你到底是在指 $p(x_i \mid y)$ 高?还是 $p(x_i)$ 的方差大?抑或 $I(X_i; Y)$ 互信息高?三者根本不是一回事;
- 为什么 PCA 降维后模型性能反而下降?因为你在用边缘分布 $p(x_i)$ 的方差做主成分选择,却无视了联合分布 $p(\mathbf{x}, y)$ 中特征与标签的协同结构;
- 为什么 GAN 生成的图片看着“差不多”,但下游任务(比如人脸属性识别)一跑就崩?因为你只匹配了边缘分布 $p_G(x)$ 和 $p_{\text{data}}(x)$,而真实任务依赖的是 $p_G(x \mid y)$ 或 $p_G(y \mid x)$ 的保真度。
标题里写“10mins 入门”,不是说十分钟就能精通,而是指:用十分钟建立一个可立即用于 debug 模型的、带物理意义的概率坐标系。接下来所有内容,都围绕“如何把抽象符号变成你调试模型时脑子里闪过的那句判断”来组织。你会看到二维正态分布的等高线图怎么暴露数据采集漏洞,会亲手用 NumPy 拆解一个真实传感器数据集的联合-边缘关系,还会发现:所谓“一维随机变量”的边缘分布,其实是你每天都在画的直方图——只是你从没意识到,那根柱子的高度,本质是联合分布在一个维度上“压扁”后的密度投影。
关键词“机器学习”“联合分布”“边缘分布”“一维随机变量”“二维随机变量”不是标签,是操作指令——它们对应着你明天早上打开 Jupyter Notebook 时,要检查的三行核心代码、要画的两张关键图表、要质疑的一个数据加载逻辑。现在,我们从最朴素的直觉开始:分布不是函数,是数据世界的地形图;联合分布是三维山峦,边缘分布是你站在山顶垂直向下看的影子。
2. 内容整体设计与思路拆解:为什么必须从二维切入,而非教科书式的一维铺垫?
2.1 教科书陷阱:一维分布教学为何让你越学越迷?
翻开任何概率统计教材,“随机变量”章节几乎千篇一律:先定义一维离散/连续随机变量,讲分布律/概率密度函数,再引入期望、方差……最后才在“多维随机变量”小节里,用轻描淡写的语气说:“将一维推广到二维即可”。这种结构看似循序渐进,实则埋下巨大隐患——它让你误以为联合分布是“多个一维分布的简单拼接”,而边缘分布是“把多余维度删掉”。
我试过让学员用这种思路解释一个真实问题:某智能电表每分钟记录电压 $V$ 和电流 $I$,工程师说“电压波动大所以故障率高”,但数据分析师发现,单独看 $V$ 的边缘分布(直方图),其标准差确实比历史均值高 30%;可当画出 $(V, I)$ 联合分布的热力图时,高电压区域几乎全被低电流覆盖,而高电流只出现在中等电压区间。这意味着:所谓“电压波动大”,实际是系统在低负载时反复启停造成的虚假尖峰,与设备老化无关。如果你只盯着 $p(V)$ 的边缘分布,就会把运维资源错误投向电压稳压模块,而真正该检修的是负载调度算法。
这个案例揭示了教科书路径的根本缺陷:一维分布剥离了变量间的约束关系,而机器学习处理的从来都是多变量耦合系统。电压 $V$ 的取值范围受电流 $I$ 制约(欧姆定律),图像像素 $x_{i,j}$ 的灰度值受邻域像素 $x_{i\pm1,j\pm1}$ 影响(马尔可夫随机场),用户点击行为 $C$ 受页面布局 $L$ 和用户历史 $H$ 共同驱动(因果图)。这些约束全部编码在联合分布 $p(V,I)$、$p(\mathbf{x})$、$p(C,L,H)$ 中,而非单个边缘分布里。
因此,本笔记彻底放弃“先一维、再二维”的线性教学法,采用逆向工程式设计:直接从二维联合分布 $p(x,y)$ 出发,将其视为一个不可分割的整体“数据地形”,然后通过两种物理操作来理解其结构:
- 切片(Slicing):固定 $y=y_0$,观察 $p(x \mid y=y_0)$ —— 这是条件分布,反映“当结果已知时,输入的形态”;
- 投影(Projection):对 $y$ 所有取值求和/积分,得到 $p(x) = \int p(x,y) , dy$ —— 这是边缘分布,反映“不管结果如何,输入的总体形态”。
提示:切片操作保留了变量间的关系,投影操作则主动丢弃关系。机器学习中 80% 的建模错误,源于混淆了该做切片还是该做投影。
2.2 为什么聚焦二维?因为它是理解高维的最小完备单元
有人会问:现实模型动辄上百维特征,为什么只讲二维?答案很实在:二维是人类视觉和直觉能直接验证的最高维度。你可以用 Matplotlib 画出 $p(x,y)$ 的等高线图、热力图、3D曲面图,能一眼看出“分布是否对称”、“是否存在长尾”、“条件分布是否随 $y$ 变化”。而三维以上,所有可视化都是降维投影,本身已含信息损失。
更重要的是,所有高维联合分布的性质,都能在二维子空间中找到原型:
- 高维协方差矩阵的奇异值分解(SVD),本质是寻找二维平面上的主方向;
- Batch Normalization 对每个特征做归一化,隐含假设是各维度边缘分布近似独立,这在二维联合分布中可通过散点图直接证伪(若散点呈斜椭圆,则 $x$ 与 $y$ 相关,边缘归一化会破坏原始尺度关系);
- 对抗样本攻击,常在二维特征子空间中构造扰动方向,其有效性直接取决于该子空间的联合分布曲率。
因此,本笔记的二维聚焦不是妥协,而是精准打击。我们将用 NumPy 生成一个可控的二维联合分布,然后像拆解机械钟表一样,逐层剥离其结构:
- 先构建一个带强相关性的二维正态分布 $p(x,y)$,参数可调(均值、方差、相关系数);
- 用数值积分法计算其边缘分布 $p(x)$、$p(y)$,并与理论解析解对比;
- 用条件分布公式 $p(x \mid y) = p(x,y)/p(y)$,生成不同 $y$ 值下的条件分布曲线;
- 最后,将此过程迁移到真实传感器数据集,验证其诊断价值。
这套流程,就是你后续处理百维特征时的思维模板——只不过把“画图”换成“计算特征重要性”,把“肉眼观察”换成“统计检验”。
2.3 “10mins 入门”的真实含义:建立可执行的检查清单
标题中的“10mins 入门”,指的是掌握一套5步快速分布诊断法,它能在模型上线前 10 分钟内,帮你识别 70% 的数据质量问题。这套方法不依赖复杂工具,仅需 NumPy + Matplotlib,且每一步都有明确的物理含义:
| 步骤 | 操作 | 检查目标 | 机器学习意义 |
|---|---|---|---|
| 1. 绘联合热力图 | plt.hist2d(x, y, bins=50) | 观察 $(x,y)$ 取值是否集中在特定区域?有无异常空洞或尖峰? | 数据采集是否完整?传感器是否偶发失联? |
| 2. 叠加边缘直方图 | plt.hist(x, alpha=0.5); plt.hist(y, alpha=0.5) | 比较 $p(x)$ 与 $p(y)$ 的支撑集(support)是否重叠? | 特征与标签的取值范围是否匹配?避免 $y$ 为类别而 $x$ 全为负数 |
| 3. 计算条件分布簇 | 对 $y$ 的每个分位数,画 $p(x \mid y \in [q_i, q_{i+1}])$ | 条件分布形态是否随 $y$ 系统性变化?(如均值漂移、方差扩大) | 模型是否需要分段建模?或引入交互项? |
| 4. 估算互信息 | sklearn.metrics.mutual_info_score | $I(X;Y)$ 是否显著大于 0? | 特征 $X$ 是否携带标签 $Y$ 的有效信息? |
| 5. 检验独立性 | scipy.stats.kendalltau(x,y) | Kendall 秩相关系数是否接近 0? | 若 $X,Y$ 独立,则 $p(x,y)=p(x)p(y)$,多数模型可简化 |
你会发现,这五步没有一步涉及“证明定理”或“推导公式”,全是动手操作。而正是这些操作,构成了你作为 ML 工程师的核心肌肉记忆——就像老司机不用想“离合器半联动点在哪”,抬脚就知道。
3. 核心细节解析与实操要点:从数学定义到代码实现的每一处“坑”
3.1 联合分布:不是两个分布的乘积,而是数据世界的“全息底片”
教科书常把联合分布 $p(x,y)$ 定义为“描述 $X$ 和 $Y$ 同时取值的概率规律”,听起来抽象。换个说法:联合分布是你采集到的所有 $(x_i, y_i)$ 数据点,在二维平面上的“密度云图”。每个数据点不是孤立存在,而是与其他点共同构成一片“概率雾”,雾浓的地方 $p(x,y)$ 大,雾薄的地方 $p(x,y)$ 小。
关键细节在于:联合分布必须满足两个硬性约束,缺一不可:
- 非负性:$\forall x,y,, p(x,y) \geq 0$;
- 归一性:$\iint_{\mathbb{R}^2} p(x,y) , dx,dy = 1$。
这两个约束看似简单,却是实操中踩坑的重灾区。我曾见过一个工业预测项目,工程师用 KDE(核密度估计)拟合传感器联合分布,但未对 KDE 结果做归一化校验,导致后续计算的条件概率 $p(x \mid y)$ 在某些 $y$ 值上积分不为 1,模型输出概率和超过 100%,被产线系统直接拒绝。原因很简单:KDE 默认输出的是“密度估计值”,需手动除以积分值才能成为合法概率密度。
实操要点:用 NumPy 验证归一性
import numpy as np from scipy.stats import multivariate_normal # 生成标准二维正态分布样本 np.random.seed(42) mean = [0, 0] cov = [[1, 0.8], [0.8, 1]] # 高相关 x, y = np.random.multivariate_normal(mean, cov, 10000).T # 方法1:用 histogram2d 估算联合密度(需归一化) hist, xedges, yedges = np.histogram2d(x, y, bins=50, density=True) # hist 是归一化的密度矩阵,sum(hist * dx * dy) ≈ 1 dx = np.diff(xedges)[0] dy = np.diff(yedges)[0] print(f"联合密度积分验证: {np.sum(hist) * dx * dy:.6f}") # 应接近 1.0 # 方法2:用 multivariate_normal.pdf 精确计算(需注意输入格式) rv = multivariate_normal(mean, cov) # 计算网格点上的密度值 x_grid, y_grid = np.meshgrid(xedges[:-1], yedges[:-1]) pdf_grid = rv.pdf(np.column_stack([x_grid.ravel(), y_grid.ravel()])) pdf_matrix = pdf_grid.reshape(x_grid.shape) print(f"理论PDF积分验证: {np.sum(pdf_matrix) * dx * dy:.6f}") # 同样应接近 1.0注意:
np.histogram2d(..., density=True)返回的hist是概率密度,其元素值需乘以面积元dx*dy才能得到概率。很多初学者直接np.sum(hist)得到 50,误以为代码出错,其实是忘了乘以微元。
3.2 边缘分布:不是“删除列”,而是“把纸卷成筒后看投影”
边缘分布 $p(x)$ 的定义是 $\int p(x,y) , dy$,常被通俗解释为“对 $y$ 求和”。但这个“求和”在物理世界中意味着什么?想象一张印有 $(x,y)$ 数据点的透明胶片,现在你把它卷成一个圆筒,让 $y$ 方向围成圆周,$x$ 方向保持直线——此时从筒轴方向(即 $x$ 轴)看过去,所有点在 $x$ 轴上的“影子叠加”就是 $p(x)$。边缘分布是联合分布在某个坐标轴上的“正交投影”,它必然丢失 $y$ 的细节,但保留了 $x$ 的全局轮廓。
这个投影过程在代码中极易出错。常见误区是:用np.mean()或np.sum()直接对二维直方图矩阵按行/列求和,却忽略 bin 宽度。正确做法是:对联合密度矩阵沿 $y$ 轴积分,即乘以 $y$ 方向的 bin 宽度dy。
实操演示:从联合分布精确推导边缘分布
# 基于前面生成的 hist (50x50 密度矩阵) # 正确:沿 y 轴积分 -> 得到 p(x) 密度 px_density = np.sum(hist, axis=1) * dy # axis=1 表示对每行(固定 x)求和,乘 dy 得密度 # 验证归一性 print(f"p(x) 边缘密度积分: {np.sum(px_density) * dx:.6f}") # 应接近 1.0 # 错误示范(勿模仿): px_wrong = np.sum(hist, axis=1) # 忘记乘 dy,结果是“密度×bin数”,无量纲,不归一 print(f"错误p(x)求和: {np.sum(px_wrong) * dx:.6f}") # 通常远大于 1,如 50.0 # 可视化对比 import matplotlib.pyplot as plt plt.figure(figsize=(12, 4)) plt.subplot(1, 3, 1) plt.hist(x, bins=50, density=True, alpha=0.7, label='真实p(x)') plt.plot(xedges[:-1] + dx/2, px_density, 'r-', lw=2, label='从联合推导p(x)') plt.legend(); plt.title('边缘分布p(x)验证') plt.subplot(1, 3, 2) plt.hist2d(x, y, bins=50, cmap='Blues', density=True) plt.title('联合分布p(x,y)热力图') plt.subplot(1, 3, 3) # 画条件分布簇:取 y 的 3 个分位数区间 y_quants = np.quantile(y, [0.25, 0.5, 0.75]) for i, (q_low, q_high) in enumerate(zip([y.min()] + y_quants.tolist(), y_quants.tolist() + [y.max()])): mask = (y >= q_low) & (y < q_high) if np.sum(mask) > 50: # 确保有足够样本 plt.hist(x[mask], bins=30, alpha=0.5, label=f'y∈[{q_low:.2f},{q_high:.2f})') plt.legend(); plt.title('条件分布p(x|y)簇') plt.show()这段代码的关键在于:px_density = np.sum(hist, axis=1) * dy。axis=1表示对每一行(即固定 $x$ 值,遍历所有 $y$ bin)求和,乘以dy才是真正的密度。若忘记* dy,得到的是“每个 $x$ bin 内的总‘密度计数’”,其量纲错误,无法与真实直方图对比。
3.3 一维 vs 二维:为什么“一维随机变量”的边缘分布才是你天天打交道的“直方图”?
标题中并列“一维、二维随机变量”,容易让人误解为两类独立对象。真相是:所谓“一维随机变量”,本质上是高维联合分布降维后的边缘分布。你每天画的plt.hist(data),那个data看似一维数组,但它背后必然关联着至少一个隐变量——时间戳、设备ID、用户会话ID……这些隐变量与data构成联合分布 $p(\text{value}, \text{context})$,而你画的直方图,只是对该联合分布沿 context 维度投影得到的边缘分布 $p(\text{value})$。
这个认知转换至关重要。举个例子:某推荐系统监控点击率(CTR),运营同学说“今天 CTR 直方图变宽了”,技术同学立刻查模型 AUC 下降。但若深入看联合分布 $p(\text{CTR}, \text{hour})$,会发现:直方图变宽并非整体波动,而是深夜时段(0-6点)CTR 异常升高(因爬虫流量涌入),而白天时段 CTR 实际更稳定。此时,对 $p(\text{CTR})$ 做边缘分析是无效的,必须回到联合分布 $p(\text{CTR}, \text{hour})$,做条件分析 $p(\text{CTR} \mid \text{hour})$。
因此,本笔记强调:不要孤立看待“一维分布”,而要始终追问“它从哪个联合分布投影而来?”这个问题的答案,直接决定你该用什么统计方法:
- 若联合分布是 $p(\text{feature}, \text{label})$,则用互信息、条件熵评估特征质量;
- 若联合分布是 $p(\text{feature}_i, \text{feature}_j)$,则用相关系数、距离相关性检测冗余;
- 若联合分布是 $p(\text{metric}, \text{time})$,则用时间序列分解(趋势/周期/残差)替代静态直方图。
实操心得:下次画任何直方图前,强制在笔记本上写下它的联合分布形式。例如:
plt.hist(user_age)→ 联合分布是 $p(\text{age}, \text{country})$,那么你画的其实是 $\int p(\text{age}, \text{country}) , d\text{country}$。这个习惯能瞬间提升你对数据偏差的敏感度。
3.4 二维联合分布的三大典型形态及其机器学习启示
二维联合分布 $p(x,y)$ 的形态,直接暴露数据生成机制。掌握三种基础形态,相当于拿到数据质量的“X光机”:
形态1:独立同分布(IID)——散点呈圆形/方形均匀云团
- 数学特征:$p(x,y) = p(x)p(y)$,协方差为 0;
- 可视化:
plt.scatter(x,y)呈均匀圆形或方形点云,无明显方向性; - ML 启示:适合用线性模型、朴素贝叶斯;特征工程可大胆做标准化(因各维度独立);
- 陷阱:现实中极少严格 IID。若散点图看似均匀,务必用
scipy.stats.kendalltau检验秩相关性,避免将弱相关误判为独立。
形态2:线性相关——散点呈倾斜椭圆
- 数学特征:协方差非零,$p(x,y)$ 是二维正态分布;
- 可视化:点云沿某条直线密集分布,椭圆长轴即主成分方向;
- ML 启示:PCA 降维有效;但若标签 $y$ 与特征 $x$ 呈此形态,线性回归是合理起点;
- 关键细节:椭圆倾斜角度 $\theta$ 满足 $\tan(2\theta) = \frac{2\sigma_{xy}}{\sigma_x^2 - \sigma_y^2}$,其中 $\sigma_{xy}$ 是协方差。这解释了为何高相关特征组合(如 $x_1+x_2$)常提升模型性能——它在旋转后的坐标系中对齐了主轴。
形态3:条件异方差(Heteroscedasticity)——散点呈“喇叭形”或“束状”
- 数学特征:$p(x \mid y)$ 的方差随 $y$ 变化,如 $y$ 大时 $x$ 波动剧烈;
- 可视化:固定 $y$ 的水平切片,其 $x$ 的散布宽度明显不同;
- ML 启示:均方误差(MSE)损失函数失效(因对大 $y$ 区域过度惩罚);应改用分位数损失或加权 MSE;
- 实操技巧:用
sns.boxplot(x='y_bin', y='x')画箱线图,直观观察条件方差变化。
下面用代码生成这三种形态,并标注关键诊断指标:
# 形态1:近似独立(低相关) np.random.seed(1) x1 = np.random.normal(0, 1, 1000) y1 = np.random.normal(0, 1, 1000) + 0.1 * x1 # 加微弱相关防完全独立 corr1, _ = kendalltau(x1, y1) # 形态2:强线性相关 x2 = np.random.normal(0, 1, 1000) y2 = 0.9 * x2 + np.random.normal(0, 0.3, 1000) corr2, _ = kendalltau(x2, y2) # 形态3:条件异方差(喇叭形) x3 = np.random.normal(0, 1, 1000) y3 = x3 + np.random.normal(0, 0.2 + 0.5 * np.abs(x3), 1000) # 方差随|x|增大 corr3, _ = kendalltau(x3, y3) # 可视化对比 fig, axes = plt.subplots(1, 3, figsize=(15, 4)) for i, (x, y, corr, title) in enumerate(zip([x1,x2,x3], [y1,y2,y3], [corr1,corr2,corr3], ['近似独立', '强线性相关', '条件异方差'])): axes[i].scatter(x, y, s=1, alpha=0.6) axes[i].set_title(f'{title}\nKendall τ = {corr:.3f}') axes[i].set_xlabel('x'); axes[i].set_ylabel('y') plt.tight_layout() plt.show()运行这段代码,你会清晰看到三种形态的视觉差异。特别注意形态3:当 $x$ 接近 0 时,$y$ 的点很集中;当 $x$ 远离 0 时,$y$ 的点呈喇叭状散开。这就是典型的条件异方差——它意味着模型误差不是恒定的,而是随输入幅度变化。若忽略这点,用普通线性回归,预测结果在 $x$ 大的区域必然系统性不准。
4. 实操过程与核心环节实现:用真实传感器数据验证联合-边缘分析法
4.1 数据准备:一个真实的电机振动传感器数据集
为避免纯模拟数据的“玩具感”,我们采用某高校公开的电机轴承故障数据集(代号:Bearing-2023)。该数据集包含:
- 采样频率:10 kHz;
- 信号长度:每样本 1024 点;
- 标签:4 类(正常、内圈故障、外圈故障、滚动体故障);
- 关键特征:我们提取两个时域特征——均方根值(RMS)和峭度(Kurtosis),构成二维特征空间 $(x,y)$。
提示:RMS 反映振动能量强度,峭度反映冲击脉冲的尖锐程度。二者在故障诊断中具有物理互补性:早期故障表现为峭度突增而 RMS 变化不大;晚期故障则 RMS 和峭度同步升高。
我们加载数据(此处用模拟数据代替真实文件,但结构完全一致):
# 模拟 Bearing-2023 数据集(结构与真实数据一致) np.random.seed(42) n_samples = 2000 # 正常状态:RMS 低,峭度近似正态 rms_normal = np.random.normal(0.8, 0.1, n_samples//4) kurt_normal = np.random.normal(3.0, 0.3, n_samples//4) # 内圈故障:RMS 升高,峭度显著增大(冲击性强) rms_inner = np.random.normal(1.2, 0.15, n_samples//4) kurt_inner = np.random.normal(6.5, 0.8, n_samples//4) # 外圈故障:RMS 中等,峭度中等但分布偏斜 rms_outer = np.random.normal(1.0, 0.12, n_samples//4) kurt_outer = np.random.lognormal(1.7, 0.4, n_samples//4) # 偏斜分布 # 滚动体故障:RMS 波动大,峭度不稳定 rms_ball = np.random.normal(1.1, 0.25, n_samples//4) kurt_ball = np.random.normal(5.0, 1.2, n_samples//4) # 合并数据 X_rms = np.concatenate([rms_normal, rms_inner, rms_outer, rms_ball]) X_kurt = np.concatenate([kurt_normal, kurt_inner, kurt_outer, kurt_ball]) y_label = np.array([0]*len(rms_normal) + [1]*len(rms_inner) + [2]*len(rms_outer) + [3]*len(rms_ball)) # 添加少量噪声模拟测量误差 X_rms += np.random.normal(0, 0.02, len(X_rms)) X_kurt += np.random.normal(0, 0.05, len(X_kurt))这段代码生成了符合物理规律的四类故障数据。注意:我们没有用make_classification这类黑盒生成器,而是基于故障机理(如“内圈故障产生强周期冲击,故峭度高”)手动建模,确保数据具备真实世界的因果结构。
4.2 第一步:绘制联合分布热力图,诊断数据采集完整性
执行联合热力图诊断:
plt.figure(figsize=(10, 8)) # 使用高分辨率 bin(100x100)捕捉细节 hist, xedges, yedges = np.histogram2d(X_rms, X_kurt, bins=[100, 100], density=True) # 绘制热力图 im = plt.imshow(hist.T, extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]], origin='lower', cmap='viridis', aspect='auto') plt.colorbar(im, label='p(RMS, Kurtosis)') plt.xlabel('RMS (g)'); plt.ylabel('Kurtosis') plt.title('电机振动特征联合分布热力图\n(颜色越亮,概率密度越高)') plt.show()观察热力图,你能发现什么?
- 正常状态(左下角):RMS≈0.8,Kurtosis≈3.0,形成一个高密度椭圆斑块;
- 内圈故障(右上角):RMS≈1.2,Kurtosis≈6.5,另一个分离的斑块;
- 外圈故障(中部偏右):RMS≈1.0,Kurtosis 分布更广(因对数正态的长尾),呈现横向拉伸;
- 滚动体故障(分散区域):RMS 波动大(纵向拉伸),Kurtosis 不稳定(横向拉伸),形成一片弥散云。
关键发现:四个斑块之间存在明显的“空洞区”(如 RMS=0.95, Kurtosis=4.5 附近)。这并非数据缺失,而是物理规律决定的——某种故障模式不会同时产生中等 RMS 和中等峭度。若你在真实数据中发现本该有数据的区域出现大片空白,那极可能是传感器采样丢失或数据清洗误删。这就是联合分布热力图的核心价值:它是一张“数据健康地图”。
4.3 第二步:叠加边缘直方图,检验特征-标签对齐性
现在,我们不再按类别分开,而是看所有数据的边缘分布:
plt.figure(figsize=(12, 4)) # 子图1:RMS 边缘分布 plt.subplot(1, 3, 1) plt.hist(X_rms, bins=50, density=True, alpha=0.7, label='p(RMS)') plt.xlabel('RMS (g)'); plt.ylabel('Density'); plt.title('RMS 边缘分布') plt.legend() # 子图2:Kurtosis 边缘分布 plt.subplot(1, 3, 2) plt.hist(X_kurt, bins=50, density=True, alpha=0.7, label='p(Kurtosis)') plt.xlabel('Kurtosis'); plt.ylabel('Density'); plt.title('Kurtosis 边缘分布') plt.legend() # 子图3:联合分布 + 边缘投影(关键!) plt.subplot(1, 3, 3) # 先画联合热力图 hist, xedges, yedges = np.histogram2d(X_rms, X_kurt, bins=[50,50], density=True) plt.imshow(hist.T, extent=[xedges[0], xedges[-1], yedges[0], yedges[-1]], origin='lower', cmap='Blues', alpha=0.8) # 叠加边缘分布(投影到轴上) px = np.sum(hist, axis=1) * np.diff(yedges)[0] # p(RMS) 投影 py = np.sum(hist, axis=0) * np.diff(xedges)[0] # p(Kurtosis) 投影 plt.plot(xedges[:-1] + np.diff(xedges)[0]/2, px, 'r-', lw=2, label='p(RMS)') plt.plot(py, yedges[:-1] + np.diff(yedges)[0]/2, 'g-', lw=2, label='p(Kurtosis)') plt.xlabel('RMS'); plt.ylabel('Kurtosis') plt.title('联合分布 + 边缘投影\n(红线:p(RMS),绿线:p(Kurtosis))') plt.legend() plt.tight_layout() plt.show()这个三联图揭示了一个致命问题:RMS 的边缘分布(红线)峰值在 0.8-1.2,而 Kurtosis 的边缘分布(绿线)峰值在 3.0-6.5,但二者在联合图中并非均匀覆盖——高 Kurtosis 区域主要对应高 RMS(内圈故障),而低 Kurtosis 区域主要对应低 RMS(正常)。这意味着:RMS 和 Kurtosis 并非独立特征,它们的联合结构才是分类的关键。
若你只看单个边缘直方图,可能会认为“RMS 范围太窄,需要扩大量程”,从而错误地调整传感器增益。而联合图告诉你:窄不是问题,问题是窄范围内蕴含了丰富的条件结构。这正是边缘分布无法替代联合分布的原因。
4.4 第三步:计算条件分布簇,定位模型失效的“危险区”
现在,我们按标签类别,分别计算条件分布 $p(\text{RMS} \mid \text{class}=c)$:
plt.figure(figsize=(12, 8)) classes = [0, 1, 2, 3] class_names = ['Normal', 'Inner', 'Outer', 'Ball'] colors = ['blue', 'red', 'green', 'orange'] for i, c in enumerate(classes): mask = (y_label == c) # 计算该类别的 RMS 条件分布(用直方图近似) hist_c, edges_c = np.histogram(X_rms[mask], bins=30, density=True) centers_c = edges_c[:-1] + np.diff(edges_c)[0]/2 plt.plot(centers_c, hist_c, color=colors[i], lw=2, label=f'{class_names[i]}') # 标注该类别的 RMS 均值和标准差 mean