资讯动态

数据预处理实战指南:从清洗到降维的完整流程

发布时间:2026/9/29 12:55:53 来源:尧图企业网站定制
1. 数据预处理到底是什么为什么它比建模更值得花时间1.1 从“垃圾进垃圾出”说起做机器学习项目这几年我最深的体会是算法调参的时间其实远不如处理数据的时间多。很多人拿到数据集的第一反应是赶紧训练模型跑个baseline但真实项目里原始数据的脏乱差程度往往超出想象——字段名不规范、类型对不上、缺失值满天飞、单位不统一、标签分布极端不平衡。你费劲调了三天的模型效果可能还不如别人把数据清洗一遍之后随手跑的线性回归。数据预处理英文叫Data Preprocessing就是把原始数据改造成算法能直接“吃进去”且“吃得舒服”的形态。它不是一个孤立的步骤而是一套组合拳通常包括数据清洗、数据转换、数据集成、数据规约含降维这几个大类。为什么这么重要因为大多数机器学习算法对输入数据都有隐性假设——比如数值型特征要在相近的尺度范围内、类别特征要变成数值、缺失值不能让算法直接报错、冗余特征会影响收敛速度。数据预处理就是去满足这些假设。以头歌平台上常见的机器学习实训任务为例很多同学卡住的点往往不是算法本身的数学推导而是“为什么pandas读进来之后type不对”“为什么标准化之后准确率反而掉了”“为什么sklearn的PCA参数不知道怎么调”。这些问题归根结底都是对预处理流程缺乏一个整体认识。1.2 一份可以抄作业的数据预处理总框架我习惯把数据预处理拆成四个阶段这个框架在表格数据、文本数据、图片数据上都适用数据清洗处理缺失值、重复值、异常值、不一致数据。数据集成把多个数据源合并成统一格式解决实体识别、冗余字段、冲突值问题。数据转换规范化、标准化、离散化、类别编码、函数变换等让数据符合模型输入要求。数据规约降维和特征选择删掉无关和冗余特征降低计算复杂度。这四个阶段不是严格串行的实际项目中常常要来回迭代。比如你做完标准化之后发现某个特征的异常值把均值拉偏了就得退回去先处理异常值再做标准化。所以我建议把这个流程当做一个“预处理流水线”来看待而不是一次性完成的线性任务。你在实操中可以借助sklearn的Pipeline把多个步骤串起来但前提是你得理解每一步在干什么否则Pipeline只会帮你把错误一键放大。提示如果只是为了跑通模型可以只做最小必要处理但如果是参加比赛、做项目交付或者写论文数据预处理的质量直接决定成果天花板这一步值得你投入70%的精力。2. 数据清洗把脏数据挡在门外2.1 缺失值处理先判断机制再选策略缺失值是每个数据项目都躲不开的问题。处理之前我的习惯是先搞明白缺失是怎么产生的完全随机缺失MCAR、随机缺失MAR还是非随机缺失MNAR。虽然严格判断机制不容易但至少要看一下缺失率高的那些列是不是和目标变量有关联。常用的处理策略有四种直接删除适合缺失率极低比如低于1%且样本量充足的情况或者某个特征缺失率超过70%基本失去使用价值。均值/中位数/众数填充数值型用小提琴图或分布图看一眼是否偏态偏态明显就用中位数正态或近似正态可以用均值类别型用众数。插值法时间序列数据用线性插值、多项式插值或前向/后向填充效果往往比均值填充好很多。模型预测填充把带缺失的列当目标变量用其他完整列做预测适合重要特征且缺失率不太高的情况但成本较高一般项目不必轻易上。实际写代码时pandas处理缺失值很方便核心就几个API。比如用isnull()统计缺失分布用fillna()填充用dropna()删除。但我想提醒一点填充本身会引入偏差所以建议额外生成一个“是否为缺失”的指示特征让模型自己学习缺失模式。这在医学数据、风控数据里尤其有效。import pandas as pd # 查看缺失情况 print(df.isnull().sum()) # 数值列按中位数填充并生成缺失指示列 for col in df.select_dtypes(includenumber).columns: if df[col].isnull().any(): df[col _was_missing] df[col].isnull().astype(int) df[col] df[col].fillna(df[col].median())2.2 重复值与异常值一个要彻底清除一个要谨慎对待重复值的处理比较简单drop_duplicates()一行搞定。但有几个坑值得注意一是“看起来很相似但并不是重复”的数据比如同名不同地址的用户单纯按某一列去重会导致误删二是重复出现在特征子集上比如一份订单数据里同一个订单号可能有多行正常明细不能盲目去重。我在做电商数据时就遇到过因为按订单号去重结果把真实的多商品订单砍掉一半的惨案。异常值则要复杂得多。异常值可能是噪声也可能是真实的极端事件比如风控场景里的超大额交易恰恰是重点监控对象。处理异常值常用三种办法3σ原则数据近似正态分布时超过均值±3倍标准差的值视为异常。四分位距法IQR小于Q1-1.5IQR或大于Q31.5IQR的值视为异常对偏态分布更稳健。基于模型用孤立森林Isolation Forest、DBSCAN等算法做离群点检测。我的经验是先用箱线图或散点图可视化看一遍数据分布再决定用哪种方法。如果异常值是有业务意义的可以考虑单独标记出来而不是直接删除或者做截尾处理winsorize把极端值压到合理分位点上。import numpy as np # 使用IQR方法识别数值列的异常值 def find_outliers_iqr(s): q1, q3 s.quantile(0.25), s.quantile(0.75) iqr q3 - q1 lower, upper q1 - 1.5 * iqr, q3 1.5 * iqr return s[(s lower) | (s upper)] for col in [age, income]: outliers find_outliers_iqr(df[col]) print(f{col} outliers: {len(outliers)})2.3 数据清洗的实操顺序与自查清单我踩过很多次坑之后总结出一套固定的清理顺序分享出来供参考读入数据后用info()和describe()做全面体检确认列类型和分布范围。按业务主键比如用户ID、订单ID检查重复行。统计每列的缺失率画缺失值矩阵判断缺失机制。可视化关键特征的分布初步判断异常值的合理区间。处理不一致数据比如性别字段里同时出现“男”“male”“M”。清洗完成后把结果导出为中间文件再进入下一阶段。这里再给一个自查清单清洗后的数据里每个特征都有明确含义吗类型是否都对了有无遗漏的极端值如果这些检查都通过你就能放心进入转换环节。3. 数据转换让数据变得模型友好3.1 标准化和归一化到底怎么选数据转换是预处理里最容易被忽视却对模型效果影响极大的环节。先聊聊标准化Standardization和归一化Normalization的区别。标准化Z-score把数据变成均值为0、标准差为1的分布公式是(x - mean) / std。归一化Min-Max把数据缩放到[0,1]区间公式是(x - min) / (max - min)。一句话总结数据有边界、需要保留原始相对距离时用归一化数据近似正态分布、或者存在极端值时用标准化像神经网络、梯度下降类模型标准化通常是更稳妥的默认选择。另一个容易混淆的是几种常见的Scikit-learn转换器StandardScaler、MinMaxScaler、RobustScaler、MaxAbsScaler。RobustScaler用中位数和四分位距缩放对异常值不敏感我在处理房价、收入这类长尾分布数据时非常喜欢用它。MaxAbsScaler适合稀疏数据因为不会破坏稀疏性。需要特别强调一个极其常见的错误先拆分训练集和测试集再对测试集单独fit变换器。正确做法是只在训练集上fit然后用同一个scaler去transform训练集和测试集。不少初学者在整份数据上做标准化然后才切分数据这会导致测试集信息泄露模型评估结果虚高。用Pipeline可以很优雅地解决这个问题。from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) # 只transform不fit3.2 类别特征编码别陷入One-Hot的误区类别特征只有两种有序类别和无序类别。例如“学历等级”小学、中学、大学、研究生是有序的用OrdinalEncoder按顺序编码是合理的而“颜色”红、绿、蓝是无序的用LabelEncoder简单编码成0、1、2会引入不存在的“颜色大小”关系。对于无序类别常用方案是One-Hot编码独热编码把每个类别变成一列0/1。但独热编码也有两个问题类别数太多会造成维度爆炸比如城市有几百个取值类别之间有相似性时独热编码丢失了这种结构。针对类别数多、频率长尾分布的情况我常用目标编码Target Encoding或频率编码Frequency Encoding用类别对应目标变量的均值或类别出现次数来编码在kaggle竞赛中非常常见。这类编码需要配合交叉验证使用避免过拟合。from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder # 无序类别用独热 one_hot OneHotEncoder(sparse_outputFalse) color_encoded one_hot.fit_transform(df[[color]]) # 有序类别用顺序编码 ordinal OrdinalEncoder(categories[[小学, 中学, 大学, 研究生]]) edu_encoded ordinal.fit_transform(df[[education]])另外提一个冷门但好用的小技巧如果你的数据里类别特征很多且稀疏试试FeatureHasher或者嵌入层embedding思路前者原理类似哈希函数后者在深度学习中处理高基数类别特征几乎成了标配。3.3 数据离散化、函数变换与时间/文本字段处理离散化就是把连续型特征切分成区间分等方法、等频分箱、基于聚类分箱是三种典型方式。分箱能增强模型鲁棒性减少异常值影响也让结果可解释性更强比如“年龄在18-30岁”比“年龄26.7岁”更好解释。代价是损失信息量因此不是所有特征都适合分箱。函数变换主要用来修正偏态分布。取对数log、平方根、Box-Cox变换是常见做法。比如收入数据严重右偏取个log之后分布就正常多了。画个直方图或者用scipy.stats.skew看偏度凡是绝对值大于1的基本都可以考虑变换。时间字段处理是另一个容易被忽略的环节。我的建议是拆成年、月、日、星期几、是否节假日等周期特征或者计算“距离某个固定日期的时间差”。在预测场景里“距上一笔交易多少天”往往比“交易日期”本身更有信息量。文本字段则要走另外一套流程分词、去停用词、TF-IDF向量化或者直接用预训练向量模型。这里提一句处理文本之前先确认是否所有样本都有足够的文本内容很多表中只有少部分行填了备注这种稀疏文本特征有时去掉反而更好。4. 数据降维与特征选择少即是多4.1 降维不是玄学而是对抗维度灾难的武器当特征数量非常多的时候模型容易过拟合样本距离趋向均匀距离度量基本失效这就是所谓的“维度灾难”。数据降维的核心思路是在保留尽可能多信息的前提下用少量特征表达原始数据的核心结构。降维还能显著缩短训练时间、缓解特征共线性问题甚至出于隐私保护将原始敏感特征隐藏掉。降维和特征选择常被混在一起说但两者有本质区别。特征选择是从原始特征里挑选子集不改变特征含义可解释性强降维则是通过线性或非线性变换生成一组新特征原始可解释性会丢失。选型时如果项目需要向业务方解释模型特征选择优先如果以预测精度为首要目标降维更合适。特征选择有三大类方法过滤法Filter根据统计指标给特征打分比如卡方检验、方差阈值、互信息包裹法Wrapper用目标模型的性能评估特征子集比如递归特征消除RFE嵌入法Embedded在模型训练过程中自动完成特征选择比如L1正则化Lasso特征权重自动变零。实操中我通常先用Filter方法快速筛一遍再用Lasso或者RFE精选计算量和效果都有保障。4.2 PCA、LDA、t-SNE的选择逻辑主成分分析PCA是最经典的线性降维方法它寻找方差最大的正交投影方向让投影后的数据保留最大方差。PCA无监督不关心标签LDA线性判别分析则有监督目标是让类别间距离最大、类别内距离最小所以LDA天然适合分类任务。t-SNE和UMAP属于非线性降维主要用于可视化不适合用来做特征工程因为它们不保留全局结构映射结果对超参数敏感无法对未知样本做变换。PCA操作时有个关键细节必须先标准化数据。因为PCA找的是最大方差方向如果特征量纲不同比如一个特征单位是万元另一个是百分比方差大的特征会主导主成分结果毫无意义。另一个细节是主成分数量的选择通常看累计解释方差比explained variance ratio达到85%~95%就可以。from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_scaled scaler.fit_transform(X) pca PCA(n_components0.95) # 自动保留累计方差达到95%的主成分数 X_pca pca.fit_transform(X_scaled) print(保留主成分数:, pca.n_components_) print(各主成分方差占比:, pca.explained_variance_ratio_)以10个数值特征的数据为例如果前3个主成分累计方差就达到93%那么就可以放心地把特征从10维压到3维。压缩后模型训练时间大幅下降有时候效果反而更稳因为去掉了噪声和冗余信息。4.3 特征选择实战用Lasso和RFE快速落地L1正则化天然可以把不重要的特征权重压到0这种稀疏性非常适合特征选择。我用LassoCV做特征选择的标准流程是这样的标准化所有数值特征。用LassoCV做交叉验证自动找到最优惩罚系数alpha。提取系数不为0的特征作为候选集合。与业务方确认这些特征是否合理而不是机械接受。递归特征消除RFE则是另一条路线它反复训练模型、剔除权重最小的特征直到达到预设数量。效果不错但计算代价比较高特征很多时速度会很慢建议先用Filter方法把特征数量降到几百以内再用RFE。注意特征选择永远不要只看统计指标一定要结合业务理解。我之前做过一个信贷违约预测统计指标把“近3个月查询次数”这个特征排得很靠后但信贷业务里这恰恰是高风险信号。数据驱动和业务经验必须结合不能偏废。5. 图片数据预处理的特殊性以ISIC2017数据集为例5.1 图片与表格数据到底差在哪前面的内容都在讲表格数据但很多实际项目CV、医疗影像、自动驾驶面对的是图片。图片数据的预处理思路和表格数据差别很大但核心目标是一致的让模型看到更“规整”、更有“区分度”的输入。这里我用ISIC2017数据集作为例子。ISIC2017是国际皮肤成像协作组发布的皮肤镜图像数据集包含约2000多张训练图像任务是皮肤病变分割和分类黑色素瘤、脂溢性角化病、普通痣。这类医学影像数据有几个典型问题类不平衡明显黑色素瘤样本远少于良性样本图像尺寸不统一图像存在拍摄光照差异、肤色差异、毛发遮挡等干扰标注掩膜需要和原图像素对齐。每一步都是预处理的内容。图片预处理一般包含尺寸统一、归一化、数据增强、掩膜对齐、类别权重处理。尺寸统一常用resize到固定大小比如256x256或224x224归一化则是把像素值从0-255缩放到模型输入的期望范围比如PyTorch的Normalize(mean, std)一般用ImageNet数据集的均值和标准差。数据增强包括随机旋转、翻转、缩放、裁剪、颜色抖动等目的不是“增加样本数”这么简单更重要的是让模型对变换不敏感提升泛化能力。5.2 从一张原始皮肤镜图片到可训练样本以ISIC2017为例一个标准预处理管线可以这样写把原始JPG图像尺寸统一到256x256用双线性插值不用直接拉伸因为会变形。可以先等比缩放再中心裁剪。像素归一化到[0,1]再按通道做标准化。对分割任务把原始掩膜图像二值化确保像素值是0或1并与原图保持相同尺寸。数据增强。分割任务的增强必须对原图和掩膜做相同变换比如旋转30度、水平翻转、随机裁剪到224x224。如果做分类任务对少数类样本进行过采样增强或者计算类别权重放入损失函数。在PyTorch里实现比较简单torchvision.transforms提供了很多现成组件难点在于“原图和掩膜必须同步变换”。我建议把原图和掩膜拼接成一个多通道张量一起变换或者自己写一个带seed的随机变换函数确保两个对象用同一组参数。from torchvision import transforms train_transform transforms.Compose([ transforms.Resize((256, 256)), transforms.RandomRotation(15), transforms.RandomHorizontalFlip(p0.5), transforms.ColorJitter(brightness0.2, contrast0.2), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ]) # 注意对分割掩膜不要用Normalize和ColorJitter值域必须保持0/1值得单独强调的一点训练阶段使用随机增强但验证和测试阶段只做尺寸调整和归一化不要再做随机增强。这是很多新手会犯的错误一旦验证集也用随机增强指标波动会很大模型好坏完全看不出来。另外增强不是越强越好过强的几何变换可能破坏医学图像的病理特征比如皮肤病变的对称性是诊断黑色素瘤的重要线索你用翻转和旋转时要有业务认知不能无脑套。5.3 类不平衡医学图像预处理的隐藏难点ISIC2017这样的数据集中正负样本比例严重失衡。如果在预处理阶段不做任何处理模型会本能地学会“全部预测为多数类”因为这样loss也能降到很低。常用的对策有三个重采样少数类做随机过采样多数类做随机欠采样。对图片数据过采样通常配合轻量数据增强进行。损失函数加权在交叉熵损失里给少数类更大的权重torch.nn.CrossEntropyLoss(weight...)直接传参即可。硬样本挖掘训练中途重点抽取模型容易分错的样本这个方法实现复杂一些但效果显著。我在ISIC2017上的实际做法是“类别权重 适度过采样”双管齐下分割任务还会配合Dice损失或Focal损失。这里不展开讲损失函数但大家要明白预处理不只是把像素变一下还包括数据层面的类别平衡策略。6. 常见问题与排查技巧实录6.1 让人头疼的五个经典场景标准化后模型效果反而变差了先看你的模型是不是树模型。决策树、随机森林、XGBoost对单调变换不敏感标准化对它们无益甚至浪费时间。线性模型、SVM、神经网络、KNN这类依赖特征尺度的模型标准化通常是必须的。其次检查你是不是在全数据集上fit了scaler导致信息泄露。One-Hot编码后内存爆炸高基数类别特征比如用户ID、城市直接One-Hot会产生海量稀疏列。一个城市特征如果有一千个取值One-Hot后就是一千列。这种情况建议改用目标编码、频率编码或者做类别合并把低频类别统一归为“其他”。填充缺失值之后数据分布怪异用均值填充后变量方差会被低估分布中间会出现一个尖峰。处理思路是改用随机填充从已有值的分布中抽样或模型填充并配合缺失指示特征。pandas数据类型和预期不符读入数据后年龄列是object而不是int多半是混入了“未知”这类字符串。用pd.to_numeric(errorscoerce)把非法值转成NaN再走缺失值流程是最快的处理方式。图片训练时尺寸不统一报错最常见的错误是DataLoader返回的batch里图片张量shape不一致。这时候要么全部resize到固定尺寸要么用collate_fn做自定义批次拼接但最好的做法还是统一尺寸省时省力。6.2 一个可直接套用的预处理速查表场景首选方案备选方案注意事项数值特征量纲不同StandardScalerRobustScaler先拆分训练/测试集数值特征偏态严重Log变换Box-Cox变换后重新检查分布缺失率5%删除对应行中位数填充样本量充足时才删缺失率30%~60%模型填充中位数指示列合理生成缺失指示特征无序类别特征One-Hot目标编码高基数类别避免One-Hot特征数量过多滤法嵌入法结合PCA线性模型优先考虑PCA图片尺寸统一Resize中心裁剪Padding补齐分割任务掩膜同步处理标签不平衡类别权重过采样增强验证集保持原始分布6.3 我的几条独家避坑经验最后聊聊在数据预处理这条路上我觉得最实用的几条经验第一过程留痕。每次做清洗或转换时把操作步骤和参数记录下来建议写成一个可重复执行的预处理脚本而不是在notebook里手动点几十次。这样模型效果不好时可以随时回溯看看是哪一步预处理引入的问题。第二保存中间结果。原始数据、清洗后数据、转换后数据分别保存一份尤其是清洗后那份后续做特征扩展时能省很多事。我一般会在项目目录下建data/raw、data/clean、data/processed三个文件夹。第三用视觉化验证预处理效果。标准化前后各画一次直方图PCA降维后做一次二维散点图上色看类别可分性图片预处理后把图像按batch可视化保存几张。眼睛看到的确认比单纯看代码和数据shape可靠得多。我吃过亏——有一次图片标准化后出现了全黑图就是因为图像通道顺序搞错了模型一直在训练垃圾。第四不要迷信单一方法。在网上经常能看到“某大佬只用均值填充”“某比赛冠军全靠目标编码”的说法但任何方法都有适用边界。我的一般做法是同一种预处理方法跑不同的下游模型用收敛时间和验证集指标综合判断选那个让模型“更快变好”的方案。第五尽早把预处理变成pipeline。如果项目很短用pandas一个个处理也能应付但项目一旦涉及交叉验证、超参搜索就必须把预处理步骤封装进Pipeline。我自己现在做任何一个建模任务第一步永远是定义自己的预处理管线后面训练、调参、预测全部走管线最大程度防止信息泄露和步骤遗漏。这个习惯让我至少省下了一半的返工时间。7. 思维导图思路把整个预处理体系装进一张图虽然这篇文章不会真正画图但为了帮你搭建整体认知我建议你自己动手时按以下分支组织思维导图根节点数据预处理数据清洗缺失值处理、异常值处理、重复值处理、一致性处理数据集成多源合并、实体识别、冗余属性识别、冲突检测数据转换标准化/归一化、离散化、类别编码、函数变换、时间/文本处理数据降维特征选择Filter/Wrapper/Embedded、线性降维PCA/LDA、非线性降维t-SNE/UMAP图片专用尺寸统一、像素归一化、数据增强、掩膜同步、类不平衡处理工具链pandas、sklearn.preprocessing、sklearn.decomposition、torchvision.transforms在思维导图里每个叶子节点旁边可以标注一句话“什么时候用”和“什么时候不用”这一步做完你对数据预处理的体系认知就基本到位了。后续再遇到任何新数据集顺着这张图的节点走一遍基本不会漏掉关键步骤。我自己做这行这些年最大的一个感受是模型结构可以借鉴开源参数可以靠调参工具搜索但数据预处理这个环节永远逼着你真正去理解自己的数据和业务场景。同样的数据集不同的人处理出来的效果天差地别差别往往不在算法而在对数据细节的敏感度和对业务问题的理解深度。所以面对任何新项目多花点时间在你的数据上吧它会用最终的模型效果回报你。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑