不使用for循环重构DataFrame的Pythonic(Pandas风格)实现方法
Pandas风格的DataFrame转换:彻底告别For循环
这问题问得太对了——用Pandas处理DataFrame结构转换,绝对要抛弃for循环,这才是Pandas的正确打开方式!核心思路就是用Pandas内置的矢量化操作和数据重塑工具,既简洁又高效,完全符合Python/Pandas风格。我给你分场景拆解几种常用方法:
一、数据重塑:宽表↔长表转换
这是最常见的结构转换场景,Pandas专门提供了工具函数:
- 宽表转长表:用
melt()
比如你有一张按用户+多科目分数的宽表,要转成用户-科目-分数的长表:import pandas as pd # 原宽表 df_wide = pd.DataFrame({ 'Name': ['Alice', 'Bob'], 'Math': [85, 90], 'English': [78, 82], 'Science': [92, 88] }) # 转换成长表 df_long = df_wide.melt( id_vars='Name', # 保留的主键列 var_name='Subject', # 原列名转成的新列名 value_name='Score' # 原列值转成的新列名 ) - 长表转宽表:用
pivot()或pivot_table()
如果要把上面的长表转回宽表,用pivot();如果有重复主键需要聚合,就用pivot_table():# 长表转宽表 df_wide_new = df_long.pivot( index='Name', columns='Subject', values='Score' ).reset_index()
二、列衍生/批量计算转换
如果是要基于现有列生成新列,或者批量修改列,直接用矢量化运算就行,比for循环快几个数量级:
- 直接矢量化运算:比如新增一列是多列的求和
df['Total_Score'] = df['Math'] + df['English'] + df['Science'] - 用
assign()做链式衍生:适合一次性生成多列,代码更整洁df = df.assign( Total_Score=lambda x: x['Math'] + x['English'] + x['Science'], Avg_Score=lambda x: x['Total_Score'] / 3 ) - 专属访问器处理特殊类型:比如字符串、日期的批量转换
# 字符串批量转大写 df['Name_Upper'] = df['Name'].str.upper() # 日期字符串批量转日期类型 df['Exam_Date'] = pd.to_datetime(df['Exam_Date_Str']).dt.date
三、筛选+重组结构
如果是要筛选部分行/列,再重组新的DataFrame,用loc/iloc配合concat/merge:
- 直接筛选重组:
# 筛选数学分数>80的行,只保留姓名和数学列,并重命名列 new_df = df.loc[df['Math']>80, ['Name', 'Math']].rename(columns={'Math':'Math_Score'}) - 合并多个片段:用
concat(行/列合并)或merge(关联合并)# 按行合并两个筛选后的DataFrame片段 df_part1 = df.loc[df['Name']=='Alice', :] df_part2 = df.loc[df['Name']=='Bob', :] new_df = pd.concat([df_part1, df_part2], axis=0)
四、分组后结构转换
如果需要按分组做转换,用groupby配合transform或agg:
# 给每个班级添加班级内的总分平均分 df['Class_Avg'] = df.groupby('Class')['Total_Score'].transform('mean') # 按班级聚合生成新的统计DataFrame grouped_df = df.groupby('Class').agg( Avg_Score=('Total_Score', 'mean'), Max_Score=('Total_Score', 'max') ).reset_index()
避坑提醒
绝对不要用iterrows()/itertuples()这类伪循环方法——它们本质还是逐行遍历,效率极低,完全不符合Pandas的设计理念。只要是你想用for循环做的操作,99%都能找到对应的矢量化方法。
内容的提问来源于stack exchange,提问作者andandandand
相关产品推荐
相关产品推荐

