Pandas 2.2 数据清洗实战:map、replace、rename 3种方法处理5类脏数据
Pandas 2.2 数据清洗实战:map、replace、rename 3种方法处理5类脏数据
数据清洗是数据分析过程中最耗时但也最关键的环节。真实世界的数据往往充满各种"脏数据"问题:编码混乱的类别值、非标准化的命名、异常值、缺失值以及格式不统一的文本。本文将聚焦Pandas 2.2版本中最实用的三种数据清洗方法——map、replace和rename,通过解决五类典型脏数据问题,带你掌握高效的数据清洗技巧。
1. 编码映射:用map处理类别型数据
实际业务数据中,我们经常会遇到用数字编码表示的类别数据。比如性别字段存储为1和2,产品类型用101-199的数字区间表示。这类数据如果不经过解码,分析结果将难以理解。
1.1 字典映射法
最直接的解决方案是使用字典建立编码与含义的映射关系:
import pandas as pd # 示例数据:学生信息表 data = { 'student_id': [101, 102, 103], 'gender': [1, 2, 1], # 1:男, 2:女 'score': [85, 92, 78] } df = pd.DataFrame(data) # 建立性别编码映射字典 gender_map = {1: '男', 2: '女'} # 应用map进行转换 df['gender'] = df['gender'].map(gender_map)执行后,gender列将从[1,2,1]变为['男','女','男']。这种方法简洁高效,特别适合处理固定编码的类别变量。
1.2 函数映射法
当映射逻辑较复杂时,可以使用函数作为map的参数:
# 定义成绩等级转换函数 def score_to_grade(x): if x >= 90: return 'A' elif x >= 80: return 'B' elif x >= 70: return 'C' else: return 'D' # 应用函数映射 df['grade'] = df['score'].map(score_to_grade)对于简单的逻辑,lambda函数更加简洁:
# 使用lambda简化 df['grade'] = df['score'].map(lambda x: 'A' if x >= 90 else 'B' if x >= 80 else 'C' if x >= 70 else 'D')1.3 处理缺失值
map方法默认会将无法映射的值保留原样,我们可以通过na_action参数控制缺失值行为:
# 原始数据包含None df.loc[1, 'gender'] = None # 忽略NaN的映射 df['gender'] = df['gender'].map(gender_map, na_action='ignore')提示:当需要映射的列可能包含缺失值时,建议始终设置na_action='ignore'以避免意外错误。
2. 批量替换:用replace处理异常值与标准化
replace是Pandas中最强大的值替换工具,特别适合处理以下场景:
2.1 单值替换
# 将所有的-1替换为NaN df.replace(-1, pd.NA) # 多列同时替换 df.replace({'gender': {None: '未知'}, 'score': {0: pd.NA}})2.2 列表替换
# 批量替换多个值 df.replace(['优秀', '良好', '及格'], ['A', 'B', 'C']) # 正则表达式替换 df.replace(r'^\d+\.\d+$', '浮点数', regex=True)2.3 高级替换技巧
replace支持多种高级替换模式:
# 列特定替换 df.replace({'gender': {'男': 'M', '女': 'F'}, 'grade': {'A': 'Excellent'}}) # 类型特定替换 df.replace({'score': {r'[^\d]': pd.NA}}, regex=True)3. 列名清洗:用rename规范化数据结构
混乱的列名是常见的数据质量问题,rename方法提供了灵活的列名调整能力。
3.1 基本重命名
# 单个列重命名 df.rename(columns={'student_id': 'id'}, inplace=True) # 批量重命名 new_columns = { 'gender': '性别', 'score': '分数', 'grade': '等级' } df.rename(columns=new_columns, inplace=True)3.2 函数式重命名
# 统一去除列名前缀 df.rename(columns=lambda x: x.replace('student_', ''), inplace=True) # 标准化列名格式 df.rename(columns=lambda x: x.lower().replace(' ', '_'), inplace=True)3.3 索引重命名
rename同样适用于行索引的重命名:
# 重置索引并命名 df.reset_index().rename(columns={'index': 'original_index'}) # 多层索引重命名 df.rename(index={0: '第一行', 1: '第二行'}, level=0)4. 性能对比与最佳实践
三种方法各有优劣,下面是它们的核心差异对比:
| 方法 | 适用场景 | 性能特点 | 内存使用 |
|---|---|---|---|
| map | 单列元素转换 | 中等 | 低 |
| replace | 全表多值替换 | 快(向量化) | 高 |
| rename | 行列索引操作 | 极快 | 极低 |
注意:对于大数据集(>1GB),建议优先考虑replace的向量化操作,避免使用map逐元素处理。
5. 综合实战:处理真实脏数据
让我们通过一个综合案例演示如何处理真实场景中的混合脏数据问题:
# 模拟真实脏数据 dirty_data = { '用户ID': ['001', '002', '003', '004'], '性别': [1, 2, 3, 1], # 1:男, 2:女, 3:未知 '年龄': ['25', '三十', 'N/A', '42'], '消费金额': ['100.50', '200元', '--', '150.00'], '注册日期': ['2022-01-01', '2022/02/15', '无效日期', '2022-03-20'] } df = pd.DataFrame(dirty_data) # 第一步:性别编码转换 gender_map = {1: '男', 2: '女', 3: '未知'} df['性别'] = df['性别'].map(gender_map) # 第二步:年龄标准化 df['年龄'] = df['年龄'].replace({'三十': '30', 'N/A': pd.NA}).astype('float') # 第三步:金额清洗 df['消费金额'] = df['消费金额'].replace({'元': '', '--': pd.NA}, regex=True).astype('float') # 第四步:日期格式化 df['注册日期'] = pd.to_datetime(df['注册日期'], errors='coerce') # 第五步:列名标准化 df.rename(columns=lambda x: x.lower().replace(' ', '_'), inplace=True)经过这五步处理,原始脏数据被转换为整洁可分析的结构化数据。每种方法都在最适合的场景中发挥了最大效用。
