1. 项目概述:为什么无监督学习不是“放任自流”,而是数据世界的探矿者

你手头有一堆没贴标签的客户行为日志,几万张未分类的工业零件图像,或者连续采集了三个月的传感器时序数据——没有“这是故障”“那是正常”的标注,连“好/坏”“高/低”“A/B/C类”这种最基础的提示都没有。这时候,有人告诉你:“用无监督学习试试。”你心里可能立刻浮现出两个疑问:第一,没标签怎么学?第二,学出来的东西到底靠不靠谱?

这正是我过去八年在制造业AI落地、金融风控建模和医疗影像预处理中反复被问到的问题。今天这篇内容,不讲教科书定义,也不堆砌数学公式,而是像带徒弟一样,把 14种真正能在产线、实验室和业务系统里跑起来的无监督算法 ,掰开揉碎讲清楚:它们各自在什么土壤里长势最好,为什么选它而不是隔壁那个,参数调错一格会掉进什么坑,以及——最关键的是,当你在Jupyter里敲下 fit() 那一行时,模型内部到底在干一件什么样的“体力活”。

核心关键词“无监督学习”“聚类”“异常检测”“降维”“生成模型”不是术语展览,而是四把不同形状的钥匙:一把开客户分群的门,一把拧开设备早期故障的螺丝,一把把100维的基因表达数据压成一张可画图的纸,一把让AI自己“编造”出符合真实分布的新样本。这篇文章适合三类人:刚学完K-Means但不知道该用肘部法则还是轮廓系数的新人;正在为某次模型上线后效果断崖下跌而熬夜查日志的工程师;还有那些被老板一句“你看看能不能从数据里挖点新东西”拍到肩膀上的技术负责人。我们不追求“最全”,只聚焦 实操中真正高频、稳定、有明确归因路径的14种方法 ——它们不是论文里的幻灯片,而是我亲手在37个真实项目里反复验证过的工具箱。

2. 算法选型逻辑:为什么不是“哪个热门选哪个”,而是“哪块石头挡路就用哪把锤子”

2.1 问题本质决定算法骨架:先问“你要解决什么”,再翻算法手册

很多人一上来就查“无监督学习算法排名”,结果在DBSCAN和HDBSCAN之间纠结三天,却忘了回看原始需求。在我经手的案例里, 90%的选型错误源于对问题本质的误判 。举个具体例子:去年帮一家电池厂做电芯老化分析,产线每天产出5000颗电芯,每颗测200个电压-时间点。工程师最初的需求是“把相似的老化曲线聚成几类”,听起来是标准聚类问题。但当我们把曲线拉出来一看,发现85%的曲线形态高度一致,只有不到2%的曲线在第120个采样点突然出现微小平台——这是典型的 局部异常模式 ,而非全局形态差异。如果硬上K-Means,强行分成5类,那2%的异常点会被稀释进某个大类里,彻底消失。最后我们改用 Isolation Forest + 时间序列动态时间规整(DTW)距离 ,异常检出率从37%飙升到92%。

这个案例揭示了一个铁律: 无监督任务必须先完成一次“问题解构” 。我习惯用三把尺子来量:

  • 空间尺度 :你的数据是点(如用户画像向量)、线(如心电图)、面(如卫星遥感图),还是体(如CT三维重建)?K-Means对点数据友好,但对时序线数据必须先做特征工程(如提取斜率、曲率、峰值数),否则距离计算完全失真。
  • 噪声容忍度 :产线传感器数据常带毛刺,金融交易日志有大量脏记录。DBSCAN能自动识别噪声点,而K-Means会强迫每个点归属某类,把噪声也当宝贝供起来。
  • 可解释性刚需 :给医院部署的肺结节筛查模型,医生必须知道“为什么这个结节被标为高危”。此时用t-SNE降维后人工圈定区域,比用VAE生成隐空间再聚类,临床接受度高出3倍——因为前者能回溯到原始CT切片位置,后者只能输出一个抽象坐标。

提示:别被“14种算法”的数字吓住。实际项目中,80%的场景由5种算法覆盖:K-Means(全局聚类)、DBSCAN(密度聚类)、PCA(线性降维)、t-SNE(非线性可视化)、Isolation Forest(异常检测)。剩下9种是应对特定地形的特种工具,比如处理文本用LDA,处理图结构用Node2Vec,处理多模态数据用CLIP-style对比学习——它们不是替代品,而是补丁。

2.2 算法能力光谱:同一目标,不同算法给出的答案为何天差地别

以“客户分群”为例,同样是把10万用户分成5组,不同算法输出的群体价值截然不同:

  • K-Means :强制球形簇,组内方差最小。适合收入、年龄、消费频次这类近似正态分布的指标。但若用户数据里混着大量零消费的沉默用户(占60%),K-Means会把他们全塞进一个“低价值簇”,而忽略其中可能存在的“高潜力休眠用户”(如刚毕业的学生,当前零消费但学历高、APP活跃度高)。
  • Gaussian Mixture Model (GMM) :允许椭球形簇,能拟合重叠分布。用EM算法迭代,输出每个用户属于各簇的概率。在上面的例子中,GMM能把“零消费但活跃度高”的用户识别为“高潜力休眠”概率0.72、“纯流失”概率0.28,给运营团队留出精准唤醒空间。
  • HDBSCAN :不预设簇数量,基于密度连接。当用户数据存在明显密度谷(如消费金额在500元和5000元之间断层),它会自动拆出“中产务实派”和“高净值享受派”两个簇,中间的断层区域标记为噪声——这反而暴露了产品定价的盲区。

这种差异的本质,在于 算法对“相似性”的定义不同 。K-Means用欧氏距离,GMM用概率密度,HDBSCAN用可达距离。就像用直尺、卷尺、激光测距仪量同一堵墙,结果都“对”,但适用场景完全不同。我在某电商大促前夜,曾用三种算法跑同一份用户数据,K-Means给出的“高价值用户包”转化率12%,GMM的概率加权包转化率18%,而HDBSCAN识别出的“密度边缘用户”(介于高/中价值之间的模糊地带)通过定向发券,转化率冲到23%——因为他们是最容易被临门一脚打动的人群。

2.3 工程落地成本:为什么有些算法写三行代码就能跑,有些要搭整个管道

学术论文里一个算法可能只占一页,但工程化时,它的“体重”可能翻十倍。以**Autoencoder(自编码器)**为例:

  • 理论描述:三层神经网络,输入=输出,中间层为瓶颈,训练目标是重构误差最小。
  • 实际落地:你需要处理缺失值(不能直接丢弃,否则时序断裂)、标准化(不同量纲指标如点击次数vs停留时长需分别缩放)、序列填充(用户行为长度不一,需统一pad或截断)、GPU显存管理(10万用户×200特征,batch_size设大了直接OOM)、重构损失选择(MSE对异常值敏感,Huber Loss更鲁棒)、瓶颈层维度确定(用PCA解释方差比例反推,而非拍脑袋定32维)……

相比之下, PCA 虽然古老,但工程极简: from sklearn.decomposition import PCA; pca = PCA(n_components=0.95); X_reduced = pca.fit_transform(X) 。0.95代表保留95%原始方差,一行参数搞定维度选择。我在某车载语音系统里,用PCA把128维MFCC特征压到20维,推理延迟从47ms降到12ms,准确率仅降0.3个百分点——这种“性价比”,是深度模型短期内难以超越的。

所以我的选型清单里永远有两列: 理论威力值 (解决复杂问题的能力)和 工程衰减系数 (从论文到API的损耗率)。当项目周期紧、数据质量一般、团队缺乏深度学习经验时,我会毫不犹豫把PCA、DBSCAN、Isolation Forest放在前三顺位。不是它们不够酷,而是它们把“可靠”刻进了基因里。

3. 14种核心算法详解:从原理内核到实操陷阱的完整链路

3.1 K-Means:最朴素的聚类,但90%的人没用对距离函数

K-Means的三步循环(初始化中心→分配点→更新中心)人人会背,但真正卡住项目的,永远是第一步: 如何定义“距离”

教科书默认欧氏距离,但在真实场景中,它常是灾难源头。比如处理用户地理位置数据:北京朝阳区和上海浦东新区的经纬度差值巨大,但用欧氏距离算,两个同在朝阳区的用户,可能因为一栋楼的GPS漂移(±50米),距离反而大于跨省用户。这时必须切换到 Haversine距离 (球面大圆距离)。代码只需两行:

from sklearn.metrics.pairwise import haversine_distances
# 注意:经纬度需转为弧度,且sklearn返回单位为弧度,需乘地球半径6371km
dist_matrix = haversine_distances(X_radians) * 6371

另一个致命误区是 k值选择 。肘部法则看SSE下降拐点?在客户分群中,我见过太多次“肘部”出现在k=2到k=3之间,但业务上必须分5类(对应5种运营策略)。这时轮廓系数(Silhouette Score)更实用:它衡量每个点与自身簇的紧密度 vs 与其他簇的分离度,取值[-1,1],越接近1越好。但要注意,当簇大小差异极大时(如95%用户在A簇,5%在B簇),轮廓系数会被A簇主导,掩盖B簇的内部质量。我的补救方案是: 分层评估 ——先用轮廓系数选k,再对每个簇单独计算Davies-Bouldin指数(簇内散度/簇间距离),确保小簇也有合理结构。

实操心得:K-Means对异常值极度敏感。某次处理物流时效数据,一个录入错误的“1000小时送达”样本,直接把整个“超快配送”簇中心拉偏。解决方案不是删数据,而是 用RobustScaler替代StandardScaler ——它用中位数和四分位距缩放,对离群值免疫。代码: from sklearn.preprocessing import RobustScaler; scaler = RobustScaler(); X_scaled = scaler.fit_transform(X)

3.2 DBSCAN:密度聚类的王者,但min_samples和eps的设定是玄学?

DBSCAN的两个参数 eps (邻域半径)和 min_samples (核心点最小邻居数)常被说成“调参靠感觉”。其实有迹可循。关键洞察在于: eps 不是距离阈值,而是“局部密度”的探测器

我的标准流程分三步:

  1. 计算k-距离图 :对每个点,找它第k近的邻居,k设为 min_samples (通常取 len(X.columns)+1 ,如5维数据取6)。所有点的第k近邻距离排序后画图,拐点处的距离即为 eps 候选值。Scikit-learn没内置此功能,但用 NearestNeighbors 三行搞定:
from sklearn.neighbors import NearestNeighbors
nn = NearestNeighbors(n_neighbors=6).fit(X)
distances, indices = nn.kneighbors(X)
distances_sorted = np.sort(distances[:, -1], axis=0)
plt.plot(distances_sorted)  # 拐点即eps
  1. min_samples 定生死 :它决定“多稀疏才算噪声”。在用户行为数据中,若 min_samples=5 ,意味着至少5个用户行为模式高度相似才构成簇。但若数据噪声大(如爬虫流量混入), min_samples 太小会让噪声点抱团成伪簇。我的经验是: min_samples ≥ 数据维度 × 2 ,高维数据(如100维文本向量)必须设≥200,否则DBSCAN退化为“找最近邻”。
  2. 距离度量必校准 :DBSCAN默认欧氏距离,但对混合类型数据(数值+类别)无效。例如用户数据含“城市等级(一线/新一线/二线)”和“月均消费(数值)”,需用 Gower距离 。我用 gower 库: from gower import gower_matrix; dist_matrix = gower_matrix(X) ,再传入DBSCAN的 metric='precomputed'

注意:DBSCAN不保证所有点都有标签。 labels_ 数组中-1代表噪声点——这不是失败,而是算法在说“这堆数据太杂,我拒绝强行归类”。某次在工厂设备振动分析中,-1点集中出现在凌晨2-4点,人工核查发现是维护人员巡检时的误触,这反而帮客户发现了运维流程漏洞。

3.3 主成分分析(PCA):降维界的“老黄牛”,但别让它替你做特征工程

PCA的数学本质是找数据方差最大的正交方向,但工程师常犯两个错:

  • 错把PCA当万能清洗器 :PCA能去噪,但前提是噪声在低方差方向。若噪声与信号同方向(如传感器随机漂移叠加在趋势线上),PCA会把信号也滤掉。某次处理风电功率预测数据,直接PCA降维后,模型R²从0.82暴跌到0.41。根源是风速传感器漂移与功率趋势强相关。解决方案: 先用小波变换分解趋势/周期/噪声分量,再对趋势分量PCA
  • 忽略重建误差的业务含义 :保留95%方差看似安全,但若丢失的5%恰好是故障前兆的微弱谐波,后果严重。我的做法是: 按业务目标反推 。比如轴承故障诊断,关注2kHz以上频段,就用FFT转换后,对高频段单独做PCA,确保其方差保留率≥99%。

代码层面有个隐藏坑: sklearn.PCA components_ 是主成分向量,但 原始特征重要性不能直接看绝对值 。因为主成分是线性组合,单个特征权重受量纲影响。正确做法是计算 每个原始特征对前n个主成分的贡献总和

pca = PCA(n_components=10)
X_pca = pca.fit_transform(X)
# 计算各特征贡献度
contributions = np.abs(pca.components_).sum(axis=0)  # 对每个特征,求其在10个主成分中的权重绝对值和
feature_importance = pd.Series(contributions, index=X.columns).sort_values(ascending=False)

这比单纯看 pca.explained_variance_ratio_ 更能指导特征采集——比如发现“电机电流谐波畸变率”贡献度最高,就推动产线加装高精度电流传感器。

3.4 t-SNE:可视化神器,但别用它做聚类依据

t-SNE能把100维数据压到2D并保持局部相似性,效果惊艳。但它的致命缺陷是: 全局结构失真 。两个簇在t-SNE图上看着很远,实际高维空间中可能只隔一个标准差。

我坚持一条铁律: t-SNE只用于探索性分析,绝不用于下游任务 。某次在医疗影像项目中,团队用t-SNE降维后K-Means聚类,发现“恶性肿瘤”样本聚成一团,兴奋地以为找到新亚型。但当用原始高维特征训练SVM时,该“亚型”的预测准确率仅58%。复盘发现:t-SNE为突出局部差异,压缩了簇间距离,制造了虚假分离。

正确用法是“三明治流程”:

  1. 用PCA粗降维(如100维→10维),保留大部分全局结构;
  2. 在PCA结果上跑t-SNE(10维→2维),此时计算量小,失真可控;
  3. 在t-SNE图上圈定区域后,回到PCA空间提取对应样本,再用这些样本训练正式模型

参数调优上, perplexity (困惑度)常被神化。其实它约等于“每个点考虑的邻居数”。我的经验值:数据量<1000,perplexity=5~10;1000~10000,取30~50;>10000,取50~100。超过100反而让图变得模糊——就像用广角镜头拍人群,边缘人脸全变形。

3.5 Isolation Forest:异常检测的“快刀手”,但它的“孤立”逻辑常被误解

Isolation Forest(iForest)不学正常模式,而是学“怎么快速孤立异常点”。核心思想:异常点是少数、不同、易隔离的,所以用随机超平面切割时,它们会被更少的切割次数就分出来。

但很多人误以为“分数越低越异常”,其实 decision_function 输出的是 异常程度得分,正值为异常,负值为正常 。更关键的是: iForest对训练数据分布极其敏感 。某次在银行反欺诈中,用历史正常交易训练iForest,上线后对新型羊毛党(模拟正常用户行为)检出率仅22%。原因在于:iForest的随机树切割,依赖训练数据的范围。新型羊毛党虽行为异常,但其特征值(如单日交易笔数)仍在历史正常范围内,导致切割树无法有效区分。

解决方案是 动态基线 :不固定训练集,而是用滑动窗口(如最近30天交易)实时训练iForest,并设置双阈值——

  • score > 0.5 :高置信异常,立即拦截;
  • 0.2 < score ≤ 0.5 :可疑,进入人工审核队列;
  • score ≤ 0.2 :正常。

这样既避免漏报,又控制误报率。代码实现时注意: n_estimators (树数量)不宜过多,50~100足够; max_samples 设为 'auto' (自动取min(256, n_samples)),防止小数据集过拟合。

3.6 高斯混合模型(GMM):概率聚类的“精算师”,但协方差矩阵选型是灵魂

GMM比K-Means多一层概率思维:每个点属于各簇的概率之和为1。但它的威力取决于 协方差矩阵的约束方式

  • covariance_type='full' :每个簇有自己的全协方差矩阵,最灵活,但参数最多,易过拟合;
  • 'tied' :所有簇共享同一协方差矩阵,适合簇形状相似的场景;
  • 'diag' :协方差矩阵为对角阵,假设特征间独立,计算快,适合高维稀疏数据;
  • 'spherical' :协方差为标量,等价于K-Means的球形假设。

我在某推荐系统中处理用户兴趣向量(50维),初始用 'full' ,AIC(赤池信息量准则)评分很高,但线上AB测试CTR下降。查原因发现: 'full' 过度拟合了训练集中的噪声关联(如“看科幻片”和“买咖啡”在样本中偶然共现),导致推荐泛化差。换成 'diag' 后,AIC略升,但CTR提升11%——因为模型被迫忽略虚假特征关联,专注单特征强度。

GMM的另一个优势是 天然支持增量学习 sklearn.mixture.BayesianGaussianMixture 可用 partial_fit ,适合流式数据。某物联网平台用它实时聚类设备状态,每分钟接收10万条心跳数据,无需全量重训,内存占用稳定在200MB内。

3.7 层次聚类(Agglomerative Clustering):可解释性最强的聚类,但距离度量是命门

层次聚类不预设簇数,输出树状图(dendrogram),业务人员能直观看到“哪些客户在什么相似度下合并”。但它的距离度量常被忽视。

默认 linkage='ward' 要求欧氏距离,且 对异常值零容忍 。某次处理销售区域数据,一个偏远县的GDP和人口数据录入错误(GDP写成1000亿,实际100亿), ward 聚类直接把该县和所有一线城市捆成一簇——因为ward最小化簇内平方和,错误数据把平方和拉得极高,算法“妥协”把它和高值城市配对。

解决方案: linkage='average' 'complete' ,并用曼哈顿距离 。曼哈顿距离对量纲变化不敏感, average 链接基于簇间平均距离,抗噪性强。代码:

from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics.pairwise import manhattan_distances
dist_matrix = manhattan_distances(X)
clustering = AgglomerativeClustering(
    n_clusters=5,
    metric='precomputed',
    linkage='average'
).fit(dist_matrix)

树状图解读技巧:横轴是合并顺序,纵轴是距离。若某次合并距离远高于前几次(如前10次距离<5,第11次跳到50),说明这两簇本不该合并——这就是业务上“强行归类”的警示信号。

3.8 自编码器(Autoencoder):深度降维的“黑盒”,但瓶颈层设计决定成败

Autoencoder的结构简单:编码器压缩→瓶颈层→解码器还原。但工程难点在瓶颈层:

  • 维度不是越小越好 :某次处理卫星图像(256×256×3),瓶颈设32维,重构图像全是色块。后来发现, 瓶颈维度应与数据的信息熵匹配 。用PCA先估算:若PCA保留95%方差需128维,则Autoencoder瓶颈至少128维。
  • 激活函数选择 :ReLU在瓶颈层易产生“死神经元”(输出恒为0),导致信息丢失。改用LeakyReLU( alpha=0.1 )或ELU,保留下限梯度。
  • 损失函数陷阱 :MSE损失让模型专注像素级还原,忽略语义。处理医学图像时,改用 感知损失(Perceptual Loss) :用预训练VGG网络提取特征,计算特征图的MSE。代码需自定义loss:
def perceptual_loss(y_true, y_pred):
    vgg = VGG16(include_top=False, weights='imagenet')
    # 取block3_conv3层特征
    feature_extractor = Model(inputs=vgg.input, outputs=vgg.get_layer('block3_conv3').output)
    true_features = feature_extractor(y_true)
    pred_features = feature_extractor(y_pred)
    return tf.keras.losses.mse(true_features, pred_features)

这能让重构图像在器官结构上更准确,哪怕像素略有偏差。

3.9 隐狄利克雷分布(LDA):文本主题的“考古学家”,但超参α和β的物理意义必须吃透

LDA将文档视为主题混合,主题视为词混合。但 alpha (文档-主题分布的先验)和 beta (主题-词分布的先验)常被当成调参数字。

  • alpha 小(如0.1):鼓励文档只含少数主题,适合新闻分类(一篇报道通常聚焦1-2件事);
  • alpha 大(如1.0):文档主题分布更均匀,适合百科全书条目(涵盖多方面知识)。

beta 同理: beta 小(0.01)让主题更专一(如“量子”主题只含“叠加”“纠缠”“坍缩”), beta 大(0.1)让主题更泛(“量子”主题混入“物理”“实验”“理论”)。

我的实操技巧: 用Coherence Score(一致性得分)代替困惑度 。困惑度衡量预测能力,但一致性得分(如UMass)计算主题内高频词的共现概率,更贴近人类对“主题是否合理”的判断。 gensim 库一键计算:

from gensim.models import CoherenceModel
coherence_model = CoherenceModel(model=lda_model, texts=tokenized_docs, dictionary=dictionary, coherence='u_mass')
coherence_score = coherence_model.get_coherence()

某次分析客服对话, beta=0.01 时“退款”主题含“快递”“破损”“拒收”, beta=0.1 时混入“好评”“感谢”“下次还来”——后者显然违背业务逻辑,一致性得分也低0.15。

3.10 局部离群因子(LOF):密度异常检测的“显微镜”,但邻居数k的选择有讲究

LOF通过比较点与其邻居的局部密度,识别密度显著低于邻居的点。但 n_neighbors (邻居数)设定不当,效果天壤之别。

  • n_neighbors 太小(如5):只看最近邻,易受噪声干扰,把正常波动当异常;
  • n_neighbors 太大(如100):邻居包含异质点,局部密度被稀释,异常点淹没。

我的黄金法则是: n_neighbors ≈ 数据集大小的平方根 。如10万样本,取316;同时设置 contamination=0.1 (预估异常比例),让LOF自动调整阈值。

更关键的是: LOF对距离度量极度敏感 。处理地理数据时,用欧氏距离算经纬度,结果荒谬。必须用Haversine距离,且 sklearn 不支持,需自定义:

from sklearn.neighbors import LocalOutlierFactor
from sklearn.metrics.pairwise import pairwise_distances
# 先计算haversine距离矩阵
dist_matrix = haversine_distances(X_radians) * 6371
# 用precomputed距离矩阵
lof = LocalOutlierFactor(
    n_neighbors=20,
    metric='precomputed',
    contamination=0.05
)
outlier_labels = lof.fit_predict(dist_matrix)  # -1为异常

某次物流路径优化中,LOF用Haversine距离揪出3个“幽灵网点”——GPS坐标在太平洋中央,是数据录入错误。

3.11 UMAP:t-SNE的强力竞品,但它的“连接性”哲学改变游戏规则

UMAP(Uniform Manifold Approximation and Projection)近年大热,它不像t-SNE只保局部,而是 同时优化局部和全局结构 。核心是构建高维空间的k近邻图,再在低维空间重建该图的拓扑连接。

参数 n_neighbors 控制局部性:值小(如5)强调局部细节,适合找子簇;值大(如50)增强全局结构,适合看大类分布。 min_dist (低维空间最小距离)控制簇间分离度:0.1让簇紧凑,0.5让簇分散便于观察。

我的UMAP实战口诀:

  • 先用PCA初筛 :UMAP对高维噪声敏感,100维数据直接UMAP,结果常是乱麻。先PCA到10-20维,再UMAP到2D,效果稳如磐石。
  • 距离度量必匹配 :处理基因表达数据(高维稀疏),用余弦距离;处理图像特征,用欧氏距离。 umap.UMAP(metric='cosine')
  • 别迷信2D可视化 :UMAP的2D图是投影,真正的结构在更高维。某次用UMAP降维到5维后,用HDBSCAN聚类,效果比2D图上肉眼圈选好3倍——因为5维空间保留了更多判别信息。

3.12 谱聚类(Spectral Clustering):图结构数据的“翻译官”,但相似度矩阵构造是艺术

谱聚类把数据看作图,节点是样本,边权是相似度。它的威力全在 相似度矩阵W的构造

常用高斯核: W_ij = exp(-||x_i - x_j||² / σ²) 。但 σ (带宽)选错,全盘皆输。 σ 太大,所有点相似度趋近1,图变成全连接; σ 太小,图稀疏断裂。我的解法是: 用k近邻图替代全连接 ——只保留每个点的k个最近邻,边权为高斯核,其余为0。 sklearn 原生支持:

from sklearn.cluster import SpectralClustering
clustering = SpectralClustering(
    n_clusters=5,
    affinity='nearest_neighbors',  # 关键!
    n_neighbors=10,
    assign_labels='discretize'
).fit(X)

这避免了 σ 调参,且k近邻图天然抗噪。某次处理社交网络关系,用k近邻谱聚类,社区发现准确率比全连接高27%,因为全连接把弱关系(如偶然点赞)当成了强连接。

3.13 变分自编码器(VAE):生成式无监督的“造物主”,但KL散度权重需动态调节

VAE在Autoencoder基础上加了概率约束:编码器输出均值μ和方差σ²,再用重参数化采样z=μ+ε·σ。损失函数含两部分:重构损失 + KL散度(拉近q(z|x)和p(z))。

但KL散度权重常设为1,导致 训练早期KL项主导,模型放弃重构,只学标准正态分布 。我的解决方案: KL权重β从0开始,随epoch线性增加到1 (β-VAE)。代码:

class BetaVAE(tf.keras.Model):
    def train_step(self, data):
        with tf.GradientTape() as tape:
            z_mean, z_log_var, z = self.encoder(data)
            reconstruction = self.decoder(z)
            # 重构损失
            recon_loss = tf.keras.losses.mse(data, reconstruction)
            # KL散度,加权重beta
            kl_loss = -0.5 * tf.reduce_mean(1 + z_log_var - tf.square(z_mean) - tf.exp(z_log_var))
            total_loss = recon_loss + self.beta * kl_loss
        gradients = tape.gradient(total_loss, self.trainable_variables)
        self.optimizer.apply_gradients(zip(gradients, self.trainable_variables))
        return {"recon_loss": recon_loss, "kl_loss": kl_loss}

self.beta 在训练循环中动态更新。某次生成工业缺陷图像,β从0线性增至1,生成图像从模糊色块变为清晰裂纹纹理,FID(Fréchet Inception Distance)分数降低40%。

3.14 密度峰值聚类(DPC):小样本聚类的“狙击手”,但截断距离dc需领域知识

DPC算法假设:簇中心是密度高且距离其他高密度点远的点。它需要计算每个点的局部密度ρ和距离δ,再画ρ-δ图找“右上角”点。

dc (截断距离)决定ρ的计算范围,选错则全盘失效。 dc 不是超参,而是 需根据数据分布确定的物理量 。我的做法:

  • 计算所有点对距离,取前2%大的距离作为 dc 候选;
  • 对每个候选 dc ,计算ρ的分布直方图,选使ρ分布最平滑(方差最小)的 dc

代码精简版:

def find_optimal_dc(distances, percentile=2):
    # distances是距离矩阵上三角
    dc_candidates = np.percentile(distances, [98, 99, 99.5, 99.9])
    best_dc = dc_candidates[0]
    min_variance = float('inf')
    for dc in dc_candidates:
        rho = np.sum(distances < dc, axis=1)  # 每个点的局部密度
        variance = np.var(rho)
        if variance < min_variance:
            min_variance = variance
            best_dc = dc
    return best_dc

某次处理航天器遥测数据(仅200个样本),DPC比K-Means更准识别出3个故障模式,因为它的ρ-δ图能直观显示“哪些点是真正的簇中心”。

4. 实战避坑指南:14个算法在真实战场上的血泪教训

4.1 数据预处理:90%的失败,始于没搞懂“标准化”和“归一化”的生死线

新手常混淆 StandardScaler (Z-score标准化)和 MinMaxScaler (归一化到[0,1])。它们的适用场景有本质区别:

  • StandardScaler :假设数据近似正态分布,用均值和标准差缩放。适合K-Means、PCA、GMM等依赖距离/方差的算法。但若数据含大量离群值(如用户消费金额,95%<1000元,5%>10万元),均值和标准差被拉偏,缩放后正常点挤在-0.5~0.5,异常点飞到10以上,K-Means直接崩溃。
  • MinMaxScaler :用最小最大值缩放,对离群值敏感,但能保证所有值在[0,1]。适合神经网络(如Autoencoder),因为sigmoid/tanh激活函数在[0,1]外梯度极小。

我的铁律: 先用 RobustScaler (中位数+四分位距)做初筛 。它对离群值免疫,缩放后看数据分布

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐