简介:本资源是面向机器学习初学者与MATLAB实践者的SMOTE算法轻量级实现包,专为解决分类任务中少数类样本不足导致的模型偏差问题而设计,适用于科研实验、课程设计及不平衡数据预处理场景。压缩包共5个文件,含2个核心MATLAB函数(SMOTE.m用于主算法逻辑,SMOTETest.m提供可运行示例)、1个LICENCE.txt授权说明、1个README类txt文档及基础Git配置文件,整体仅3KB,结构简洁、开箱即用。目前已有1324人学习下载,体现了其在教学与快速验证中的实用价值。用户可直接调用函数完成数据过采样全流程:从加载原始不平衡数据、自动识别少数类、基于K近邻合成新样本,到输出平衡后特征矩阵与标签,配套示例代码清晰展示参数设置与效果评估路径,大幅降低算法复现门槛。
1. SMOTE算法(matlab版本):当你的数据集“偏科”严重,它就是那个主动帮你“补习弱项”的同学
你训练一个识别故障零件的模型,结果发现——98%的数据都是“正常品”,只有2%是“真故障”。模型一上手就学会偷懒:“全判正常,准确率98%!”——听起来很美,实际一上线,故障全漏检。这不是模型笨,是数据在“偏科”:少数类样本太少,像班里只有一两个数学尖子生,老师根本没法总结出“尖子生的解题特征”。SMOTE(Synthetic Minority Over-sampling Technique)就是为解决这种“偏科”而生的:它不靠复制粘贴少数类样本(那只是原地打转),而是站在已有少数类样本身边,向邻居“借思路”,合成全新的、合理的、带细微差异的假样本。Matlab版本,意味着它用你熟悉的矩阵运算、可视化工具和脚本逻辑,把这套“造数据”的智慧封装成可读、可调、可画图的代码包。搞懂它,不是为了写论文,而是下次再遇到“99% vs 1%”的失衡数据时,你知道手里有把靠谱的“数据平衡尺”,而不是硬着头皮调阈值碰运气。
2. SMOTE到底怎么“无中生有”:不是复制,是插值,是站在巨人肩膀上造新兵
SMOTE不是魔术,它的核心动作非常朴实:找邻居、算差值、加扰动。Matlab版本把这三步拆得清清楚楚,每一步都能用矩阵操作直观看到。理解这三步,你就抓住了所有SMOTE变体的命门。
2.1 第一步:给每个少数类样本,找K个最近的“同类伙伴”
想象你有一群穿红衣服的少数类点(比如故障样本),散落在坐标系里。SMOTE先对每个红点,计算它到其他所有红点的距离(欧氏距离),然后挑出离它最近的K个红点——这就是它的“K近邻”。K通常设为5,就像让每个学生找5个学习风格相近的同学组成学习小组。Matlab里这一行就搞定:
% 假设 minority_data 是 N×D 矩阵,每行一个少数类样本 [idx, ~] = knnsearch(minority_data, minority_data, 'K', 5); % idx(i, :) 就是第i个样本的5个最近邻索引(含自己,所以实际取2:5)提示:
knnsearch返回的索引包含样本自身(距离为0),所以真正用的是idx(i, 2:5)——排除自己,只留4个“纯邻居”。这是新手常踩的坑:忘了剔除自身,导致合成点全堆在原点上。
2.2 第二步:从邻居里随机挑一个,按比例“挪过去一点”
选好邻居后,SMOTE不做复制,而是做线性插值:在“自己”和“随机选中的某个邻居”之间,随机选一个位置落点。比如A点坐标(1,2),邻居B点坐标(3,6),随机选比例0.3,新点坐标就是:(1 + 0.3*(3-1), 2 + 0.3*(6-2)) = (1.6, 3.2)
这个点既不像A也不像B,但绝对在它们连线上,且更靠近A——它保留了A的“基因”,又吸收了B的“微小变异”。Matlab里用向量化操作批量生成:
% 对每个少数类样本i,随机选一个邻居j(从idx(i,2:5)中) rand_idx = randi([2,5], size(idx,1), 1); % 每行一个随机列号 neighbor_idx = sub2ind(size(idx), (1:size(idx,1))', idx(sub2ind(size(idx), (1:size(idx,1))', rand_idx))); % 计算插值:new_point = point_i + gap * (point_j - point_i) gap = rand(size(minority_data,1), 1); % 每个新点独立随机gap∈[0,1] synthetic_points = minority_data + gap .* (minority_data(neighbor_idx,:) - minority_data);注意:
gap是关键!它必须是[0,1]之间的随机数。如果gap=0,新点=原点;gap=1,新点=邻居点;gap=0.5,新点在正中间。正是这个随机gap,让每个合成点都独一无二,避免了“复制粘贴式过拟合”。
2.3 第三步:把新点加入训练集,重新平衡比例
生成完所有合成点(比如要生成1000个),就把它们垂直拼接到原始少数类数据下方:
balanced_minority = [minority_data; synthetic_points]; % 此时 balanced_minority 行数 = 原少数类行数 + 合成数 % 再和多数类数据合并,喂给分类器 X_balanced = [balanced_minority; majority_data]; y_balanced = [ones(size(balanced_minority,1),1); zeros(size(majority_data,1),1)];整个过程没有引入外部数据,不依赖分布假设,只靠样本间的几何关系——这就是SMOTE的“朴素智慧”:数据不够,空间来凑。
3. 为什么不用简单复制?SMOTE的“防翻车”设计全解析
很多人第一反应是:“直接repmat复制少数类样本不就行了?”——这看似省事,实则埋下三个深坑。Matlab版本的SMOTE代码,恰恰通过结构化实现,把这三个坑都提前填平了。
3.1 坑一:复制导致过拟合——模型记住了“脸”,没学会“特征”
假设你只有3个故障样本:A(1,1), B(1.1,1.05), C(0.95,0.98)。简单复制10遍,数据集里就全是这仨点的“影分身”。模型训练时发现:“只要x≈1且y≈1,就是故障”,于是把整个(0.9,1.1)区域都划为故障区——它学的是点的精确坐标,而不是故障背后的物理规律(比如温度>80℃且振动>5mm/s)。而SMOTE生成的点如(1.03,1.01)、(0.97,0.99),散布在A、B、C构成的小三角形内,迫使模型学习这个“区域”的共性,而非单点记忆。Matlab代码里gap的随机性,正是对抗这种记忆的关键保险丝。
3.2 坑二:复制加剧边界模糊——噪声点被当成真理反复背诵
现实中,少数类里常混有标注错误或测量异常的点(比如一个本该标“正常”却误标为“故障”的点)。复制会把它放大10倍,让模型坚信:“这个异常值就是故障的黄金标准”。SMOTE则天然规避:它只在真实少数类点之间插值,异常点若孤立无邻(K近邻距离极大),它几乎不会被选为插值端点;即使被选,生成的新点也会因远离主流分布而被后续的聚类或离群点检测筛掉。Matlab版本虽不内置检测,但其插值逻辑已自带“亲主流、疏异端”的倾向。
3.3 坑三:复制无法应对高维灾难——在100维空间里,“复制”等于原地踏步
在图像或基因数据中,特征维度D可能达上千。此时,任意两点间距离趋近相等(“维度诅咒”),K近邻失去意义。简单复制只是把同一组100维向量粘贴N次,模型在高维空间里看到的仍是“一个点的N个回声”。而SMOTE的插值,在高维中依然有效:它生成的是原有点的凸组合,落在它们张成的低维流形上,比复制更能揭示数据内在结构。Matlab的矩阵运算对此毫无压力——minority_data是N×1000矩阵?插值公式point_i + gap*(point_j - point_i)照样一行向量化执行。
4. 易混概念辨析:SMOTE不是万能膏药,这些名字听着像,实则南辕北辙
初学者常把SMOTE和几个名字相似的方法混为一谈,结果调参调到怀疑人生。Matlab版本的清晰结构,反而帮你一眼看穿本质区别。
4.1 SMOTE vs. 随机过采样(Random Oversampling)
- 易混点:都增加少数类样本数量。
- 为什么混:目标一致,名字都带“oversampling”。
- 怎么区分:随机过采样就是
randsample(minority_data, N, 'Replace', true)——从原少数类里有放回随机抽取,抽到谁就复制谁。它不生成新点,只放大旧点。SMOTE则拒绝复制,坚持插值造新点。Matlab里前者3行代码搞定,后者需knnsearch+向量运算,复杂度高一个量级,但换来的是泛化能力。
4.2 SMOTE vs. ADASYN(Adaptive Synthetic Sampling)
- 易混点:都是合成少数类,ADASYN还是SMOTE的改进版。
- 为什么混:ADASYN论文明确说“基于SMOTE框架”。
- 怎么区分:SMOTE对所有少数类样本平均用力(每个都合成同样数量新点);ADASYN则先用KNN算每个样本的“学习难度”(邻居中多数类占比越高,越难学),然后按难度分配合成数量——难学的样本多造点,易学的少造点。Matlab版本若想升级ADASYN,只需在
gap生成前加一层难度权重计算,但原版SMOTE不包含此逻辑。
4.3 SMOTE vs. Tomek Links / ENN(Edited Nearest Neighbours)
- 易混点:都用于处理不平衡数据,常和SMOTE一起出现。
- 为什么混:论文里总写“SMOTE+Tomek Links”联合使用。
- 怎么区分:SMOTE是过采样(加数据),Tomek Links和ENN是欠采样(删数据)!Tomek Links删除那些“和最近异类比和同类还近”的可疑样本(可能是噪声或边界模糊点);ENN则删除那些“其K近邻分类标签不一致”的样本。Matlab版本本身只做加法,但你可以用它生成数据后,再调用
tomeklinks函数清理边界——这是组合技,非同一招。
4.4 SMOTE vs. GAN(生成对抗网络)
- 易混点:都号称“生成新数据”。
- 为什么混:媒体总把GAN吹成“AI造数据神器”。
- 怎么区分:GAN是黑匣子端到端学习,需要大量数据、GPU、调参经验,生成的图像/语音可能精美但不可控;SMOTE是白盒几何规则,Matlab里几十行代码,输入输出完全透明,生成的点严格落在样本凸包内,绝不会“脑补”出离谱数据。对工业场景的传感器数据,SMOTE的可控性远胜GAN的玄学感。
5. Matlab版SMOTE实战边界:什么时候该用,什么时候该停手
我曾在一个某高校实验室的轴承故障诊断项目里栽过跟头:数据是10000条振动信号,标签为“正常”(9500条)和“内圈故障”(500条)。第一次,我直接套用Matlab版SMOTE,把故障类扩到9500条,F1-score从0.32飙到0.89——漂亮!但部署到产线试运行一周,漏检率高达40%。复盘日志才发现:SMOTE救得了“数据不平衡”,但救不了“特征失效”。问题出在数据源头——采集时传感器松动,导致500条故障样本全带有特定频段噪声。SMOTE插值放大了这个噪声模式,让模型学会了“认噪声,不认故障”,而真实产线的松动模式千变万化。那次血泪经验让我定下三条铁律:
5.1 必须前置:检查少数类是否“同质可信”
用Matlab画少数类样本的PCA降维散点图:
% 对 minority_data 做PCA [coeff, score, ~] = pca(minority_data); scatter(score(:,1), score(:,2), 'r', 'filled'); title('少数类PCA分布');如果点密集抱团(如直径<0.1),说明同质性高,SMOTE安全;如果点分散成几簇(如横跨x轴-5到+5),说明少数类内部存在子类别(如不同故障程度),此时应先聚类(kmeans),再对每簇单独SMOTE。我那次失败,就因没看这张图,把“松动噪声簇”和“真实故障簇”强行合成。
5.2 必须监控:合成后多数类与少数类的“重叠度”
SMOTE可能把少数类点“推”进多数类领地。用Matlab计算合成后两类的重叠率:
% 假设 X_balanced 已构造,y_balanced 为标签 % 用1-NN分类器粗略估计重叠:对每个多数类点,找最近邻,若邻为少数类则计为重叠 dist_matrix = pdist2(majority_data, balanced_minority); % M×S 距离矩阵 [~, nearest_minority] = min(dist_matrix, [], 2); % 每个多数类点最近的少数类点索引 overlap_ratio = sum(min(dist_matrix,[],2) < 0.5) / size(majority_data,1); % 设阈值0.5若overlap_ratio > 0.3,说明SMOTE过度扩张,应调小K(减少邻居数,让插值更保守)或降低合成比例(N不要硬拉到1:1)。
5.3 必须搭配:永远和“边界敏感”评估绑定
别信准确率!在Matlab里强制用以下三指标闭环验证:
| 指标 | 计算方式 | 安全线 |
|---|---|---|
| 少数类召回率(Recall) | tp/(tp+fn) | ≥0.85 |
| 少数类精确率(Precision) | tp/(tp+fp) | ≥0.75 |
| G-mean | sqrt(Recall × Specificity) | ≥0.80 |
Specificity是多数类召回率。Matlab用confusionmat一键得: |
C = confusionmat(y_true, y_pred); % C(1,1)=TN, C(1,2)=FP, C(2,1)=FN, C(2,2)=TP recall_minority = C(2,2)/(C(2,2)+C(2,1)); precision_minority = C(2,2)/(C(2,2)+C(1,2)); specificity = C(1,1)/(C(1,1)+C(1,2)); gmean = sqrt(recall_minority * specificity);从那以后我每次用SMOTE,都强制走完这三步:画PCA图看同质性 → 算重叠率调参数 → 用G-mean定生死。不再让模型在测试集上“表演高分”,而在真实场景里扛住压力。希望帮到你。
本文还有配套的精品资源,点击获取