导读:本期聚焦于闲进程创作的《Pandas数据重塑怎么做?多列映射、数据转换与DataFrame合并实战详解》,敬请观看详情。数据处理过程中,把宽表变长表、按映射规则批量改写列值、再把多张表拼成一张完整数据集,几乎是每个做数据分析的人都绕不开的操作。本文围绕Pandas的数据重塑展开,重点讲解map、apply、merge、concat等核心方法的使用方式,包括多列同时映射的技巧、类型转换与自定义函数转换的对比、以及merge与concat在不同场景下的选择依据。文中配有可直接运行的代码示例,并总结了常见坑点,比如重复索引、映射产生NaN、合并后行数异常等问题,帮助你把杂乱的数据整理成适合分析的标准结构。

拿到一份原始数据,列名混乱、取值不规范、信息散落在多张表里,这种情况下直接做分析基本不可能出结果。Pandas提供了整套数据重塑工具,从单列映射到多列联动转换,从纵向堆叠到横向对齐合并,覆盖了数据清洗阶段的绝大部分需求。本文结合具体代码,把多列映射、数据转换和DataFrame合并这三个高频操作讲透。

Pandas数据重塑怎么做?多列映射、数据转换与DataFrame合并实战详解

一、多列映射:用map、replace和apply改写数据

映射操作的本质是把列中的原始值按照某个对照关系替换成新值。最常用的是Series.map,它接收一个字典或函数,把列里的每个元素按规则转换。比如把性别编码0和1换成可读文本,把部门缩写换成全称,一行代码就能搞定。

import pandas as pd

df = pd.DataFrame({
    'name': ['张三', '李四', '王五'],
    'gender': [0, 1, 0],
    'dept': ['RD', 'SALES', 'RD']
})

# 用字典做单列映射
df['gender'] = df['gender'].map({0: '男', 1: '女'})
df['dept'] = df['dept'].map({'RD': '研发部', 'SALES': '销售部'})
print(df)

需要注意的是,map遇到字典中不存在的键时会直接填NaN。如果数据里有脏值,比如dept列混进了一个'MKT',映射后这一行就变成缺失值。稳妥的做法是先检查未覆盖的取值,或者改用replace,它对未匹配的值会保持原样不动,不会产生NaN。这两种方法的差异在实际清洗工作中非常关键,很多莫名其妙的缺失值就是map用错了导致的。

当映射逻辑需要同时参考多个列时,map就不够用了,因为map只能作用于单个Series。这时有两个选择:一是用apply配合axis=1逐行处理,二是先用字典构建复合键再映射。例如根据性别和年龄段共同决定保费档位,逐行处理虽然直观,但数据量大时性能会明显下降,因为它本质上是Python级别的循环。

# 多列联动映射:根据性别和职级计算补贴
df['level'] = ['P5', 'P6', 'P7']

subsidy_map = {
    ('男', '研发部'): 800,
    ('女', '研发部'): 850,
    ('男', '销售部'): 1200,
    ('女', '销售部'): 1250,
}

df['subsidy'] = df.apply(
    lambda row: subsidy_map.get((row['gender'], row['dept']), 0),
    axis=1
)
print(df)

性能要求高的场景可以换一种思路:先用zip把多列拼成元组Series,再对它做一次map,这样能利用Pandas底层的向量化映射,速度比逐行apply快一个数量级。另外DataFrame.applymap(新版本中叫DataFrame.map)可以对整表每个元素做函数映射,适合批量格式化,比如把所有浮点数保留两位小数。

二、数据转换:类型转换、标准化与自定义函数

转换比映射的范围更广,除了替换值,还包括类型转换、数值标准化、字符串处理等。astype是最基础的类型转换工具,但遇到脏数据很容易报错,比如字符串列里混了一个空串,直接转int会抛异常。此时推荐用pd.to_numeric配合errors='coerce',转换失败的值会自动变成NaN,后续再统一处理缺失值。

df['salary'] = ['15000', '22000', '']

# 直接 astype 会报错,用 to_numeric 更稳妥
df['salary'] = pd.to_numeric(df['salary'], errors='coerce')
df['salary'] = df['salary'].fillna(df['salary'].median())

# 日期转换同样推荐专用函数
df['hire_date'] = pd.to_datetime('2023-0' + df.index.astype(str), format='%Y-%m%d', errors='coerce')
print(df.dtypes)

数值标准化也是常见需求,比如把薪资列缩放到0到1区间,或者做Z-score标准化。这些操作完全可以用向量化表达式完成,避免写循环。向量化写法不仅代码短,而且由NumPy底层执行,处理百万行数据也就是毫秒级的事。对于分组标准化的场景,比如每个部门内部单独做归一化,可以结合groupbytransform,transform返回的结果形状与原Series一致,可以直接赋值回新列。

# 分组内归一化:每个部门内部比较薪资才有意义
df['salary_norm'] = df.groupby('dept')['salary'].transform(
    lambda s: (s - s.min()) / (s.max() - s.min())
)
print(df)

自定义函数转换时有个容易忽略的坑:apply处理单列时,如果函数里返回了不同类型的值,结果可能变成object类型,后续数值计算会出错。建议在函数末尾显式用floatint包一层返回值,保证类型一致。此外,如果只是简单条件赋值,优先考虑np.wherenp.select,它们比apply快得多,代码也更清晰。

三、DataFrame合并:merge、join与concat的选择

合并操作分两个方向:横向按键对齐用merge,纵向堆叠用concatmerge类似SQL的JOIN,通过一个或多个键把两张表横向拼接。最常见的坑是合并后行数暴涨,这通常是因为连接键存在重复,产生了笛卡尔积。合并前用duplicated检查键的唯一性,是避免这类问题的有效手段。

emp = pd.DataFrame({
    'emp_id': [101, 102, 103],
    'name': ['张三', '李四', '王五']
})

salary = pd.DataFrame({
    'emp_id': [101, 102, 104],
    'salary': [15000, 22000, 18000]
})

# 默认内连接,只保留两表都有的键
result = pd.merge(emp, salary, on='emp_id', how='inner')
print(result)

# 左连接保留左表全部行,右表缺失则填NaN
result_left = pd.merge(emp, salary, on='emp_id', how='left')
print(result_left)

how参数有inner、left、right、outer四种模式,选择依据是业务上想保留哪部分数据。核对数据时建议合并前后各做一次行数统计,left连接的结果行数应该等于左表行数,如果变多了,几乎可以断定右表的键有重复。还要注意键名不一致的情况,此时用left_onright_on分别指定,合并后再drop掉多余的列。

concat处理的是另一个维度的问题,把多张结构相同或相近的表上下拼接,比如把12个月的月度数据合成年度表。默认纵向拼接时要求列名对齐,列名不一致的列会自动补NaN。如果设置ignore_index=True会重建索引,避免出现重复索引标签。横向拼接时用axis=1,此时按索引对齐,因此拼接前务必确认索引含义,必要的话先reset_index

q1 = pd.DataFrame({'name': ['张三', '李四'], 'score': [88, 92]})
q2 = pd.DataFrame({'name': ['王五'], 'score': [79]})

# 纵向堆叠并重建索引
year = pd.concat([q1, q2], ignore_index=True)
print(year)

# 多列键合并,类似SQL的复合主键关联
info = pd.DataFrame({
    'dept': ['研发部', '研发部', '销售部'],
    'level': ['P5', 'P6', 'P5'],
    'bonus': [1000, 2000, 1500]
})
final = pd.merge(year.assign(dept=['研发部', '销售部', '研发部']),
                 info, on=['dept', 'level'], how='left')
print(final)

还有个实用技巧:合并后可以用indicator=True参数生成一个_merge列,标记每行数据来自左表、右表还是两边都有,做数据对账时特别好用。至于join方法,它本质上是merge的便捷封装,默认按索引连接,适合索引本身就有业务含义的场景。

四、常见坑点与实操建议

第一,映射产生的NaN要警惕。map遇到未知键会静默填NaN,不会报错,问题往往到分析阶段才暴露。建议映射后立即用isna().sum()检查缺失情况,或者干脆在字典里加一个兜底逻辑。第二,合并后索引重复是隐蔽的bug来源,尤其是concat之后继续做loc筛选,重复索引会返回意外的多行结果,养成拼接后重置索引的习惯。

第二,大数据量下尽量少用逐行apply。apply加lambda的写法方便但性能差,能换成向量化运算就换,能换成分组transform就别手写循环。第三,链式操作虽然优雅,但中间步骤出错时不好定位,关键流程建议分步执行并打印中间结果,确认无误后再合并成链式调用。

总的来说,多列映射负责改值,数据转换负责规范结构,合并操作负责把分散的信息聚合到一起,三者配合使用就能把绝大多数原始数据整理成可直接分析的标准DataFrame。掌握这些方法后,再配合groupby和透视表,基本可以应对日常数据清洗的全部需求。

Pandas数据重塑DataFrame合并多列映射修改时间:2026-09-04 22:44:54

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260904/50527.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。