news 2026/9/9 17:29:30

平衡谱特征选择:无监督降维中如何兼顾流形结构与判别信息

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
平衡谱特征选择:无监督降维中如何兼顾流形结构与判别信息

搞无监督特征选择的人,应该都听过“谱方法”这个词。但大多数项目里,大家默认用的还是方差过滤、相关性分析、卡方检验这些最朴素的方案,总觉得谱特征选择门槛高、调参麻烦、收益不透明。直到我认真看了TCYB-2022上的这篇《Balanced Spectral Feature Selection》,才意识到问题不在于谱方法不行,而在于很多经典谱方法只解决了一半问题——它们在努力拟合局部图结构,却牺牲了对判别信息的保留。所谓“Balanced”,就是要把这两件事摆到同一个目标函数里去平衡,而不是让某一方主导。

这篇文章想解决的场景很明确:当你要从几百上千个特征里挑出一部分,用来做聚类、可视化、或者给下游模型降维时,传统的谱特征选择方法往往选出的特征高度相似,甚至把无用但平滑的特征排在前面。Balanced Spectral Feature Selection的思路,是在谱嵌入框架里同时约束局部流形结构和全局判别能力,用行稀疏化的方式让最终选出的特征既保留图结构,又不过度冗余。对做数据预处理、特征工程、无监督学习的同学来说,这个方法是一个值得认真落地的备选方案。

下面我会先从原理层面拆解它的动机,再给出一条我自己复现过、跑通了的完整链路,最后重点讲实验里那些文章不会写但实际一定会踩的坑。

1. 为什么“平衡”两个字值得单独拿出来聊

1.1 无监督特征选择里的“谱”到底在谱什么

要理解Balanced Spectral Feature Selection,得先回到谱特征选择的基本逻辑。我们手里有一批样本,每个样本有高维特征。没有标签的情况下,怎么判断哪些特征重要?一个经典假设是:数据在低维空间里是有结构的,相近的样本在原始特征空间里也应该相近。谱方法做的事情,就是先根据样本之间的相似度构建一个图,然后用图拉普拉斯去刻画特征在这个图上的光滑程度。

具体来说,我们会为每个特征计算它在图上的“拉普拉斯分数”,分数越低,说明这个特征在相邻样本之间变化越平缓,也就是越符合流形假设。Laplacian Score是这个思路的代表,也是入门必看的方法。它很直观,但局限也很明显:它只看单个特征与图的一致性,完全不考虑特征之间的冗余,更不考虑多特征组合起来是否能区分不同的簇。于是后续有了SPEC、UDFS、NDFS等改进,试图把谱信息嵌入和稀疏学习结合起来。

但这里有个裂缝:很多方法在构造目标函数时,把“拟合图嵌入”当成唯一目标,结果就是选出来的特征在局部很平滑,却可能在全局上毫无区分度。举个极端例子,所有样本在某个特征上的取值都近似等于一个常数,这个特征在图上的拉普拉斯分数会很低,因为它均匀得离谱,但它对聚类毫无价值。单纯追求图平滑,就会选出这种“漂亮但没用”的特征。

1.2 经典方法只做了一半

我早期用Laplacian Score做过一个电商用户分群项目,特征有四百多个,里面有大量用户活跃天、访问频次这类分布极度偏斜的字段。跑完拉普拉斯分数,排在最前面的几乎全是稀疏到接近常数的风控标记字段,唯一的作用就是它们在图里特别“平整”。但真正能区分用户消费偏好的字段,全都沉在榜单中间。这个例子让我很受触动——谱方法对图结构的尊重确实很强,但“平滑”不代表“有用”。

后来的UDFS在拉普拉斯项之外加入了Frobenius范数损失,让特征选择矩阵同时学到判别投影;NDFS则把聚类和特征选择放进同一个框架,迭代更新聚类标签和特征选择矩阵。思路方向对了,但代价是模型复杂度明显上升,尤其是聚类标签初始化和特征选择矩阵迭代都容易掉进局部最优。而且这些方法在目标函数里,图拟合项和判别项通常是加性组合,权重完全靠经验调,结果要么还是偏向图结构,要么判别项喧宾夺主,把流形信息毁了。

1.3 把“平衡”拆开看:结构保持、判别能力、冗余控制

Balanced Spectral Feature Selection说的“平衡”,我理解下来至少包含三个层面。

第一是局部与全局的平衡。局部看样本邻居关系,全局看簇间分离程度。目标函数里不能只有图拉普拉斯平方和,也要有嵌入空间里类间散度的约束。第二是相关性与互补性的平衡。特征选择切忌只看单特征得分,两个特征单独看都很强,放一起几乎是同一个信息,那选一个就够了。目标函数需要用特征选择矩阵的行范数惩罚来控制冗余,因为行范数大意味着这个特征对多个维度都有贡献,自然更可能承载多样性信息。第三是结构复杂度和可解释性的平衡。方法不能为了效果把图嵌入维度搞得和特征数一样高,那样计算量大到工程上不可用,而且选出来的特征缺乏稳定性。

这三层平衡,恰恰是TCYB-2022这篇论文最核心的贡献。它不是第一个提出谱特征选择的论文,但它把“平衡”这个容易被忽视的细节拿到了台面上,用可求解的优化形式把三个目标拧在一起。

2. 从TCYB论文中提取的核心建模逻辑

2.1 图构建与邻域阈值

我把论文思路落地时,首先处理的是图构建。这一步听起来简单,实际有很大操作空间。经典做法是用k近邻或ε近邻构建无向加权图,权重用热核函数计算:

( S_{ij} = \exp(-||x_i - x_j||^2 / \sigma) )

但这里有个关键细节:特征选择时用的样本距离,是在原始高维空间里算的,可高维空间的距离有意义的前提是特征尺度一致。如果特征量纲不统一,欧氏距离会被量纲大的特征主导,整个图就废了。所以实际工程里,要先做标准化,再做距离计算,再去构建图。文本场景还要考虑用余弦距离;图像特征则常用欧氏距离配合白化预处理。

邻域大小k的选择也直接影响后续平衡效果。k太小,图可能断成多个连通分量,拉普拉斯矩阵出现多个零特征值,优化时特征向量不稳定;k太大,图的局部性消失,流形结构被过度平滑,Balanced方法里“局部”这一项就形同虚设。我在不同数据集上的经验:样本量在几千到一万时,k取5到15之间比较合理;样本量很大时,k可以适当放大,但不要超过ln(n)的2到3倍。

2.2 目标函数如何同时容纳局部与全局信息

论文的目标函数整体上可以看成这样一个优化问题:给定特征矩阵 (X \in \mathbb{R}^{n \times d})和图拉普拉斯矩阵 (L \in \mathbb{R}^{n \times n}),我们想找一个特征选择矩阵 (W \in \mathbb{R}^{d \times c}),以及一个嵌入表示 (Y \in \mathbb{R}^{n \times c}),然后最小化:

[ \mathcal{L} = \alpha \cdot Tr(Y^T L Y) + ||Y - X W||F^2 + \beta \cdot ||W||{2,1} + \gamma \cdot \text{Disc}(Y) ]

几个项的作用分别是:

  • (Tr(Y^T L Y)):让嵌入表示Y在图上尽量平滑。Y是样本的低维表示,如果两个样本在图中是邻居,它们的Y表示差异应该小。这一项把流形结构带进了学习。
  • (||Y - X W||_F^2):要求低维嵌入Y可以被原始特征X的线性组合近似。这一步很关键,它逼迫特征选择矩阵W去重建能被图结构认可的表示,而不是单纯去拟合图。
  • (||W||_{2,1}):行稀疏正则。W的每一行对应一个特征的全部维度。行范数小意味着这个特征对重建嵌入贡献微弱,最终会被淘汰;行范数大的特征被保留。这样就把“选哪些特征”变成了“哪些行比较大”的自然结果。
  • (\text{Disc}(Y)):判别项,鼓励样本的嵌入表示在不同簇之间更加分离。实际实现中,可以用谱聚类得到的簇标签来构造类间散度矩阵,或者用核化类间距离。

这里的关键设计是:Y和W是交替优化的。初始化Y时,通常用拉普拉斯矩阵的广义特征分解求出前c个特征向量,作为嵌入的初值。后面固定Y,对W求解一个带L2,1正则的线性回归;再用更新过的W去构造新的相似度或更新Y。如此反复,直到收敛。

2.3 求解过程中的数值稳定性处理

直接套用这个目标函数,数值上是很容易出问题的。一是拉普拉斯矩阵的特征分解,L可能是半正定的大规模稀疏矩阵,求前c个广义特征向量时,如果直接拿numpy求全部特征值,内存直接爆炸。正确做法是用ARPACK或LOBPCG这类稀疏特征求解器,只求最小的k个特征值及对应向量。二是W的L2,1范数在原点不可导,单纯用梯度下降会遇到数值抖动,工程上更稳妥的方式是写成迭代重加权最小二乘:每次更新时给W的每一行一个权重,权重等于该行范数的倒数加一个小常数,然后转成加权的岭回归求解。虽然多几次迭代,但每次都是线性闭式解,整体非常稳。

我有一段时间直接用现成ADMM库去解,PyADMM性能不太行,大矩阵上迭代几百轮,时间完全不可接受。后来改回“重加权最小二乘+稀疏特征分解”的组合拳,效果和速度都立刻对味了。这也印证了一个经验:做特征选择这种底层模块,尽量别把自己的效率绑架在通用优化库上,针对问题结构手写迭代往往更实用。

3. 一条能自己动手复现的算法链路

3.1 从零开始的核心代码骨架

下面是我整理的一份最小可复现的代码骨架,去掉了论文里一些花哨的变体,保留了平衡谱特征选择的骨架。用协方差矩阵和邻接图模拟,方便大家直接跑通。

import numpy as np from scipy.sparse.csgraph import laplacian from sklearn.neighbors import kneighbors_graph from scipy.sparse.linalg import eigsh def balanced_spectral_selection(X, k=5, c=2, alpha=1.0, beta=1.0, max_iter=30, tol=1e-4): n, d = X.shape # 标准化提到最前面 X = (X - X.mean(axis=0)) / (X.std(axis=0) + 1e-8) # 1. 构建k近邻图 + 热核权重 graph = kneighbors_graph(X, n_neighbors=k, mode='connectivity', include_self=False) graph = 0.5 * (graph + graph.T) # 对称化 # 简单热核 from sklearn.metrics import pairwise_distances dist = pairwise_distances(X) knn = graph.toarray() S = np.exp(-dist**2 / (np.median(dist[dist > 0])**2)) * (knn > 0) S = np.maximum(S, S.T) L = laplacian(S, normed=True) # 2. 初始化Y:拉普拉斯前c个特征向量 evals, evecs = eigsh(L, k=c, which='SM', maxiter=1000) Y = evecs[:, :c] W = np.zeros((d, c)) # 3. 交替迭代 for it in range(max_iter): # 固定Y,解带L2,1正则的线性回归 # 先计算行权重矩阵D_w row_norms = np.linalg.norm(W, axis=1) + 1e-6 D_w = np.diag(1.0 / (2.0 * row_norms)) # 岭回归闭式解 W_new = np.linalg.solve(X.T @ X + beta * D_w + 1e-4 * np.eye(d), X.T @ Y) # 固定W,更新Y,这里用谱回归近似 Y_new = X @ W_new # 可选:Y做一次图平滑 Y_new = np.linalg.solve(np.eye(n) + alpha * L, Y_new) if np.linalg.norm(Y_new - Y, 'fro') < tol * np.linalg.norm(Y, 'fro'): W = W_new Y = Y_new break W, Y = W_new, Y_new feature_score = np.linalg.norm(W, axis=1) rank = np.argsort(feature_score)[::-1] return rank, feature_score

这个骨架省略了判别项,但已经比单纯Laplacian Score多了一个联合优化环节。如果你想加入判别项,可以在Y更新之后,对Y做一次k-means得到伪标签,再计算类间散度,叠加到Y的更新里。注意迭代次数别太多,否则容易过拟合到初始化标签上。

3.2 数据集与基线选择

我在复现时用了三类数据。一类是UCI的Wine、Ionosphere,样本量小,特征中等,适合快速验证逻辑正确性;一类是MNIST的784维像素特征,用来测高维时的稳定性;还有一类是20Newsgroups的文本TF-IDF矩阵,维度破万,用来检验行稀疏正则在大规模场景下是否还靠谱。

基线一定要放Laplacian Score和无监督判别特征选择。因为Balanced方法本质上是对这两类的整合,如果跑不过这两个基线,说明你的实现平衡没调好,而不是方法本身有问题。另外,方差过滤和完全随机选择也值得放进来,它们能给你一个“地板”参考。我在多个数据集上都发现一个现象:特征维度特别高时,很多谱方法的上限只比随机选择高几个点,Balanced方法能看到明显的提升,但这个提升需要用可靠的评价指标来度量。

3.3 聚类效果怎么衡量才公平

特征选择没有标签,怎么判断好坏?最常用的是选出一批特征后,在这个特征子集上做聚类,然后和真实标签比较。但这里有个大坑:聚类算法本身有随机性,k-means的初始点不同,跑出来的NMI完全不一样。我一开始只跑一次k-means,某次实验中Balanced方法的NMI忽高忽低,差点得出错误结论。后来我改成固定随机种子,重复20次聚类取中位数,才看到相对稳定的提升。

更有说服力的做法是结合下游任务。比如用选出的特征训练一个监督分类器,虽然特征选择时没用标签,但最终评价可以用分类准确率来判断“这组特征有没有保留判别信息”。文本场景我习惯用SVM,图像场景用简单的逻辑回归。这个“无监督选择+监督验证”的组合,在跟业务方沟通时特别好使,因为NMI这种指标很难讲清业务价值,分类准确率却谁都能听懂。

4. 实验里最容易翻车的几个细节

4.1 图的尺度参数到底怎么定

这是最让我头疼的环节。热核参数σ如果设置太大,所有权重都趋近于1,图太平滑;设置太小,只有距离非常近的点才有连接,流形结构碎成一地。论文里通常会说“根据经验调参”,但这句经验对不同数据集根本不好使。

我后面的做法是:先计算样本间的成对距离,取所有非零距离的中位数作为σ的基准,再用α倍中位数做网格搜索,α从0.2到3.0。更重要的是观察选出来特征的稳定性,如果相邻α值对应的特征重合度只有百分之五六十,说明σ这个位置太敏感,需要重新预处理数据;如果特征重合度稳定在八成以上,那这个σ就是可信的。

另一个容易忽略的点是:构建图之前一定要对特征做标准化,但如果你做的是文本TF-IDF,标准化又可能破坏稀疏结构。文本场景我更倾向于先做L2行归一化,再用余弦距离转成相似度。一句话总结,图构建的预处理方法对结果的影响,比目标函数里α、β的影响大得多,务必花时间先定它。

4.2 特征选择比例与嵌入维度的耦合问题

Bravo,这里有个很少有人讲清楚的关系:你再怎么调平衡项,特征选择比例m和嵌入维度c如果配比不对,结果照样崩。我的经验是,嵌入维度c代表你希望保留多少个“结构方向”,而选择的特征数量m至少要能撑起这几个方向。如果c=10,却只选5个特征,那么总会有方向找不到特征支撑,等于那些结构信息在特征空间里被硬生生抹掉了。

我常用的配置是:c取聚类预期簇数的2到3倍;m取特征总数的20%到50%。如果你的项目提前知道要聚类成5簇,那c设10左右比较稳妥;如果对簇数没概念,用谱聚类里的特征值gap先估一个范围,再定c。不要迷信“嵌入维度越大越好”,c太大时Y的每一维可能只是在拟合噪声,目标函数里的判别项反而会放大随机簇的差异。

4.3 归一化顺序错了,结果差一个档次

我踩过一个特别低级的坑:先算相似度矩阵,再对特征做标准化。结果就是,全数据集的大幅值特征在原始距离中占据了绝对主导,标准化之后图结构已经固定,你再怎么改目标函数也救不回来。正确顺序一定是先特征标准化/归一化,再构建图,再进行谱分解。虽然这听起来显然是先处理后建图,但实际代码里很容易把顺序写反,因为数据集读取时你可能天然觉得“先算特征矩阵,然后建图”,而标准化模块是后加的,一不小心就加到了建图之后。

类似的问题还有:特征矩阵是否中心化。拉普拉斯图本质上对特征的均值偏移不敏感,因为热核距离考虑了均值,但L2,1回归项对均值敏感,因为XW的拟合会受到均值影响。因此我建议在进模型之前,对所有特征做一遍零均值标准化。若每个特征方差差异很大而不处理,最后的行范数会偏向高方差特征,导致选出来的特征和方差过滤差不多,完全丧失谱结构的意义。

4.4 收敛判据与初始化敏感度

迭代优化最常见的问题是卡在局部最优。我试过把W初始化为全零矩阵,结果第一轮迭代里行权重全部变成同一个常数,后续更新慢得要命。更稳的做法是用Laplacian Score排序的前c个特征对应的方向来初始化W,或者直接用随机高斯矩阵但固定随机种子。迭代终止条件也别只看目标函数变化量,最好同时看W的排序变化:如果两轮迭代之间,特征排名重合度超过99%,说明已经稳定,没必要继续烧算力。

另外,因为目标函数里有L2,1范数,它的行权重在原点附近特别敏感。某些特征的行范数会在优化过程中反复横跳,这通常不是平衡权重的问题,而是线性回归部分的特征共线性太强。解决办法是在X.T @ X加上一个小的岭项,我习惯加1e-4到1e-3的系数,能显著提升稳定性,而且不会改变特征选择的整体排序。

5. 方法边界与我的默认取舍

5.1 什么时候效果明显,什么时候并不值得

Balanced Spectral Feature Selection不是万能的。在我实测过的场景里,它对手写数字、图像HOG特征、文本TF-IDF这类本身具有局部流形结构的数据效果明显,往往比Laplacian Score高3到5个NMI点,比方差过滤高更多。但如果你处理的是高维稀疏的one-hot类别特征,基本没有局部结构可言,图方法就无从发力。这种场景下老老实实用基于频次和方差的方法反而更可靠。

另一个不值得用的场景是特征数量极其庞大但样本量很小,比如基因表达数据,n只有几十,d有上万。此时光构建一个k近邻图就已经充满噪声,更别提后面的特征分解和回归。我试过在n=50,d=5000的模拟数据上跑,结果特征选择结果比随机选择还差。不是说论文方法有问题,而是方法的适用前提——可靠的距离度量——在此被样本量限制死了。

5.2 与谱聚类嵌入、监督信息结合的可能

这个方法是纯无监督的,但我在项目里经常把它当特征预处理层,而不是最终结果。比如先用Balanced方法选出一批候选特征,再结合业务定义的标签做一次监督过滤,效果比只用单边方法要好。原因也简单:Balanced方法把流形结构的信息压缩进特征子集,监督过滤把业务关心的目标压缩进去,两者叠加信息更完整。

我还在一个推荐系统项目里把选出的特征当成排序模型的输入,对比直接用全量特征,模型训练速度大幅提升,AUC只掉了0.001左右。这其实是个很实用的定位——它不追求在某个指标上超越全量特征,而是用少量特征去逼近全量特征的效果,这在高维业务场景中反而很有价值。

5.3 我做个人项目时的默认参数组合

如果你不想从零调参,可以参考我最后固定下来的一套参数组合,它在我手头多个数据集上都拿到了能接受的结果:

  • 标准化:z-score
  • 图构建:k=5近邻,边权采用热核,σ取中位距离
  • 嵌入维度c:聚类预期簇数的2倍,通常设4到10
  • 目标函数权重:α=0.1,β=10,γ=0.5
  • 特征选择比例:30%到40%
  • 迭代次数:30轮以内,配合收敛判据

需要注意的是,β取10看起来很大,但L2,1范数对行范数的绝对值贡献往往远小于重构误差,权重太小等于没加,特征选择就退化成线性回归的保序结果。这个参数在我项目中几乎是设置后就不用再动的,反而α需要根据数据噪声适当调整。数据噪声大时,α降低一些,避免过度强调图平滑,把噪声点也当成了流形结构。

另外,如果你不是在做学术对比,而是业务落地,我建议最后一定要看一眼选出来的特征列表到底是不是业务上有意义的字段。谱方法最大的缺点就是它只看结构,不看业务含义。哪怕NMI提升了,如果选出的特征在业务上完全无法解释,那它只能作为离线参考,不能直接上生产。我通常会把选出的特征再做一次业务映射,保留三到五个最强字段,再配合人工规则决定最终上线名单。

复现这个思路最大的收获,不是拿到了一个多强的特征选择器,而是彻底理解了一个道理:在真实数据里,“平滑”和“有用”之间永远存在一条细线,你说不清它在哪里,但你可以用一个平衡的目标函数去逼近它。以后再遇到高维特征选择的活,我不再急着套方差或卡方,而会先问一句:这份数据的流形结构是什么?如果答不上来,那再先进的谱方法也只是在给噪声画皮而已。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 17:29:20

GitHub Squad:把多智能体协作放进代码仓库,关键不是多开几个模型

下午三点&#xff0c;我同时对着四个智能体窗口下了同一个指令&#xff1a;帮我把这个仓库里关于用户认证的代码梳理一遍&#xff0c;顺便看看有没有安全漏洞。第一个窗口给我吐了一堆文件路径&#xff0c;第二个开始改代码但没告诉我要改什么&#xff0c;第三个卡在“思考中”…

作者头像 李华
网站建设 2026/9/9 17:28:52

FPGA软核最小系统:MicroBlaze+IIC+UART+LED完整搭建指南

简介&#xff1a;面向FPGA开发者的完整MicroBlaze软核处理器工程源码包&#xff0c;基于Vivado 2021.1与Vitis 2021.1构建。工程实现了AXI兼容IIC控制器&#xff08;用于IMX327图像传感器通信&#xff09;、UART控制器&#xff08;用于状态监控与调试&#xff09;以及LED状态指…

作者头像 李华
网站建设 2026/9/9 17:28:31

蓝桥杯训练士兵题解:C语言实现贪心排序与前缀和优化

2024年蓝桥杯省赛A组有一道让人印象很深的题&#xff0c;叫“训练士兵”。如果你是用C语言参赛&#xff0c;这道题基本把排序、贪心、前缀和优化这几个省赛高频考点一锅端了&#xff0c;代码量不大&#xff0c;但思路一旦卡住&#xff0c;很容易绕进“模拟每一天”的坑里出不来…

作者头像 李华
网站建设 2026/9/9 17:27:42

Flutter鸿蒙多地址监听实战:http_multi_server与Socket桥接方案

先说个背景。去年我给一个开源的多设备调试工具做 OpenHarmony 适配时&#xff0c;遇到了一个非常具体但又特别磨人的问题&#xff1a;开发板同时连着公司 WiFi 和开着一个手机热点&#xff0c;Flutter 侧的控制面板需要局域网内其他电脑、手机都能访问。折腾了一圈发现&#x…

作者头像 李华
网站建设 2026/9/9 17:26:28

微信聊天记录导出指南:4步把对话存成3种格式到本地

微信聊天记录导出指南&#xff1a;4步把对话存成3种格式到本地 【免费下载链接】WeChatMsg 提取微信聊天记录&#xff0c;将其导出成HTML、Word、CSV文档永久保存&#xff0c;对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeChatMs…

作者头像 李华