资讯详情

sklearn特征工程实战:从数据预处理到特征选择全指南

📅 2026/10/13 11:08:44 | 华诺云谱 👁 阅读
sklearn特征工程实战:从数据预处理到特征选择全指南
写这篇笔记之前先说一个我踩过的坑有一次拿一组销售数据做预测模型调了一整天参数AUC就是卡在0.72上不去。后来仔细看了下原始数据发现“商品价格”和“用户点击次数”两个特征的量纲差了三个数量级所有基于距离的计算全被价格主导了。当时要是先把特征工程做好这半天时间根本不用浪费。这就是我今天要整理的内容。在sklearnscikit-learn这个生态里特征工程不是一个孤立的步骤它贯穿了数据预处理、特征处理、特征抽取和特征选择的全过程。这篇笔记会从sklearn的实际使用角度出发把数据的特征工程拆开讲清楚特征工程到底在解决什么问题哪些处理手段是必须掌握的哪些坑是新手最容易踩的。这篇笔记适合两类人刚学完机器学习基础、准备开始做实战项目的人以及已经跑通了一些模型但总觉得效果“差口气”的从业者。特征工程是性价比最高、也最容易被忽略的技术环节搞懂它比多调几个超参数有用得多。1. 先把sklearn和特征工程的关系理清楚1.1 sklearn到底给了我们什么很多初学者把sklearn简单理解成一个“模型库”觉得它只是用来调用逻辑回归、随机森林这些算法的。这是对sklearn最可惜的一种误解。实际上sklearn是一个完整的机器学习工具箱。它的核心设计理念是“统一接口”所有功能模块都遵循fit、transform、predict这套调用逻辑。你预处理数据用fit_transform训练模型用fit预测结果用predict所有模块之间的对接非常顺滑。在sklearn里和特征工程直接相关的模块至少有四个preprocessing数据预处理包括无量纲化、缺失值处理、编码转换等。这是最常见的模块几乎每个项目都会用到。feature_extraction特征抽取包括从字典数据中提取特征、从文本数据中提取词频或者TF-IDF特征。feature_selection特征选择从已有的特征中筛掉无用的、保留有用的。decomposition降维模块最经典的就是PCA主成分分析当特征数量太多、又需要压缩维度时这里就是主场。这些模块的名字本身就对应了特征工程的不同环节。所以在sklearn的语境下特征工程不是一个抽象概念而是一堆可以直接调用的工具。理解了这些模块的划分你也就理解了特征工程在实际操作中的工作流。1.2 特征工程在机器学习流程中的位置一个完整的机器学习项目流程大概是这样的先做数据采集和清洗然后把原始数据交给特征工程处理接着划分训练集和测试集再去跑模型训练和调参最后评估效果、部署上线。很多人的问题在于把精力全花在模型选择和调参上给特征工程的时间少得可怜。这是典型的“方向错了越努力越尴尬”。我给你举个直观的例子。假设你要预测一个城市里二手房的成交价如果只给你“房屋面积”一个特征再牛的模型也只能画一条简单的曲线预测误差很大。但如果把“所在商圈”“房龄”“楼层”“朝向”“是否临街”“装修程度”这些特征都构建出来模型可学的东西就完全不一样了预测能力有了质的提升。这就是特征工程的价值它决定了模型能够从数据中学到什么信息。原始数据是矿石特征工程就是选矿和提炼的过程。提炼得好模型才能发挥真正的实力。2. 特征工程的意义数据和特征决定了上限2.1 那句经典的话到底在说什么在机器学习领域流传着一句话“数据和特征决定了机器学习的上限而模型和算法只是逼近这个上限而已。”这句话不是我说的是业内公认的规律也一直是我做项目时最认同的判断标准。怎么理解呢模型说白了就是在找特征和目标之间的数学关系。如果特征本身就没有携带足够的信息那不管用什么高级模型都不可能拟合出理想的效果。比如你要判断一个用户是否会再次购买特征只给了“性别”和“年龄”而没有“最近消费时间”“购买频次”“优惠券使用情况”这些行为特征那模型能捕捉到的信息就非常有限。特征工程要做的事情就是尽量把原始数据中隐藏的信息转换成模型能理解、能利用的形式同时去掉干扰信息。这一步做得越好模型在训练时的起点就越高。从我实际做项目的经验来看特征工程通常是整个项目中最耗时的一个环节。一个中等规模的数据集数据清洗和特征工程往往占据整个项目60%的时间模型调参反而只占20%甚至更少。在工业界一个优秀的特征往往能比一个复杂的模型带来更多的效果提升。2.2 特征工程包含哪几块内容从工作内容的角度特征工程可以拆成四个部分第一特征使用。拿到原始数据后需要考虑哪些字段可以直接作为特征使用哪些字段需要清洗掉。比如数据里有“用户ID”这种字段一般是不能作为数值特征直接送进模型的因为它只是一个标识符没有实际的数值含义。第二特征获取。有时原始数据里的字段太粗糙需要从中加工出新的特征。比如把“下单时间”拆成年、月、日、星期几、是否节假日这些新特征对预测用户行为往往比单一的时间戳有用得多。第三特征处理。包括数据的无量纲化归一化、标准化、缺失值填充、异常值处理、文本数据的编码等等。这一类处理手段非常具体也是sklearn中preprocessing模块的主要用武之地。第四特征选择。前面构造了一堆特征但不代表每个特征都适合喂给模型。有些特征和标签的相关性极低有些特征之间高度相关这些都会拖慢训练速度、降低模型泛化能力。特征选择就是为了从特征集里挑出一个“最精华”的子集。理解了这四个部分再去看特征工程的实操内容思路就会清晰很多。下面我按顺序把这个流程讲透。3. 特征工程之特征处理数据预处理是绕不开的第一步3.1 无量纲化为什么SVM和KNN对数据尺度这么敏感特征处理里最基础、也最容易被忽略的就是无量纲化。所谓无量纲化就是把不同范围的特征值统一到差不多的尺度上。为什么需要这一步我们看两个实际场景。场景一KNNK近邻算法在预测时本质上是计算样本之间的“距离”。如果某个特征的值域范围特别大比如“商品价格”在几万到几十万之间而另一个特征“用户评分”在1到5之间那么在计算欧式距离的时候价格几乎支配了整个距离的计算评分的影响微乎其微。这样算出来的“近邻”其实是被单一特征绑架了预测效果自然打折。场景二SVM支持向量机和很多线性模型在求解时涉及梯度下降等优化过程。如果某些特征的值域特别大会拖慢收敛速度甚至导致模型无法收敛。用我自己的话说量纲不一致相当于让模型在崎岖不平的山路上跑步数据标准化之后路才平了模型跑起来才顺畅。在sklearn的preprocessing模块里最常用的两个工具是MinMaxScaler归一化。把数据缩放到一个指定的范围通常是[0,1]区间。公式是(x - min) / (max - min)。StandardScaler标准化。把数据变成均值为0、标准差为1的分布。公式是(x - mean) / std。那什么时候用哪个呢我的习惯是如果数据本身没有明显的分布形态、又需要保留特征的原始相对大小用MinMaxScaler更多一些如果数据近似正态分布、或者模型对异常值不敏感用StandardScaler更稳定。需要提醒的是MinMaxScaler对异常值非常敏感因为一旦数据里出现一个特别大的离群点其他的点都会被压缩到很小的区间里。下面的代码演示了一个最简单的标准化操作实际项目中记得先在训练集上fit再对测试集做transform这个细节后面我会单独展开。from sklearn.preprocessing import StandardScaler, MinMaxScaler data [[10, 50000], [20, 30000], [15, 80000], [5, 10000]] # 标准化 scaler_std StandardScaler() data_std scaler_std.fit_transform(data) # 归一化 scaler_minmax MinMaxScaler() data_mm scaler_minmax.fit_transform(data) print(data_std) print(data_mm)3.2 缺失值处理填均值、填中位数还是填众数真实数据里几乎没有不缺值的。缺失值处理是特征工程里最烦人、但也最必要的一步。在sklearn里以前常用的Imputer类在新版本中已经被废弃现在推荐用的是SimpleImputer。SimpleImputer支持四种主要策略mean用该列的均值填补适合数值型特征。median用该列的中位数填补比均值更抗异常值。most_frequent用该列出现次数最多的值填补适合类别型特征。constant用一个固定值填补比如0通常用于有明确语义的场合。选择哪种策略我的经验是先看特征的分布情况。如果数据分布比较对称、没有太多极端值用均值没问题如果数据里存在明显的离群值用中位数更稳如果是类别型特征众数是默认选项如果缺失值本身代表着一种特殊的业务含义比如“该用户未填写手机号”可以考虑单独填一个特定值甚至把“是否缺失”本身也变成一个特征。需要特别提醒的是填充缺失值必须在划分训练集和测试集之后只用在训练集上计算填充值再用同样的填充值去填充测试集。如果直接在完整数据集上填充测试集的信息会泄露到训练过程里模型评估结果会虚高到了真实环境就露馅了。下面是一个简单的示例import numpy as np from sklearn.impute import SimpleImputer X np.array([[1, 2], [np.nan, 5], [3, np.nan], [7, 9]]) # 用中位数填充缺失值 imputer SimpleImputer(strategymedian) X_filled imputer.fit_transform(X) print(X_filled)3.3 类别特征编码为什么模型需要One-Hot还有一个新手经常卡住的地方类别特征怎么喂给模型。模型本身只能处理数值但业务数据里大量存在“城市”“品类”“颜色”这样的文本型类别字段。直接把这类字段映射成一个整数比如“北京1上海2广州3”是很多初学者的第一反应但这个做法有很大的隐患它会引入一种不存在的“大小关系”模型可能认为北京的“权重”小于上海、上海的“权重”小于广州而实际这些城市之间根本没有先后顺序之说。正确的做法是独热编码One-Hot Encoding。它的思路是把一个有k个类别的字段拆成k个0/1字段每个样本在对应的类别字段上取1其余取0。在sklearn里OneHotEncoder专门做这件事也可以用pandas.get_dummies快速实现。比如城市字段有“北京”“上海”“广州”三个值经过独热编码后会变成三列城市_北京、城市_上海、城市_广州。这样每个城市之间是平等的模型也不会错误地学到顺序信息。需要留意的是当类别数量特别多时独热编码会让特征维度暴增。这种情况下可以考虑用业务上的聚合、目标编码或者干脆配合后面的特征选择/PCA降维来控制维度规模。4. 特征工程之特征抽取与特征选择把好特征“挖”出来4.1 特征抽取从原始数据中创造新特征特征抽取这个概念很多刚从理论转到实战的人容易和特征选择搞混。我简单区分一下特征抽取是从原始数据中创造新的特征比如从一段文本中统计词频从日期中拆出星期几特征选择是从已有的特征里挑出好用的子集。一个是“挖新矿”一个是“筛金子”。在sklearn里特征抽取最典型的应用场景是文本数据和字典数据。先看字典数据。有时我们的原始数据是以字典形式存储的比如一行记录是{城市: 上海, 销量: 120}DictVectorizer可以把这个字典转成一个数值矩阵同时自动对“城市”这类类别信息进行One-Hot编码。这个工具在处理JSON格式的数据集成时非常方便。再看文本数据。文本不能直接喂给模型需要先转成数值向量。最基础的方法是词袋模型也就是统计每个词在文本中出现的次数。CountVectorizer就是做这件事的。更进阶一点的是TF-IDF它不仅能表示词频还能削弱那些在不同文档中都频繁出现、因而没什么区分度的高频词。sklearn里的TfidfVectorizer使用起来非常简洁。这里有一个特别重要的坑尤其是处理中文文本的时候CountVectorizer默认按空格或者标点切分英文单词但中文的词语之间没有天然的空格分隔。如果直接拿一篇中文文章去调用CountVectorizer它会把整句话当成一个“词”产生一个没有意义的长长特征。所以在做中文文本特征抽取之前一定要先做分词处理。我一般会用分词工具把文本切分成词序列再用空格拼接成“词1 词2 词3”的形式然后再交给CountVectorizer处理。从某个角度来看特征抽取本质上就是在做“信息结构化”把我们人类容易理解、但机器无法直接读取的信息转换成机器能读懂的数字这个环节的价值往往比调模型本身更大。4.2 特征选择把无用特征请出模型特征选择的目标很明确在已经准备好的特征集合里筛掉低质量的特征保留真正有价值的部分。为什么要做特征选择最直接的原因是“维度灾难”。特征越多模型训练时间越长数据稀疏的问题也越严重模型很可能学到噪声而不是规律。比如一个只有几千条样本的数据集如果特征维度达到好几万模型很容易过拟合泛化能力反而下降。sklearn的feature_selection模块提供了一些非常实用的方法。按筛选策略我一般把它们分成三类第一类是过滤式选择。不依赖任何具体模型直接根据统计指标来筛选特征。最基础的工具是VarianceThreshold把方差过小的特征直接扔掉。方差小意味着这个特征在所有样本上几乎是常数没有任何区分能力留着只会增加噪声。另一个常用工具是SelectKBest配合卡方检验chi2筛选与目标变量最相关的特征。卡方检验在特征值和目标变量之间是否存在显著关联时非常有效尤其适合类别型特征和类别型标签的场景。第二类是嵌入式选择。它把特征选择的过程嵌进模型的训练过程里让模型自己告诉我们哪些特征更重要。最典型的是通过正则化比如L1正则化自动将不重要的特征系数压缩到0也可以是训练完树模型如随机森林、XGBoost之后直接查看feature_importances_属性来对特征重要性排序。第三类是包裹式选择比如递归特征消除RFE。它反复训练模型每次淘汰掉最不重要的特征直到达到指定的数量。这个方法效果好但计算开销较大通常不会是最优先的选择。我的个人建议是先用过滤式方法做一次粗筛把明显没用的特征去掉然后用树模型或者L1正则化做嵌入式筛选观察特征重要性的排序最后结合业务经验人工核对一遍入选的特征列表确认没有明显不合理的字段被保留。讲了这么多下面这段代码演示如何用卡方检验选出最重要的3个特征from sklearn.feature_selection import SelectKBest, chi2 from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split # 以鸢尾花数据为例仅为演示 X, y load_iris(return_X_yTrue) X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.3, random_state42) selector SelectKBest(chi2, k3) X_train_selected selector.fit_transform(X_train, y_train) X_test_selected selector.transform(X_test) print(原始训练特征形状:, X_train.shape) print(选择后训练特征形状:, X_train_selected.shape) print(各特征卡方分数:, selector.scores_)4.3 特征降维PCA到底是怎么工作的降维和特征选择看着很像但思路完全不同。特征选择是在原始特征里做减法降维则是把原有特征经过数学变换投影到一个更低维的空间里。PCA主成分分析是最常见的降维方法。它的核心思想是找到一组新的坐标轴让数据在这些坐标轴上的投影方差最大。既然方差大的方向保留了更多的信息丢掉方差小的方向就能在尽量少损失信息的前提下降低数据维度。在sklearn里decomposition.PCA用起来非常简单最难的地方估计就是n_components该怎么选。这个参数可以设成整数表示降到多少维也可以设成一个(0,1)之间的小数表示保留原始方差的多少比例。比如设成0.95就意味着PCA会帮我们选出一个降维后的特征组合使这个组合保留原始数据95%的方差。在实际项目中我一般会先设成0.95或0.9然后看一下各个主成分的“解释方差比例”explained_variance_ratio_排序再综合考虑模型效果来决定。需要说明的是PCA属于无监督方法它不关心目标变量所以只能用来压缩特征不能保证压缩后的特征对分类任务是最优的。5. 常见问题与排查技巧实录这些坑我替你先踩过了5.1 数据归一化必须放在划分训练集之后吗是的而且这个问题非常重要也很容易被忽略。很多初学者在拿到数据后会先对整个数据集做归一化然后再划分训练集和测试集。这个顺序的问题在于测试集的信息在归一化时已经被用到了等于模型在训练过程中“偷看”了测试集的分布。虽然看起来测试集没有被模型直接训练但数据预处理阶段已经泄露了信息导致评估结果偏乐观。正确的顺序是先划分训练集和测试集然后只在训练集上fit归一化器再分别用这套归一化器transform训练集和测试集。sklearn的Pipeline管道模块就是为了解决这类问题设计的把预处理、特征选择和模型训练串联成一个整体能有效避免人为的顺序错误。5.2 文本特征抽取后矩阵太稀疏内存扛不住怎么办当你用CountVectorizer或者TfidfVectorizer处理大量文本时得到的往往是一个巨大的稀疏矩阵。很多新手习惯性地调用.toarray()把它转成稠密矩阵来看内容结果数据一多内存直接告急。正确做法是不要轻易把稀疏矩阵转成稠密矩阵。大多数情况下这个稀疏矩阵可以原封不动地作为训练数据喂给模型比如逻辑回归、线性SVM都支持稀疏矩阵输入。只有在少数需要特定处理的场景比如某些不支持稀疏输入的工具才需要慎重考虑转换的问题。5.3 中文文本特征抽取完全失效怎么办这个问题我前面提过但它值得再强调一次。中文文本在交给CountVectorizer之前必须分词。否则整段文字会被当成一个“词语”特征的区分度极低。解决办法是先用中文分词工具将文本切分成词序列再用空格重新拼接起来然后交给CountVectorizer处理。5.4 特征太多筛选结果乱糟糟的怎么破如果特征维度非常大一次直接用卡方检验或者Lasso可能都不太稳定。我通常会用阶梯式筛选先用VarianceThreshold把方差极低的常量特征直接切掉再用SelectKBest做一轮无关特征粗筛然后用树模型查看特征重要性、人工复核筛选结果。这种分步走的策略每一步开销都不大又能层层收敛到最有价值的特征集合。5.5 特征工程速查表下面把这个笔记里涉及的关键问题和应对手段整理成一张速查表方便以后做项目时直接对照。问题现象常见原因处理工具与方式模型训练收敛慢特征量纲差异过大StandardScaler/MinMaxScaler数据存在大量缺失值没有做缺失值处理SimpleImputer填空均值/中位数/众数类别字段无法喂给模型需要进行编码OneHotEncoder/DictVectorizer文本不能直接建模需要结构化特征CountVectorizer/TfidfVectorizer中文前置分词特征过多、模型过拟合存在无用或冗余特征过滤式筛选、嵌入式筛选、PCA 降维特征工程出现信息泄露先归一化后划分数据集先分割数据集再fit_transform/transform6. 一点个人经验收尾特征工程是值得“浪费”时间的艺术这篇笔记从sklearn的模块体系出发把特征工程拆成了特征处理、特征抽取、特征选择三块来讲。表面上是一堆API的用法但背后的逻辑其实是相通的先理解数据的分布和含义再选择合适的手段最后用模型效果来验证特征工程做得好不好。我在实际项目中总结的一条经验是做特征工程时不要追求一步到位而是要形成一个“基线加迭代”的工作习惯。第一次建模先用最简单的清洗和编码跑一个基础模型把结果记录为基线接下来每增加一个特征、每做一次处理都和基线对比看效果是变好了还是变差了。这个习惯看起来繁琐但能帮你快速判断哪些特征真正有用哪些只是看起来高大上。最后再分享一个小技巧把特征工程的每一步都封装成函数并用Pipeline把它们串起来。这样整个流程是可复现的、可追踪的切换数据集、重跑实验都方便很多。特征工程不是一次性的苦力活它是你整个机器学习体系里最有升值空间的部分——花在上面的时间一定会以模型效果的形式回报给你。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑