ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

随机秩次k近邻:解决不平衡数据分类的低估技术路线

随机秩次k近邻:解决不平衡数据分类的低估技术路线 简介《基于随机秩次k近邻规则的不平衡数据分类算法》是一篇发表于《应用数学进展》2020年的学术论文聚焦机器学习中类别不平衡场景下少数类样本识别率低的问题。文中提出REKRNN算法将k-秩近邻规则融入Bagging集成学习框架并采用混合重采样与随机子空间法增强基学习器差异可有效提升不平衡数据的分类性能。这份PDF资料共1个文件大小521KB包含论文全文、中英文摘要、关键词及实验数据与参考文献适合机器学习、数据挖掘领域的研究者、算法工程师及高年级学生用于算法学习与论文参考。资源目前已有111人学习通过阅读该论文可以系统理解不平衡分类的集成策略、k-秩近邻的改进思路以及实验设计方法对开展相关研究与工程应用具有直接的参考价值。1. 随机秩次k近邻不平衡数据分类里被低估的一条技术路线做分类任务遇到正负样本比例1:99常规kNN几乎必然把少数类全部吞掉——这不是调参能救的是算法结构对数据分布太敏感。随机秩次k近邻Random Rank kNN这个方向核心就两件事把kNN基于绝对距离的邻居比较换成基于秩次的相对比较再用随机化去对冲边界上样本的偏置。它解决的是不平衡数据下少数类召回率过低、决策边界被多数类“淹没”的经典问题适合风控、故障诊断、医疗筛查这类少数类样本稀缺但漏检代价极高的场景。这文从原理拆到numpy实现把参数和踩坑点都讲透让你能独立跑通并评估这套方法是否值得纳入你的工具箱。2. 不平衡数据分类为什么难多数类淹没到边界样本失效2.1 多数类淹没与少数类召回率崩塌的机理不平衡数据的核心矛盾不在样本量差距本身而在密度差异。假设正常样本10万条异常样本500条异常样本在特征空间中被压缩到极小局部区域多数类样本像背景噪声一样铺满周围。基于距离的算法在其中做决策时少数类样本的每个近邻域内几乎都是多数类即使目标样本本身属于少数类最邻近的几个点也会大概率是多数类。这就导致“召回率崩塌”模型整体准确率很高因为多数类占比高但少数类几乎全部漏掉。这个现象在kNN里被放大。kNN没有显式训练过程决策完全依赖样本点之间的几何距离。当多数类密度远高于少数类时任意少数类样本到其第k个近邻的距离通常远大于多数类样本之间的平均距离。决策边界被挤压到少数类区域的内部而不是分布在两类之间的合理位置。另一个被忽视的原因是尺度敏感。特征之间的量纲差异如果不做标准化欧氏距离会被量纲大的特征主导少数类在这些特征上的小幅变化不足以影响近邻判定。很多从业者做不平衡分类时先做StandardScaler但即使做完标准化密度不均的问题依然存在。所以不平衡分类的第一个硬约束是算法必须对密度差异不敏感或者能显式补偿这种偏置。随机秩次kNN正是从“距离比较”切换到“秩次比较”绕开密度差异对绝对距离的影响。2.2 传统kNN在不平衡数据上的三个结构性缺陷传统kNN在不平衡数据上有三个结构性缺陷任何一个都足以让结果翻车。第一个缺陷是多数类投票优势。kNN的最终决策是少数服从多数k个近邻里多数类占多数时就判为多数类。在不平衡数据中多数类样本数量上的优势会直接传导到投票结果上。就算少数类样本的密度没有完全被淹没只要k稍大多数类票数就压制少数类。第二个缺陷是距离度量失真。多数类样本聚集紧密少数类样本分散稀疏同样的欧氏距离在两类样本上的“语义”完全不同——多数类样本之间的距离小但代表的是类内噪声少数类样本之间的距离大但代表的是类内真实分布。基于同一套距离阈值去判断两类样本的邻居关系本身就缺乏可比性。第三个缺陷是边界样本的确定性误判。决策边界附近的样本其近邻构成高度不稳定但kNN给出的是确定性判定。一个边界少数类样本其最近邻中可能恰好有k-1个多数类、1个少数类此时投票结果直接判错且没有任何机制表达“这个判定很不确定”。这三个缺陷叠加导致传统kNN在不平衡数据上的表现经常不如简单的逻辑回归配合过采样。这也是为什么很多团队做基线对比时kNN往往被排除在外。随机秩次kNN的改进思路就是针对这三个缺陷逐一打补丁。2.3 随机秩次规则的设计动机从距离比较到次序比较随机秩次kNN的核心改动是把“距离值”替换成“距离秩次”。给定查询样本x计算它与训练集中所有样本的欧氏距离得到距离序列。把这个序列从小到大排序每个训练样本得到一个秩次值——距离最近的秩次为1最远的为N。这一步就把绝对距离变成了相对次序。这么做为什么能对抗不平衡因为秩次只关心“谁更近”不关心“近多少”。多数类样本在局部区域内密度高它们的绝对距离可能都很小但秩次上依然有先后少数类样本之间的距离可能较大但只要查询样本确实更靠近少数类群体它们在秩次上就能排到前面。这相当于把密度差异从决策过程中剥离了一部分。随机化则加在秩次的使用方式上。一种做法是构造多个随机秩次组合对每个样本从训练集中随机抽取子集计算秩次重复多次用投票结果做最终判定。另一种做法是在平局或边界情况下随机断案。无论哪种核心都是用随机性对冲边界样本的不稳定性。从直觉上理解随机秩次kNN相当于给kNN套了一层bagging式的扰动让原本对边界敏感的确定性判定变成多次采样的综合结果。这在方差和偏差之间做了一个取舍单次秩次kNN可能比传统kNN更不稳定但多次综合后的决策边界更平滑且不会像传统kNN那样一边倒。理解了这层逻辑后续的参数调优和代码实现才有方向。3. 随机秩次kNN的算法拆解投票机制与三个必调参数3.1 秩次计算与随机化过程把距离序列变成秩次序列先把秩次计算这个步骤落到具体操作上。给定查询样本q、训练集XN个样本、距离函数d标准流程如下计算q到X中每个样本的欧氏距离得到长度为N的距离数组dist对dist做argsort得到距离从小到大的索引顺序为每个训练样本分配秩次距离最小的为1最大的为N。如果训练集有N个样本kNN只用前k个的标签投票而秩次kNN会把前k个的秩次值本身作为特征。核心差异在于传统kNN关心的是“前k个是什么”秩次kNN关心的是“前k个的次序结构是什么”。这个差异在局部密度不均时会产生不同的决策。随机化的引入方式常见做法是子采样。设采样比例r∈(0,1)每次从训练集中不放回地抽取r*N个样本对这批样本计算查询样本的秩次取前k个做投票。重复T次T次投票结果的众数或加权平均作为最终预测。这个设计有一个好处每一次子采样查询样本的近邻构成都会变化。边界样本尤其敏感——它在某些子采样下可能排到多数类附近在另一些子采样下又排到少数类附近。综合多次结果算法自然会对不确定性更高的样本输出更保守的判定。另外随机秩次还可以和类别权重结合。少数类样本的票数可以乘一个权重系数w1用来补偿多数类数量优势。严格说这不再是纯“随机秩次”但在工程实现中很常见因为单纯依赖秩次并不能完全消除投票偏差权重补偿是低成本高收益的补充。3.2 随机秩次kNN的投票规则加权、平局处理与决策阈值投票规则直接决定算法效果。朴素做法是T次采样各自找出前k个近邻每个近邻投一票票多者胜。但在不平衡数据下这种投票依然会偏向多数类。因此实际实现中通常采用加权策略。一个实用规则是秩次倒数加权对每个近邻用1/rank作为它的票权重。排名第1的样本权重1.0第10的样本权重0.1。这比简单的数量投票更精细——距离更近的样本对决策影响更大同时少数类样本即使数量少只要秩次靠前也能贡献不可忽略的权重。结合类别加权最终一个样本的少数类得分为score_minor Σ (1/rank_i) * w_minor 对所有属于少数类的近邻i多数类得分同理只差权重系数。判定时比较两个分数或者对score_minor设置一个阈值。平局处理也是一个关键细节。当少数类得分和多数类得分相等时常见做法有随机断案掷硬币、偏向多数类、偏向少数类。在不平衡分类场景下我建议偏向少数类因为代价矩阵里漏掉少数类的成本更高。但这个选择应该由业务代价决定而不是由算法默认值决定。还有一个细节是决策阈值。如果输出的是score_minor而不是硬分类就可以在验证集上调整阈值用F1或G-mean最大化来选最优阈值。这一步在实践中经常被忽略但它对不平衡分类效果的影响有时比换算法更大。3.3 三个必调参数k值、子采样比例r、随机化次数T随机秩次kNN最核心的参数有三个每个都有明确的作用边界。k值控制每个子采样中参与投票的邻居数量。k值过小单次投票对噪声敏感k值过大子采样中必然混入大量多数类样本少数类信号被稀释。在随机秩次的框架下k的合理范围比传统kNN更宽——因为秩次加权会让靠前的少数类样本获得更高权重。我一般从k5开始按数据集规模逐次翻倍用验证集F1做筛选。子采样比例r控制每次随机采样的训练集窗口大小。r越小单次采样的局部性越强算法越发关注查询样本周围的局部结构但方差也越高。r越大单次采样越接近全局结构但随机性的意义就减弱了。实践中r在0.3到0.7之间比较合理。如果数据集非常大可以适当调小r换取计算效率。随机化次数T控制重复采样和投票的次数本质是精度与算力的权衡。T太小多次投票的方差压不住结果不稳定T太大算力开销线性增长。我一般用T50做快速验证效果稳定后降到T20或T30用于线上推理。留意这里的“线上推理”指的是离线批量预测不是毫秒级实时接口。这三个参数的调节顺序有讲究。先固定r0.5、T50在验证集上调k找到最优k后再调r最后调T。不要一上来就全参数网格搜索不然调试时间成本和算力成本都会失控而且很难定位效果波动来自哪个参数。4. 用Pandas和NumPy实现最小可运行的随机秩次kNN完整代码与评估口径4.1 构造不平衡数据合成数据集与预处理流程先造一份能用实验说话的数据集避免直接拿业务数据跑因为业务数据的噪声和缺失会让你分不清是算法问题还是数据问题。用scikit-learn的make_classification设置少量少数类样本和特定分离程度。import numpy as np import pandas as pd from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler # 构造二分类不平衡数据集1000个样本少数类占比约5% X, y make_classification( n_samples1000, n_features10, n_informative6, n_redundant2, n_clusters_per_class1, weights[0.95, 0.05], random_state42 ) # 分层切分确保训练和测试集中的少数类比例与原始数据一致 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, stratifyy, random_state42 ) # 标准化基于训练集fit然后transform测试集避免数据泄漏 scaler StandardScaler() X_train scaler.fit_transform(X_train) X_test scaler.transform(X_test) print(f训练集形状: {X_train.shape}, 少数类样本数: {np.sum(y_train 1)})这段代码里有两个细节值得注意。一是分层切分必须用stratifyy否则随机切分后测试集里少数类样本数可能只有十几个评估结果波动会大到无法信任。二是标准化必须只在训练集上fit在训练集和测试集上分别transform——如果对全量数据做标准化再切分测试集的信息就泄漏进了训练流程得出来的指标会高估真实效果。4.2 随机秩次kNN核心实现子采样、秩次计算与加权投票下面这段是算法的核心实现。为了清晰把整个流程拆成三个函数子采样与秩次计算、单轮投票、最终预测。from collections import Counter from scipy.stats import rankdata def rank_knn_predict(X_train, y_train, X_test, k10, r0.5, T50, w_minor1.5, random_state42): 随机秩次kNN分类器 参数说明: k: 每次子采样中参与投票的近邻数 r: 子采样比例决定每次随机采样训练集的比例 T: 随机化重复次数 w_minor: 少数类样本票数加权系数 rng np.random.RandomState(random_state) n_train X_train.shape[0] # 用int而不是round避免n_train*r0的极端情况 sample_size max(int(n_train * r), 1) predictions np.zeros(X_test.shape[0]) for i, x_test in enumerate(X_test): scores {} # 累加每个类别的加权票数 for _ in range(T): # 1. 随机子采样不放回抽取训练样本索引 sampled_idx rng.choice(n_train, sizesample_size, replaceFalse) x_sampled X_train[sampled_idx] y_sampled y_train[sampled_idx] # 2. 计算查询样本到子采样样本的欧氏距离 dist np.linalg.norm(x_sampled - x_test, axis1) # 3. 将距离转换成秩次最小距离秩次为1 ranks rankdata(dist).astype(float) # 4. 取出前k个近邻的索引、秩次和标签 top_k_idx np.argsort(ranks)[:k] top_k_ranks ranks[top_k_idx] top_k_labels y_sampled[top_k_idx] # 5. 秩次倒数加权投票1/rank作为票权少数类乘以加权系数 for rank, label in zip(top_k_ranks, top_k_labels): vote_weight 1.0 / rank if label 1: # 假设1是少数类标签 vote_weight * w_minor scores[label] scores.get(label, 0.0) vote_weight # 综合T轮投票结果票数高者获胜 # get(0, 0.0)处理某类别一票未得的情况 predictions[i] 1 if scores.get(1, 0.0) scores.get(0, 0.0) else 0 return predictions逻辑说明整个过程先在每轮随机采样一个小训练集对测试样本算距离、转秩次、取前k个加权投票T轮结果累加后比较两类的总加权票数判定类别。这里用秩次倒数作为权重是因为前k个邻居中排名第1的邻居应当比第15的邻居拥有更大话语权——这是对朴素多数投票的重要改进。scores.get(1, 0.0)这种写法是为了防止少数类某轮中完全没有进入前k的边界情况。参数说明k10是一个中庸的起始值适合1000样本规模的数据集r0.5表示每轮用一半训练样本计算秩次兼顾局部性和稳定性w_minor1.5是对少数类的显式补偿这个值需要根据少数类占比调节。如果你手头的类别比例是1:9而不是1:19w_minor可以降到1.2甚至设为1纯靠秩次结构区分。4.3 评估指标选型F1、G-mean与AUC的适用范围跑完预测必须先选对评估指标。在1000个样本、5%少数类率的数据集上准确率几乎没参考价值——全部预测为多数类都可以拿到95%的准确率但少数类一个都救不回来。常见的三个指标各有适用场景。F1-score尤其是少数类的F1在业务代价不明确时最常用。兼顾查准率和查全率F1高意味着算法在找出少数类和减少误报之间做了合理平衡。适合像欺诈检测这类少数类样本被误判的代价和漏判代价接近的场景。G-mean它是多数类召回率和少数类召回率的几何平均。计算方式是sqrt(recall_major * recall_minor)。G-mean的优点是数值对两类召回率的平衡性极度敏感——任何一类召回率掉到0G-mean都是0。它适合你不确定业务代价、但想确保两类分类效果都不差的场景。AUC不依赖决策阈值只衡量排序能力。在随机秩次kNN输出连续分数时最好用。特别适合你后续计划做阈值调优的情况先在测试集上算AUC判断模型是否有区分度再选阈值转化为具体分类结果。from sklearn.metrics import f1_score, roc_auc_score, recall_score, confusion_matrix # 预测 y_pred rank_knn_predict(X_train, y_train, X_test, k10, r0.5, T50, w_minor1.5) # 少数类类1的召回率、F1、G-mean和AUC rec_minor recall_score(y_test, y_pred, pos_label1) f1_minor f1_score(y_test, y_pred, pos_label1) tn, fp, fn, tp confusion_matrix(y_test, y_pred).ravel() rec_major tn / (tn fp) gmean (rec_major * rec_minor) ** 0.5 print(f少数类召回率: {rec_minor:.3f}) print(f少数类F1: {f1_minor:.3f}) print(fG-mean: {gmean:.3f})这里有一个常见误区直接用sklearn的f1_score不指定pos_label在二分类中默认以1为正类一般没问题。但如果你拿到的是多分类数据必须指定正类标签否则聚合方式会让结果失去参考意义。另外建议把confusion_matrix拆开来看四个值分别是真负、假正、假阴、真正——只看F1不看混淆矩阵你可能不知道自己为了提升少数类召回误报了多少多数类样本这部分代价在风控和医疗场景里同样很高。5. 复现与调参避坑五个高频踩坑点5.1 结果波动太大随机化带来的方差失控现象同一份代码同一份数据连续跑三次F1从0.45跳到0.62让人怀疑算法有效性。原因随机秩次的随机化次数T太低。T为个位数时子采样的随机性没有被平均掉另外r值过小会导致每轮采样的训练集窗口过窄个别轮的投票结果高度不稳定。解决先把T提到100以上r提到0.5以上再评估稳定情况。如果T100时波动依然明显别盲目继续加大T先检查是不是少数类样本量太少——少数类只有十几二十个样本时任何算法都会不稳定这时候要解决的是数据量问题不是算法参数问题。5.2 效果不如传统kNN加权系数w_minor需要调现象用随机秩次kNN跑出来F1比普通kNN还低甚至少数类召回率只有0.2。原因我把默认经验值带进了你的数据。w_minor1.5适合少数类占比约5%的数据但如果你的少数类占比是1%1.5的加权根本不够少数类票数即便加了权也无法超越多数类反之少数类占比到了15%以上w_minor还是1.5就可能误报暴涨。解决把w_minor从1.0到3.0按0.25步长网格搜索结合验证集F1选最优。网格搜索不是玄学是小样本下最可靠的办法。5.3 评估指标选错导致算法被冤枉现象代码跑通了准确率99%少数类F1只有0.1于是得出“随机秩次没用”的结论。原因这是典型的只看了准确率没看混淆矩阵。在一个1:99的数据集上全部预测为多数类的准确率就是99%准确率天然虚高。解决不要用准确率评估不平衡分类。用AUC看排序能力、用G-mean看两类平衡性、用少数类F1看落地效果。如果三项指标里有两项明显优于传统kNN方法就值得进一步优化而不是直接弃用。5.4 标准化时机错误导致数据泄漏现象训练时F1为0.6测试时直接掉到0.3。原因一个隐蔽的翻车点是先对全量数据做标准化再做切分导致测试集的信息均值、方差进入了训练流程。解决标准化的fit只允许发生在训练集上。代码里先fit再transform的顺序写错结果就会虚高。这类问题特别隐蔽因为它不影响程序运行只会让上线前后的效果对不上。5.5 与其他过采样方法对比时不公平现象用SMOTE过采样后的数据训练传统kNN得了0.7的F1原始数据上跑随机秩次只得了0.5于是觉得随机秩次不行。原因训练数据分布都不同对比没有意义。SMOTE生成的样本改变了原始数据的分布相当于用一种偏置替换另一种偏置。解决如果要公平对比至少分三组原始数据上的kNN、SMOTE数据上的kNN、原始数据上的随机秩次kNN。后两者对比才有参考价值才能看出是采样方法更优还是秩次规则本身更优。6. 进阶验证与混合策略用随机秩次kNN做基线的三个技巧随机秩次kNN的定位不只是单独跑一个算法它更适合作为一个稳重的基线方案然后再与其他策略结合。这里说三个我验证过有效且成本很低的进阶用法。第一个技巧是秩次方差诊断。随机秩次kNN每轮投完票后可以记录少数类的得分方差。如果某条样本的得分方差特别大说明它处于决策边缘预测结果高度不确定。把这些样本单独取出来做人工核查或二次判定能显著提升业务的精细化处理能力。这在传统kNN里做不到——它只给出硬分类结果不给出可靠性信号。第二个技巧是与SMOTE混合。做法是在SMOTE过采样后的数据上跑随机秩次kNN。我先声明这不改变随机秩次算法的基本逻辑只是改变了输入分布。效果通常比单独用SMOTE或单独用秩次规则更好因为两条路径补偿的是不同种类的偏置——SMOTE补偿数据密度秩次规则补偿距离度量的失真。第三个技巧是关于生产应用的取舍。如果只在离线批量场景做数据分析和风险打分随机秩次kNN的T50、r0.5跑完一批数据完全够用但如果你需要较快的单条预测建议用T20并预计算每种子采样的近邻结构或者直接退化为不加随机化的纯秩次kNN。牺牲一部分稳定性换取在线推理速度在这个方向上是可以接受的折中。最后说一个我自己的教训。早年我把这套方法直接拿去做一个样本量只有几百的医疗筛查任务因为少数类过少无论怎么调w_minor结果方差都压不住。后来我明白了一个事随机秩次解决的是密度和度量的问题解决不了数据量本身的问题。样本少到连交叉验证都撑不住时先做数据积累或引入外部知识别指望任何算法能凭空变出信息。想清楚这一点之后再用这套方法效果稳定了很多。希望帮到你。本文还有配套的精品资源点击获取
返回列表