pandas数据清洗三板斧:映射(map)、替换(replace)与重命名(rename)实战解析
1. 数据清洗为什么需要三板斧刚接触数据分析时我最头疼的就是处理原始数据。比如拿到一份用户调查表性别栏写着1和2城市编码是莫名其妙的数字还有各种NA、NULL、空混用的缺失值。更崩溃的是列名全是Q1、Q2这样的编号根本看不出含义。这时候就该祭出pandas的数据清洗三板斧了——map映射、replace替换和rename重命名。这三个函数就像流水线上的三道工序能把杂乱的数据变得规整map把1和2变成男和女这类可读文本值替换replace把空、NA统一处理成标准缺失值异常值修正rename把Q1改成用户年龄这类有意义的列名结构优化举个真实案例某次分析销售数据时原始表格里商品类目用001/002编码地区用拼音缩写还有混用的缺货/无库存等表述。用这三板斧处理后数据立刻变得清晰可用。2. 第一板斧map映射实战2.1 字典映射数字转文本假设我们拿到这样一份学生数据import pandas as pd data { 学号: [101, 102, 103], 性别: [1, 2, 1], # 1男2女 年级: [3, 5, 2] # 数字代表年级 } df pd.DataFrame(data)用字典映射转换性别列gender_map {1: 男, 2: 女} df[性别] df[性别].map(gender_map)执行后数据学号 性别 年级 0 101 男 3 1 102 女 5 2 103 男 22.2 函数映射复杂逻辑处理当转换逻辑比较复杂时可以用函数。比如把年级数字转为中文def grade_to_text(x): grade_map {1:一年级, 2:二年级, 3:三年级, 4:四年级, 5:五年级, 6:六年级} return grade_map.get(x, 未知) df[年级] df[年级].map(grade_to_text)2.3 处理缺失值的技巧map映射时如果遇到字典里没有的键默认会变成NaN。比如上面的grade_map没有定义7年级如果数据里有7就会变成缺失值。有两种处理方式使用get()方法设置默认值grade_map.get(x, 其他) # 不存在的键返回其他设置na_action参数df[年级].map(grade_map, na_actionignore) # 保留原值3. 第二板斧replace替换妙用3.1 批量替换异常值replace比map更强大的地方在于可以全表替换。比如这份商品数据df pd.DataFrame({ 商品: [A, B, C], 库存: [有货, 缺货, 无库存], 价格: [100, 待定, 200] })统一库存状态和价格标识df.replace([缺货, 无库存], 缺货, inplaceTrue) df.replace(待定, pd.NA, inplaceTrue) # 转为标准缺失值3.2 正则表达式替换处理用户输入的地址数据时特别有用address_data pd.Series([ 北京市海淀区, 上海浦东新区, 广州市天河区 ]) # 去掉市和区 address_data.replace(r市|区, , regexTrue, inplaceTrue)3.3 分列差异化替换可以通过字典指定每列的替换规则df.replace({ 库存: {有货: 1, 缺货: 0}, 价格: {待定: None} }, inplaceTrue)4. 第三板斧rename重命名艺术4.1 列名规范化当列名不符合分析要求时df pd.DataFrame({ 1.学号: [101, 102], 2.姓名: [张三, 李四], 3.成绩: [85, 92] }) df.rename(columns{ 1.学号: id, 2.姓名: name, 3.成绩: score }, inplaceTrue)4.2 批量重命名技巧当需要统一添加/删除前缀时# 添加前缀 df.add_prefix(stu_) # 删除前缀 df.columns df.columns.str.replace(r^\d\., , regexTrue)4.3 索引重命名处理时间序列数据时经常需要df pd.DataFrame({ value: [10, 20] }, index[2023Q1, 2023Q2]) df.rename(indexlambda x: x.replace(Q, 季度), inplaceTrue)5. 三板斧组合实战现在我们来处理一个真实场景的电商数据集# 原始数据 raw_data { prod_id: [101, 102, 103], status: [1, 3, 2], # 1现货 2预售 3缺货 price: [100, 待询价, 200], Qty: [10, 0, 5] } df pd.DataFrame(raw_data) # 第一步状态映射 status_map {1: 现货, 2: 预售, 3: 缺货} df[status] df[status].map(status_map) # 第二步价格清洗 df[price] df[price].replace({ : , 待询价: None }, regexTrue).astype(float) # 第三步列名重命名 df.rename(columns{ prod_id: 商品ID, Qty: 库存 }, inplaceTrue)处理后的数据商品ID 状态 价格 库存 0 101 现货 100.0 10 1 102 缺货 NaN 0 2 103 预售 200.0 56. 避坑指南map性能陷阱大数据量时map比replace慢可以用replace替代简单映射# 慢 df[gender].map({1:男, 2:女}) # 快 df.replace({gender: {1:男, 2:女}})链式操作问题连续多个操作时建议要么都用inplaceTrue要么都赋值给新变量# 不推荐部分生效 df.rename(...).replace(...) # 推荐方式1 df.rename(..., inplaceTrue) df.replace(..., inplaceTrue) # 推荐方式2 new_df df.rename(...).replace(...)特殊字符处理列名含空格或特殊符号时建议先用rename规范化df.rename(columnslambda x: x.strip().replace( , _), inplaceTrue)