☰
高维小样本数据怎么筛?分子描述符特征筛选全流程解析
2026/10/16 3:21:53 网站建设 项目流程

简介:2021年研究生数学建模D题第一题的完整解决方案,面向数学建模竞赛参赛者、药物研发数据分析人员,可用于解决分子描述符变量筛选与生物活性预测中的维度灾难问题。压缩包共14个文件,约23.32MB,包含Python脚本、ipynb交互式笔记、可视化图表、Excel数据集与项目说明文档(含分子描述符含义解释),按代码、数据、结果、文档模块化组织。方案针对1974个化合物的729个分子描述符,先通过方差筛选剔除低方差特征,再采用随机森林置换重要性对变量排序,最后依据特征相关性确定最优子集,并给出前20个对生物活性影响最显著的分子描述符。所有代码均含详细注释,可视化结果可直接用于论文或答辩展示,数据处理思路可迁移至其他结构特征选择任务。目前已有265人学习,适合希望快速掌握随机森林特征选择及建模全流程的读者。

1. 某届研究生数学建模竞赛的D题第一题,到底在考什么

某届研究生数学建模竞赛的D题第一题,核心是分子描述符的筛选与分析。很多人一拿到数据就“随机森林二连跑”,结果第一问就被扣分,因为这道题真正考的不是跑模型,而是“怎么筛”。空值怎么处理、共线性怎么剔除、特征重要性怎么解释、回归模型怎么交叉验证,这条链路才是拿分重点。能把这套流程写清楚的人,哪怕不调参也能拿高分;只堆跑分结果的人,在评委眼里就是个黑匣子。这份备考笔记把高频考点拆成可直接背诵和复现的答题模板,适合准备数学建模竞赛、数据分析岗位面试以及机器学习特征筛选实操的人,照着走一遍就能拿到大部分步骤分。

2. 先看懂数据:描述符矩阵里的空值、量纲和共线性

2.1 拿到分子描述符数据集先做哪四件事

比赛给的数据通常是一个 CSV,行是化合物样本,列是各种分子描述符,最后一列是目标性质。这类数据最典型的特点是“高维、小样本、大量缺失”:描述符可能会有几百到上千列,但样本往往只有几十到几百行。如果不先处理数据,后面任何模型的结果都不可信。

拿到数据第一件事是看 shape 和缺失率。用df.isnull().mean()算出每一列的缺失比例,按降序排列,先看清楚哪些列几乎全是空值。对于分子描述符数据,缺失率超过 30% 的列通常直接删除,因为填补这种列会引入大量噪声,保留它反而会拉低模型稳定性。

第二件事是处理剩余的空值。对数值型描述符,推荐用中位数填补而不是均值填补,因为描述符数据里经常出现离群值,均值会被极端值拉偏,中位数更稳健。如果某个样本行缺失的描述符过多,比如超过一半列都是空值,可以考虑删掉这一行,否则它就是缺失值填补后的“人造样本”。

第三件事是量纲标准化。树模型不要求标准化,但题目后续通常要对比线性回归、岭回归、Lasso,这些模型对特征量纲非常敏感。用StandardScaler把每个描述符变成均值 0、方差 1 的形式,后面做相关性分析和回归建模才有意义。

第四件事是初筛。计算每个描述符与目标变量的相关系数,把绝对值低于 0.1 的描述符先标记出来;再算两两描述符之间的相关系数,找出高度相关的列。这一步不需要删得很干净,但必须做,因为后续随机森林重要性会被特征间的共线性干扰,先粗筛一遍能让结果稳定很多。

2.2 相关性热图与 VIF 筛选:哪些是必画必算的图

相关性热图是这道题最直观的得分点。用seaborn.heatmap画出描述符两两相关系数矩阵,评委一眼就能看出你在做共线性诊断。但只画热图不够,热图是给人看的,数值阈值才是给分依据。

两个描述符相关系数绝对值大于 0.7 或 0.8 时,通常认为存在强共线性,两个变量提供的信息高度重叠,保留一个即可。实际操作中可以先对相关系数矩阵做层次聚类,也可以直接按与目标变量的相关系数大小决定保留哪个:保留与目标相关性更高的那个,删掉另一个。

相关性热图只捕捉两两线性关系,多个变量之间还可能存在更隐蔽的共线性,这时候需要算方差膨胀因子,也就是VIF。VIF 的计算公式是1 / (1 - R²),其中 R² 是把某个描述符作为因变量、其他描述符作为自变量做回归得到的决定系数。VIF 大于 10 说明该描述符几乎能被其他描述符线性表示,必须剔除。

很多参赛者只会画热图不会算 VIF,或者算了也不写在论文里。实际上这道题的评分标准很看重“筛选依据”,你写了“相关系数 > 0.8 的保留与目标相关更高者,再计算 VIF 剔除 > 10 的变量”,这句话本身就是得分点。

2.3 真题演练:空值处理与初步筛选代码

下面这段代码是拿到分子描述符数据后第一个可以直接复现的完整流程:

import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler df = pd.read_csv('molecular_descriptors.csv') # 1. 查看缺失率,按降序排列 miss_ratio = df.isnull().mean().sort_values(ascending=False) print(miss_ratio[miss_ratio > 0.3]) # 2. 删除缺失率超过 30% 的列 drop_cols = miss_ratio[miss_ratio > 0.3].index df = df.drop(columns=drop_cols) # 3. 数值列缺失值用中位数填充 num_cols = df.select_dtypes(include=[np.number]).columns df[num_cols] = df[num_cols].fillna(df[num_cols].median()) # 4. 保存目标列,再做标准化 y = df['target'].values X = df.drop(columns=['target']) scaler = StandardScaler() X_scaled = scaler.fit_transform(X)

这里有几个关键点。第一,缺失率阈值为什么设 30% 而不是直接删掉所有含空值的列?因为分子描述符数据里很多列只是少量缺失,用中位数填补后信息仍然可用,如果直接dropna(),可能删掉一大半样本,建模就失去意义了。第二,为什么用中位数而不是均值?因为描述符数值跨度大,个别极端样本会把均值拉得很高,填补后的分布会失真。第三,标准化之前你必须先把target取出来,否则StandardScaler会把目标变量也标准化,后面计算 RMSE 时还要反变换,很容易出错。

做完清洗之后,还要做一次与目标变量的相关性初筛:

# 转回 DataFrame,便于保留列名 X_df = pd.DataFrame(X_scaled, columns=X.columns) # 计算每个描述符与目标变量的相关系数 target_corr = X_df.apply(lambda col: np.corrcoef(col, y)[0, 1]) # 找出与目标相关性绝对值小于 0.1 的描述符 low_corr_cols = target_corr[target_corr.abs() < 0.1].index.tolist() print(len(low_corr_cols))

这段代码的意图是找出“单变量看和目标几乎没关系”的描述符。注意,相关系数低不代表一定没用,因为可能存在非线性关系,所以这一步只做初筛标记,不急着删。如果在这之后直接去跑随机森林,重要性排序会干净很多,不会出现一堆噪声变量占据中游位置的情况。

3. 高频考点:随机森林特征重要性与嵌入法筛选

3.1 为什么这道题偏爱随机森林

分子描述符数据集有一个很特殊的结构:特征数量远大于样本数量,特征之间还普遍存在相关性。线性回归在这种数据上很容易过拟合,而且系数解释性差;物流回归、SVM 需要先做特征选择才能发挥效果。随机森林在这种场景下几乎不需要做太多预处理,能直接处理非线性关系,对离群值不敏感,还自带特征重要性输出,所以它成为这道题最常用的基线模型。

随机森林的内置特征重要性来自每棵树的节点分裂收益,变量被选中分裂的次数越多、带来的不纯度下降越大,重要性越高。这个排序可以直观地告诉你哪些分子描述符与目标性质关系最密切。但要注意,随机森林重要性是“模型视角的变量贡献”,不是因果关系,论文里描述时不能写成“该描述符导致目标值上升”,而要写成“该描述符在模型预测中贡献最大”。

这道题还经常要求“筛选出少量关键描述符并建模”。随机森林恰恰适合扮演筛选器的角色:先全特征跑一遍随机森林,拿到重要性排序,再取累计重要性前 80% 或前 Top K 个描述符,用筛选后的特征子集重新建模。整个过程可复现、可解释,比单纯用 PCA 降维更容易拿分,因为 PCA 之后的每一维是原始变量的线性组合,没办法在论文里说清楚“哪些描述符是关键”。

3.2 特征重要性排序的三种口径

面试题和论文答辩里最常见的追问是“你凭什么说这几个变量重要”。只贴一张 feature_importances_ 条形图是不够的。最好把三种口径都讲清楚,你用过哪一个要能自圆其说。

口径计算逻辑适用场景注意点
基尼重要性统计变量在树分裂时带来的不纯度下降总量快速排序,比赛首选对有相关性的变量会分散权值
置换重要性随机打乱某列数据,看模型误差上升多少变量间相关性较强时更稳健计算量较大,需要重复多次
SHAP 值基于博弈论计算每个样本上的边际贡献需要解释单条样本预测时高维特征下计算较慢

面试官想听到的不是你会不会调feature_importances_,而是你能不能说出各方法之间的差异。基尼重要性计算效率高,但当两个描述符高度相关时,重要性会被分摊到这两个变量上,可能本来重要的变量排到后面。置换重要性的思路是“把这一列随机打乱,如果误差明显变大,说明这个变量不可替代”,逻辑上更接近因果推断。SHAP 则能给出每个样本上的正负贡献方向,适合对关键描述符做进一步分析。

比赛得分点上,建议至少跑一遍基尼重要性和置换重要性,把两者的 Top K 取交集,作为“稳定重要特征”。这个交集在论文里写出来,远比单口径列表有说服力。

3.3 真题演练:随机森林重要性排序代码

from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split( X_scaled, y, test_size=0.2, random_state=42 ) rf = RandomForestRegressor( n_estimators=500, max_depth=None, min_samples_leaf=2, random_state=42, oob_score=True ) rf.fit(X_train, y_train) # 特征重要性排序 imp = pd.Series(rf.feature_importances_, index=X_df.columns) imp = imp.sort_values(ascending=False) # 取累计重要性前 80% 的描述符 cum_imp = imp.cumsum() / imp.sum() keep_cols = imp[cum_imp <= 0.8].index.tolist() print('保留描述符数量:', len(keep_cols)) print(keep_cols) # OOB 分数,作为随机森林内部验证 print('OOB R2:', rf.oob_score_)

随机森林的几个参数要能说出设置理由。n_estimators设为 500,是因为描述符维度较高,树太少时重要性估计不稳定,500 棵树能保证收敛;min_samples_leaf=2是让每片叶子至少有两个样本,防止单棵树叶节点过细导致过拟合;random_state=42固定随机种子,保证结果可复现,这一点在比赛里非常关键,否则每次跑完重要性排序都在变,论文里写不清楚。

oob_score=True是随机森林非常划算的设置,它用每棵树没抽到的样本做内部验证,不需要单独划分验证集就能得到一个 R² 参考值。如果 OOB 分数远高于后续交叉验证分数,说明模型过拟合或者存在数据泄漏。

这段代码跑完,你应该输出一张条形图,按重要性降序绘制 Top 20 描述符。图里要标清楚纵轴是描述符名称,横轴是重要性分数。很多人在这一步只输出数值列表,不画图,实际上论文和答辩里图比表格更容易被记住,尤其是能清楚看出“前几个变量的重要性断崖式下降”这种关系。

4. 建模与验证:筛选后的描述符怎么建模打分

4.1 筛选后建模:从全量描述符到精简特征集

特征筛选的最终目的是建模,而不是原地删列。竞赛第一题通常要求给出筛选出的描述符并建立预测模型。这里推荐两阶段筛选策略:第一阶段用缺失率、相关性、VIF 删除明显有问题的描述符;第二阶段用随机森林重要性或 Lasso 系数挑选 Top K 描述符。

第二阶段选 K 的标准不要拍脑袋。跑一个循环:K 从 5 到 30,每取一个 K 就用筛选后的特征子集做 5 折交叉验证,记录 R² 和 RMSE 的均值与标准差。选择 R² 开始趋于平稳、RMSE 不再明显下降的那个 K。正常情况下你会看到特征数从全量降到二三十个时,性能反而比全量特征更好,这就是筛掉了噪声变量的收益。

筛选后的建模不能只跑随机森林一个模型。至少要对比线性回归、岭回归、Lasso、随机森林四个模型。理由很简单:线性模型能说明描述符与目标之间近似线性关系,岭回归和 Lasso 能处理多重共线性并做特征压缩,随机森林能描述非线性关系。对比表一放,论文的“模型比较”部分就完整了。

4.2 评估指标:R²、RMSE、MAE 与交叉验证怎么给分

这道题的评分非常看重误差分析的完整度。R² 是决定系数,表示模型解释了目标变量多少比例的方差;RMSE 是均方根误差,对预测偏差大的样本更敏感;MAE 是平均绝对误差,能反映预测误差的典型大小。三个指标必须同时报告,只写一个会被认为分析不充分。

R² 的公式是:

R² = 1 - Σ(yi - ŷi)² / Σ(yi - ȳ)²

RMSE 的公式是:

RMSE = sqrt(1/n * Σ(yi - ŷi)²)

实际操作中需要注意,R² 不是一个绝对指标,如果目标变量本身方差很小,即使预测误差不大,R² 也会偏低。所以论文里要配合 RMSE 一起解释,比如写出“模型的 RMSE 为 0.12,与目标变量标准差 0.35 相比,误差控制在了约三分之一尺度内”,这才是得分表达。

交叉验证用 5 折还是 10 折?对于分子描述符这种样本量几十到几百的数据,5 折更常用,因为每折验证集样本更多,评估结果更稳定。每次交叉验证要同时输出均值±标准差,例如R² = 0.86 ± 0.03,标准差本身代表模型对不同数据划分的稳定性。如果标准差超过 0.1,说明模型对样本扰动太敏感,先不要急着报好结果,而是回头检查筛选后的特征是否仍然包含干扰变量。

4.3 真题演练:岭回归与 Lasso 对比代码

from sklearn.linear_model import LinearRegression, Ridge, Lasso from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import cross_val_score import numpy as np models = { 'Linear': LinearRegression(), 'Ridge': Ridge(alpha=1.0), 'Lasso': Lasso(alpha=0.01), 'RandomForest': RandomForestRegressor(n_estimators=500, random_state=42) } X_sel = X_df[keep_cols] for name, model in models.items(): r2_scores = cross_val_score(model, X_sel, y, cv=5, scoring='r2') rmse_scores = -cross_val_score(model, X_sel, y, cv=5, scoring='neg_root_mean_squared_error') print(f'{name}: R2={r2_scores.mean():.3f}±{r2_scores.std():.3f}, ' f'RMSE={rmse_scores.mean():.3f}±{rmse_scores.std():.3f}')

这份代码里有几个容易看错的地方。第一,cross_val_score的scoring='neg_root_mean_squared_error'返回的是负值,因为库约定“越大越好”,所以要在前面加负号转回正常 RMSE。第二,Ridge的alpha是正则化强度,alpha越大,系数压缩越狠,默认 1.0 未必最优,需要调参。第三,Lasso的alpha不能设得太大,否则所有系数都被压成零,一般从 0.001、0.01、0.1 这个量级开始尝试。

如果 Lasso 把某些描述符的系数压成 0,这些描述符天然就可以从特征集里删掉,这比随机森林重要性排序更直接。论文里可以写“Lasso 通过 L1 正则化将 12 个描述符的系数压缩为 0,最终保留 18 个非零系数变量”,这是特征筛选的第二种方法,体现方法的多样性。

除了数值指标,还要画一张“预测值 vs 真实值”的散点图,对角线是完美预测线。点越贴近对角线说明预测越好。这张图几乎每份高分论文都有,但大多数人在上面只画了随机森林一个模型。更建议四个模型画在同一张图上的四个子图,这样评委能直观看到你做了对比。

5. 常见错误与失分点:这五个坑几乎每年都有人踩

5.1 坑一:拿到数据直接 dropna,样本被删掉一半

错在哪:很多同学拿到分子描述符数据,第一行代码就是df.dropna(),然后发现原本 200 行样本只剩下 90 行。

为什么错:分子描述符数据是高维稀疏数据,空值分散在不同列里,整行删除会导致样本量急剧减少。样本量本来就是这类数据的短板,删完之后模型方差变大,交叉验证结果忽高忽低,论文根本没有说服力。

怎么答对:先按列算缺失率,缺失率超过 30% 的列直接删列;删除缺失严重的列之后,再对剩余空值用中位数填补。样本行只有在其缺失描述符超过一半时才考虑删除。这一段处理流程要写进论文,它本身就是评分点。

5.2 坑二:只画相关性热图,不设筛选阈值

错在哪:热图画得很漂亮,红红蓝蓝一片,但在论文里只说“可以看出部分描述符之间存在较强相关性”,然后就没有下文了,没有删掉任何共线性变量。

为什么错:热图只是在做可视化诊断,不是一个可复现的筛选规则。评委看不到你用什么标准判断“强相关”,也无法从图里知道你最后保留了哪些变量。把热图当作最终结果,等于做了分析但没有输出。

怎么答对:设定两个明确规则。第一,与目标变量相关系数绝对值低于 0.1 的描述符标记为低相关;第二,描述符两两相关系数绝对值大于 0.7 时,保留与目标相关性更高的那个。然后继续计算 VIF,VIF 大于 10 的进一步剔除。最后在论文里写出“删除前后特征数量从 312 降为 85”,这个数字变化就是工作量的证明。

5.3 坑三:把随机森林重要性排序当“一刀切”依据

错在哪:跑了一次随机森林,按重要性排序直接删掉后 50 个特征,然后建模就交上去了。复现时发现删掉的特征对结果影响很大,甚至第二次跑重要性排序的顺序都不一样。

为什么错:基尼重要性在有相关特征时会把重要性分散到多个变量上,一次排序的结果受随机种子影响,直接一刀切可能误删重要变量。题目要的是“稳定可靠的关键描述符”,不是一个碰运气的排序结果。

怎么答对:用多种口径交叉验证。至少同时跑基尼重要性和置换重要性,取两者 Top K 的交集作为最终保留特征。或者把随机森林重跑 5 次,每次用不同随机种子,只保留每次都排进前 20 的变量。删除变量后必须重新建模对比性能,不能只看排序就决定去留。

5.4 坑四:标准化和填补在切分之前做,造成数据泄露

错在哪:先用全部数据的均值和标准差做fit_transform,再train_test_split,整个流程跑下来交叉验证分数特别高,但评委一眼看出代码顺序有问题。

为什么错:标准化和缺失值填补都属于数据处理,它们的参数应该只从训练集学习。如果对全量数据先拟合再用,测试集的信息就已经泄漏到模型训练过程中,交叉验证结果虚高,提交后换新数据必然翻车。这也是面试官最喜欢追问的细节。

怎么答对:严格顺序是“先切分,后处理”。用train_test_split切分后,只在训练集上用scaler.fit_transform,然后对测试集用同一个已经拟合的scaler.transform。缺失值也是如此,在训练集上算中位数,再填充到测试集。最省心的做法是把整个过程写进Pipeline,面试时说出“我用 Pipeline 避免数据泄漏”,这一个点就能和其他考生拉开差距。

5.5 坑五:只看 R² 不看 RMSE,也不报告标准差

错在哪:结果表里只写一行“随机森林 R² = 0.93”,没有 RMSE,没有 MAE,也没有提到用的是一折还是交叉验证。细问之下发现是训练集评分,水分极大。

为什么错:R² 只能说明模型解释了多少方差,但不能体现误差尺度,而且训练集 R² 对树模型来说几乎必然接近 1。只看 R² 会让人高估模型泛化能力,漏掉过拟合严重的问题。

怎么答对:至少报告三件套:R²、RMSE、MAE,并注明是 5 折交叉验证的均值±标准差。比如写成“随机森林 5 折交叉验证 R² = 0.87 ± 0.04,RMSE = 0.21 ± 0.03,MAE = 0.16 ± 0.02”。再附一张预测值与真实值散点图,说明误差在不同取值区间是否均匀。这套组合才是这道题标准的高分答案结构。

6. 答题思路与押题技巧:一套能复用的分析流水线

把前面所有内容压缩成一条流水线,背下来就能应对这类题目:

数据读取 → 按列缺失率删除缺失率大于 30% 的描述符 → 剩余空值用中位数填充 → 标准化 → 与目标变量做相关性初筛 → 检查描述符间相关系数并剔除高共线性变量 → 计算 VIF 剔除大于 10 的变量 → 随机森林基尼重要性排序 → 叠加置换重要性取稳定 Top K → 用保留特征做随机森林、岭回归、Lasso 建模 → 5 折交叉验证输出 R² / RMSE / MAE 的均值±标准差 → 画出特征重要性图、相关性热图、预测值散点图。

这套流程每一步都对应一个得分点。数据清洗是基础分,共线性诊断是方法分,重要性筛选是核心分,交叉验证是严谨分,可视化是展示分。很多参赛者能跑出好的 R² 却拿不到高分,就是因为中间步骤没有形成完整的逻辑链,评卷时只能看到“建模”这一步。

押题方向也不难猜。分子描述符只是这类题目的一个载体,同样的套路随时会被换成催化剂特征筛选、光谱波段筛选、经济指标筛选。面试题里最常见的变体是“给你 500 个特征、100 个样本,你如何选出最重要的 20 个特征并建模”,本质和这道题一模一样。把随机森林重要性、Lasso、置换重要性这三种方法写在简历的项目经历里,面试官问到时你直接用“两阶段筛选 + 交叉验证验证”这套话术回答,比背概念高效得多。

这道题还有一个隐藏考点容易被忽略:解释变量个数与样本量的关系。分子描述符数据中特征数远超样本数,直接上线性回归会过拟合,必须先做特征筛选再建模。答这个点时要主动说“先把特征数压缩到样本量的三分之一以内,再用交叉验证确认”,面试官最想听到的正是这种对高维小样本问题的警觉。

从那以后,我每次拿到高维数据都强制自己先走一遍缺失率和相关性检查,再谈建模,模型跑完一定补上交叉验证标准差。做菜不能省洗菜这一步,这类题也一样,省略了数据检查和筛选,后面所有结果都是脆的。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询