Python数据预处理实战:从数据清洗到特征工程的全流程指南

发布时间:2026/10/12 1:47:21
Python数据预处理实战:从数据清洗到特征工程的全流程指南 简介针对数据分析中常见的数据缺失问题这份PDF是一份面向初学者的Pandas数据清洗专题笔记围绕教材第4.11节展开。内容先讲解缺失值的产生原因与判断方法再逐一说明删除缺失行或列时的各种控制选项包括按行过滤还是按列过滤、全部缺失才删还是存在缺失即删、至少保留多少个非空值、只在指定列中查找等随后介绍用固定值填充、用前值后值填充以及线性插值等方法。文中配有含有姓名、年龄、工资、性别等字段的示例表格和可直接运行的练习代码读者可反复对照练习在真实场景中完成缺失值统计、删除、填充等操作逐步掌握数据预处理的标准流程。资源仅包含一个PDF文件约375KB轻量便携适合课程学习或日常速查该内容发布以来已有1349人学习下载示例典型、步骤清晰能有效帮助初学者避开缺失值处理的常见误区。1. 数据预处理为什么说「脏数据进脏分析出」一份白酒销售表里订单金额带着货币符号和千分位逗号销量列偶尔出现负数地区字段混着“贵州”和“贵州省”——不处理直接跑分析分组金额会算错、均值会被负数带偏、地区统计会凭空多出重复项。这个标题对应一份 Python 数据分析实践讲义的第一部分标记 new 表示是修订后的新版本聚焦的是建模和可视化之前那道关键工序数据预处理。它解决“拿到手的数据不能直接用”的问题适合刚学完 Python 基础、准备跑第一个真实数据分析项目的人也适合被脏数据反复折磨的从业者。数据预处理不是体力活它决定分析结论是否可信。这份讲义值得通读一遍再拿自己的数据完整走一遍。2. 数据清洗三件套缺失值、重复值与异常值的处理边界真实项目里数据清洗占掉六成时间一点都不夸张。分析做不出结论回头查数据往往发现源头就有问题。这里用一份白酒销售数据集当例子把清洗拆成三个步骤先摸底再处理缺失最后处理重复和异常。每段都会给出可以直接复制的代码和参数说明新手照做能跑通熟手可以对照检查自己的边界条件有没有漏。2.1 先摸清数据底细info()、describe()、isnull().sum() 三件套不要一上来就动手删先花十分钟把数据底细摸清。拿到 CSV 后我一般先跑一套三件套比 head() 直接看前几行有用得多。import pandas as pd df pd.read_csv(baijiu_sales.csv, encodingutf-8-sig) print(df.info()) print(df.describe()) print(df.isnull().sum()) print(f原始数据 shape: {df.shape})逻辑说明df.info()会输出每个字段的非空计数和数据类型。之前处理一份电商快递账单时就是靠这行发现quantity列是 object——原因是有几条记录写成了1,000这种带千分位逗号的字符串pandas 把它整个当成文本了。df.describe()默认只对数值列算统计量量纲差异大的列在这里会直接暴露比如单价在几百元、销量在几万两个数字放在一张表里就能看出要不要做标准化。df.isnull().sum()按列统计缺失数量后面填充优先级全靠它。参数说明read_csv的encodingutf-8-sig专门对付 Excel 导出的 CSV能绕开 UTF-8 BOM 头导致的列名乱码如果源文件是 GBK 编码改成encodinggbk或encodinggb18030即可。describe()加上includeobject参数会顺带列出字符串列的去重数量对发现“贵州”和“贵州省”这种同义异形值很有帮助。2.2 缺失值处理删除、填充、插值什么时候用哪个缺失值没有万能解法先判断缺失机制再动手如果缺失是完全随机的比如客户漏填了生日删掉这些行对整体分布影响不大如果缺失和业务强相关比如高端白酒的团购价经常不填因为要面议直接删行会把高价交易系统性丢掉这部分缺失叫“非随机缺失”更适合单独标记或插补。缺失情况建议做法缺失列基本无业务意义如备注直接删列关键字段缺失且占比 5%直接删行数值列缺失 5%30%中位数/均值填充或加缺失标记数值列缺失 30%慎重填充必要时删列时间序列类字段前向填充或插值# 1) 缺失率超过70%的列直接删 df df.drop(columns[c for c in df.columns if df[c].isnull().mean() 0.7]) # 2) 关键字段缺失的行删除 key_cols [order_id, sku, amount] df df.dropna(subsetkey_cols) # 3) 数值列用中位数填充 num_cols df.select_dtypes(include[float64, int64]).columns for col in num_cols: if df[col].isnull().sum() 0: df[col] df[col].fillna(df[col].median()) # 4) 时间序列类字段前向填充 df[stock_level] df[stock_level].ffill()逻辑说明dropna(subsetkey_cols)只检查这三列其他列再缺也不会影响这一行的去留避免误删有价值记录。select_dtypes自动选出数值列批量填充不用手工一列列写。fillna用的是中位数而不是均值原因是销量这类字段经常有极端大单均值会被拉高填充进去就相当于给缺失值整体注入了一个偏高的基准分布会变形。参数说明ffill()默认沿行方向从上往下填充适合“库存读数沿用上一次”的业务逻辑如果要在同一渠道内做填充先groupby(channel)再调用transform就能避免不同渠道的数据互相串味。2.3 重复值与异常值去重别误伤异常值别一刀切重复值最常见的坑不是没去掉而是去过头。同一用户在同一天买了两瓶同款白酒订单明细里有两行几乎一样的数据只是 order_id 不同或 item_no 不同——如果按全部列去重看起来是“重复”实际是两笔合法交易。正确做法是先想清楚唯一键是什么。# 按唯一键检查重复而不是全列去重 dup_cnt df.duplicated(subset[order_id, item_no]).sum() df df.drop_duplicates(subset[order_id, item_no], keepfirst) before df.shape[0] # ... 中间经过若干清洗步骤 ... after df.shape[0] print(f清洗影响行数: {before - after})逻辑说明duplicated(subset...)指定业务唯一键keepfirst保留第一次出现的行。每次清洗前后都记录 shape一旦后面发现统计结果对不上能快速定位是哪一步删错了这点是血泪经验。异常值处理要更克制。统计上超过 3 倍标准差的点未必是脏数据可能是真实的大额团购、双十一峰值。我一般用 IQR 法把可疑点筛出来先看数量再看业务方意见绝不直接删。Q1 df[amount].quantile(0.25) Q3 df[amount].quantile(0.75) IQR Q3 - Q1 lower Q1 - 1.5 * IQR upper Q3 1.5 * IQR suspect df[(df[amount] lower) | (df[amount] upper)] print(suspect.sort_values(amount, ascendingFalse).head(20))参数说明IQR 系数 1.5 是 Tukey 的经典默认值适合大多数分布如果业务上极端值本来就常见把系数放宽到 3 能减少误杀。筛出来的 suspect 列表建议导出成 CSV 交给业务方人工核对这条“人肉工序”虽然麻烦但比自动清理安全得多——数据预处理里最怕的就是“看起来正确”的自动规则把真实业务模式当噪声删了。另外补一个常见脏数据形态数值列被读成 object。Excel 里的1,000或¥128会让 pandas 把整列推断为字符串先转成干净字符串再去掉符号。df[amount] ( df[amount] .astype(str) .str.replace(,, , regexFalse) .str.replace(¥, , regexFalse) .astype(float) )这段代码的价值在于replace用regexFalse避免把正则元字符当通配符astype(float)转换失败会抛异常方便第一时间发现数据里还有没清理干净的怪值。3. 数据变换标准化、归一化与类别编码的参数怎么设数据变换的作用是把不同口径的字段对齐。这个环节最容易犯的错是不看场景直接套 sklearn结果模型能跑解释却成了玄学。这一章围绕三个高频场景展开数值特征怎么缩放、类别特征怎么编码、连续特征怎么分箱。3.1 Z-score 标准化和 Min-Max 归一化场景错了就出玄学结果Z-score 标准化的公式是x (x - mean) / std变换后均值 0、标准差 1Min-Max 归一化是x (x - min) / (max - min)输出落在 [0,1] 区间。选哪个不看个人习惯看场景。线性回归、逻辑回归、SVM、K-Means、PCA 这些方法对特征尺度敏感需要标准化或归一化决策树和基于树的集成模型随机森林、XGBoost、LightGBM只按特征值排序切分缩放不影响结果但也不会有坏处。分布偏斜严重、且存在极端值时Min-Max 会把正常数据挤压到非常窄的区间此时 Z-score 因为用标准差做分母对极端值更稳健。from sklearn.preprocessing import StandardScaler, MinMaxScaler from sklearn.model_selection import train_test_split X df[[amount, discount_rate, stock_level]] X_train, X_test, y_train, y_test train_test_split( X, df[is_reorder], test_size0.2, random_state42 ) scaler StandardScaler().fit(X_train) X_train_scaled scaler.transform(X_train) X_test_scaled scaler.transform(X_test)逻辑说明这段代码的关键不在选哪个 scaler而在 fit 和 transform 的对象必须分开。scaler 只在训练集上 fit算出均值和标准差测试集只 transform用训练集的那组参数做变换。如果拿 X_test 单独 fit测试集的信息就会泄漏到模型评估里后面的准确率全都不作数。参数说明StandardScaler的with_mean默认为 True处理稀疏矩阵时要设成 False否则均值中心化会把稀疏结构破坏掉。MinMaxScaler的feature_range可以改成(-1,1)做神经网络输入时经常这么调因为很多激活函数在 (-1,1) 区间收敛更稳。还有一个容易漏的点标准化一定要在缺失值填充之后做否则 fillna 填进去的值会先被当成真实值参与均值和方差计算。3.2 类别特征编码LabelEncoder、OneHotEncoder、OrdinalEncoder 怎么选类别特征编码是数据预处理里翻车率最高的地方之一。最常见的误用是拿 LabelEncoder 给“地区”这类无序字段编码把“北京、上海、广州”变成 0、1、2——三个数字引入大小关系树模型可能会做出“2 1 0”这种无意义的切分线性模型也会把地区当成连续变量解释。分类标准很简单无序类别用 OneHotEncoder有序类别用 OrdinalEncoder只有标签 y 本身才用 LabelEncoder。from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder # 无序类别OneHot测试集遇到新类别不报错 onehot OneHotEncoder(handle_unknownignore, sparse_outputFalse) region_encoded onehot.fit_transform(df[[region]]) # 有序类别按业务顺序指定categories ordinal OrdinalEncoder(categories[[低, 中, 高]]) df[level_encoded] ordinal.fit_transform(df[[level]])逻辑说明OrdinalEncoder的categories参数是它的灵魂按业务含义排好顺序低中高编码结果才有数学意义。OneHotEncoder的handle_unknownignore是上线时最关键的参数训练集里没出现过的地区默认会直接报错设成 ignore 后新类别会被编码成全 0 向量模型不至于崩。参数说明sparse_outputFalse让返回结果是稠密数组方便直接转 DataFrame 和后续特征拼接如果类别特别多可以配合pd.get_dummies做 top-K 截断只保留出现频率最高的前 K 个类别低频类别合并成“其他”避免维度爆炸。3.3 连续特征离散化等宽分箱与等频分箱的取舍把连续特征切成区间一是为了报表好讲二是为了消除线性模型对单调性的假设。pandas 里对应两个函数pd.cut等宽切pd.qcut等频切。等宽分箱实现简单但在分布偏斜时容易切出空箱等频分箱每箱样本数相等边界会落在数据密集的地方。分箱方式边界依据优点风险pd.cut 等宽数值范围均分边界整齐好解释偏斜数据产生空箱pd.qcut 等频分位数每箱样本均衡边界值不直观# 等宽按数值区间均分5段 df[amount_bin] pd.cut(df[amount], bins5) # 等频按分位数切4段重复边界自动丢弃 df[amount_qcut] pd.qcut(df[amount], q4, duplicatesdrop)逻辑说明白酒价格这种从几十到几千的字段用等宽切 5 段很可能前三箱都挤在低价区后两箱几乎没数据用等频切每一箱样本量相同分位数边界还能对应“经济型、中端、高端、超高端”这种业务档位。参数说明pd.cut的bins可以传整数也可以传自定义列表如bins[0, 200, 500, 1000, 99999]用业务阈值替代统计阈值解释性更强pd.qcut的duplicatesdrop必须带上当数据里有大量相同值导致分位数边界重合时不加这个参数会直接抛异常。分箱之后别忘了一个动作把分箱结果转成哑变量或有序编码后再进模型直接用字符串区间会让模型报特征无法解析的错。这一步顺序错了后面调参全是白费。4. 数据规约与特征构造降维一半还能保住信息量的做法数据规约回答一个问题能不能用更少的特征表达同样的信息。特征太多不仅拖慢训练还会引入噪声和共线性。这一章给三个惯用做法相关性分析与方差过滤、PCA 降维、以及从时间戳和业务口径里构造新特征。数据分析的方法很多但规约这步几乎每个项目都能用上。4.1 相关性分析与方差过滤先砍冗余列再谈建模两个高度相关的特征同时进入线性模型系数会互相拉扯今天跑出来正号、明天跑出来负号模型变成黑匣子。处理办法是先算相关矩阵把相关性超过阈值的高相关特征对列出来。corr df.corr(numeric_onlyTrue) high_corr_pairs [] for col in corr.columns: for idx in corr.index: if col ! idx and abs(corr.loc[idx, col]) 0.9: high_corr_pairs.append((idx, col, corr.loc[idx, col]))逻辑说明先只看数值列的相关性。高相关对找到后不用两个都删保留业务上更核心的那个比如“含税金额”和“不含税金额”相关性接近 1保留一个即可。数值列之外的常量列也要处理用VarianceThreshold看方差方差为 0 的列对模型没有任何贡献。from sklearn.feature_selection import VarianceThreshold selector VarianceThreshold(threshold0.01) X_reduced selector.fit_transform(X) kept_cols X.columns[selector.get_support()]参数说明threshold0.01表示标准差低于 0.1 左右的列会被剔除这个阈值要结合特征本身的量纲调标准化之后再用更保险。VarianceThreshold 的问题是它只看方差不看预测能力所以只适合做第一道粗筛真正选特征还要靠模型特征重要性或业务判断。4.2 PCA 降维的落地参数n_components 选多少、主成分怎么解释PCA 把多个相关特征压缩成一组互不相关的主成分常用场景是特征维度很高、需要先降维再喂给模型。n_components有两种给法给整数表示保留前 K 个主成分给 0 到 1 之间的小数表示保留至少这么多比例的方差。我一般给 0.95先保留 95% 的信息再观察。from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA X_scaled StandardScaler().fit_transform(X_train) pca PCA(n_components0.95, random_state42) X_pca pca.fit_transform(X_scaled) print(pca.explained_variance_ratio_.cumsum())逻辑说明PCA 对尺度极其敏感。如果跳过来标准化这一步量纲大的特征比如金额会直接主导主成分降出来的结果跟业务含义八竿子打不着。explained_variance_ratio_.cumsum()输出累计方差贡献率用来检查你设置的 0.95 到底覆盖到第几个主成分。参数说明random_state42固定随机种子保证每次跑出的主成分方向一致否则同一份数据两次出图不同报告没法写。解释主成分时要克制主成分是原始特征的线性组合不能直接说“第三主成分就是库存”只能说它主要由哪几个原始变量解释。用 PCA 做压缩输入、去噪、可视化是合理的拿它做业务归因解释就超出了它的能力范围。4.3 特征构造把时间戳拆成年月日周比盲目调参有用时间字段是特征构造里最被浪费的信息。订单时间如果只当字符串存着模型学不到周期性拆开之后“夜间下单”“周末下单”这类行为特征往往比一堆统计特征更有效。df[order_time] pd.to_datetime(df[order_time]) df[order_hour] df[order_time].dt.hour df[order_weekday] df[order_time].dt.weekday df[is_weekend] df[order_weekday].isin([5, 6]).astype(int) df[order_month] df[order_time].dt.month逻辑说明dt.hour提取小时dt.weekday返回 0 到 6isin([5,6])把周六日映射成 1其余 0。这些派生特征在白酒销售里能区分商务宴请工作日晚间和家庭聚餐周末中午是原始时间戳直接做特征做不到的效果。如果要构造滞后特征比如“上周同一天的销量”用 shift 注意别跨实体df[sales_last_week] ( df.groupby(sku)[sales] .shift(7) )参数说明groupby(sku)确保每条记录只参考同一款商品自己的历史shift(7)在日粒度数据里取上周同一天的值。这里最大的风险是未来信息泄漏——如果数据里每条记录本身已经包含当天的汇总再用shift(7)时要注意是否跨到了不可见的未来窗口。构造完新特征后回跑一遍相关矩阵确认新特征之间没有高相关再进入建模环节。5. 数据预处理避坑指南五个让分析结果走形的经典错误这一章是数据预处理的踩坑合集。以下五个问题我都在项目里真实遇到过每条按“现象、原因、解决”写读者可以对照自己的脚本逐一排查。注意这五条坑不按严重程度排序但 5.1 和 5.2 直接影响模型评估是否可信建议每次建模前优先自查。5.1 拆分数据集忘了固定 random_state每次跑结果都不一样现象同一份数据同一个模型连续跑三次准确率波动好几个点。调参的人开始怀疑模型代码是不是有 bug。原因train_test_split默认每次随机划分没有固定种子训练集和验证集每次不同评估结果自然不稳定。解决在拆分时设置random_state42并且全流程保持同一个种子。X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy )stratifyy也很关键分类问题里用它确保训练集和测试集的类别比例与原数据一致避免某一次拆分把少数类全分到测试集。神经网络、XGBoost 这类算法内部也有随机源训练时同样要设置 seed否则即使数据拆分固定了结果还是会在小范围内浮动。规范化地固定所有随机源是数据预处理阶段最容易被新手忽略、却对结果复现影响最大的习惯。5.2 对测试集也做了 fit_transform信息泄漏的教科书级翻车现象模型在验证集上跑出很高的分数领导很高兴结果一上线效果断崖式下跌。原因预处理时用全量数据 fit 了 scaler测试集的均值和标准差也参与了计算测试集的信息在训练阶段就被模型看到了这叫信息泄漏。解决scaler、编码器、PCA 都在训练集上 fit测试集只 transform。scaler StandardScaler().fit(X_train) X_train_scaled scaler.transform(X_train) X_test_scaled scaler.transform(X_test)把 fit 和 transform 分开写虽然多一行代码却是防止泄漏最简单可靠的方式。更保险的做法是直接用 sklearn 的 Pipeline把 scaler 和模型串在一起fit 时只接触训练集预测时自动执行同一套变换从机制上杜绝“测试集被提前看光”的翻车现场。5.3 缺失值统一填均值方差被压缩结论被带偏现象填充后数值列的均值没变化但标准差明显变小画出来的分布图中央变尖、两边变薄。原因把所有缺失值替换成均值等于人为往均值点堆了一堆数据方差被严重压缩后续回归系数的标准误会被低估。解决先看缺失比例再决策比例低直接删行比例高、又不想删列时用中位数或插值并额外生成一列 is_missing 标记让模型自己学习“缺失”这个状态是否重要。df[amount_missing] df[amount].isnull().astype(int) df[amount] df[amount].fillna(df[amount].median())is_missing 列的成本极低但经常能帮模型捕捉到“缺失本身是一种信息”的业务规律。比如高端白酒价格缺失往往意味着面议面议订单的成交率本身就不同这个标记比硬填充有价值得多。再提醒一句时间序列字段别一律用均值ffill 和线性插值通常更符合业务直觉。5.4 标准化之后直接拿数值做业务报表销售额变成了负数现象分析报告里出现“平均销售额为 -0.23”业务方直接质疑数据是不是错了。原因Z-score 标准化把销售额转成了相对均值的距离负值表示低于平均水平不是真的亏钱。解决报表和业务沟通用原始值模型输入用标准化的值两条口径分开走。如果必须展示标准化后的数值Min-Max 归一化到 [0,1] 区间保留单调对应关系比带着负号解释更容易被业务接受。这个问题的根源在于“数据变换服务于模型而不是服务于人”。数据分析与可视化实践里经常见到把标准化数据直接画进趋势图图的形状是对了但坐标轴的含义变了读者很容易误读。预处理做完最好保留一份原始数据和一份建模数据报表只用前者模型只用后者。5.5 分箱边界拍脑袋等宽分箱切出一堆空箱现象pd.cut把价格字段切成 5 段结果中间两段样本数接近于 0画出来的直方图中间凹进去一块看起来像数据造假。原因数据分布偏斜严重时等宽分箱的边界不与数据分布对齐大量样本挤在低区间高区间基本为空。解决用pd.qcut等频分箱按分位数切保证每箱样本量接近如果业务上必须用固定边界比如价格门槛先把边界写成列表再用pd.cut(binslist)实现。price_bins [0, 100, 300, 800, 99999] df[price_level] pd.cut(df[price], binsprice_bins)参数说明bins 列表的上界要按业务真实范围留余量比如最高单价几万块上界写 99999 就不容易产生 NaN如果担心未来出现超界值可以先clip(upper99999)再切箱。分箱后检查每个箱的样本量用value_counts(normalizeTrue)看占比分布空箱或占比低于 5% 的箱需要重新定义边界这是让分箱真正可解释的最后一道工序。6. 把预处理流程固化成 pipeline一个能反复复用的模板前面几章的清洗和变换如果写成散落的脚本每次换数据都要重新编排漏一步就翻车。我现在的习惯是把它固化成一条流水线。6.1 用 sklearn Pipeline 串起清洗、变换与建模from sklearn.pipeline import Pipeline from sklearn.impute import SimpleImputer from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression pipe Pipeline(steps[ (imputer, SimpleImputer(strategymedian, add_indicatorTrue)), (scaler, StandardScaler()), (model, LogisticRegression(max_iter1000, random_state42)), ]) pipe.fit(X_train, y_train) acc pipe.score(X_test, y_test)fit 和 predict 时整条链路自动执行imputer 和 scaler 不会再犯测试集信息泄漏的错。SimpleImputer里add_indicatorTrue会自动生成缺失标记列对应第 5 章的 is_missing 思路。6.2 手写 Transformer把业务清洗规则封装进流程业务规则没法用现成的 Transformer 表达就写一个自定义类from sklearn.base import BaseEstimator, TransformerMixin class MoneyCleaner(BaseEstimator, TransformerMixin): def fit(self, X, yNone): return self def transform(self, X): X X.copy() for col in [amount, discount]: X[col] ( X[col].astype(str) .str.replace(,, , regexFalse) .str.replace(¥, , regexFalse) .astype(float) ) return Xfit 返回 selftransform 里做业务清洗符合 sklearn 的接口约定就能插进 Pipeline 当普通一步用。6.3 跑通验证一份脏数据小样快检每次换新数据源我会先抽 100 行跑一遍 pipeline打印清洗前后的 describe 对比。重点看三个指标缺失值数量是否归零、金额列的最大最小值是否合理、行数变化是否符合预期。这套快速检查能在半小时内定位数据里新出现的脏格式而不是等模型训练完才一脸懵。以前我习惯在每个脚本里重复写清洗逻辑后来发现数据源一变更改起来要翻好几个文件。把预处理固化成 pipeline 之后新项目只需要替换读数和业务字段流程本身直接复用。这个习惯帮我挡掉过好几次线上数据变更带来的坑现在分享给你希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询