为Pandas DataFrame批量添加列遇性能警告,求pd.concat正确用法
问题场景
我尝试通过以下代码给Pandas DataFrame批量添加求和列:
def create_sum_rounds(df, col_name_base): ''' 根据基础列生成求和列。示例: df['sum_foo'] = df['foo_1'] + df['foo_2'] + df['foo_3'] + \ df['foo_4'] + df['foo_5'] ''' out_name = 'sum_' + col_name_base df[out_name] = 0.0 for i in range(1, 6): col_name = col_name_base + str(i) if col_name in df: df[out_name] += df[col_name] else: logger.error('列 %s 不存在于DataFrame中' % col_name) for col in sum_cols_list: create_sum_rounds(df, col)
其中sum_cols_list是包含约200个基础列名(如"foo")的列表,df包含对应基础列扩展出的"foo_1", "foo_2", ..., "foo_5"这类列。
运行代码时收到性能警告:
PerformanceWarning: DataFrame is highly fragmented. This is usually the result of calling `frame.insert` many times, which has poor performance. Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
我猜测这是因为循环添加新列时后台频繁调用insert导致的。请问此时正确使用pd.concat的方式是什么?
优化方案:使用pd.concat批量生成并合并列
核心思路是先批量生成所有需要的求和列,再一次性合并到原DataFrame,避免循环中逐列插入的性能损耗。
具体实现步骤
- 先创建一个临时容器(DataFrame或Series列表)存储所有待新增的求和列
- 遍历
sum_cols_list,计算每个基础列对应的求和结果,存入临时容器 - 最后用
pd.concat将原DataFrame和临时容器中的列一次性合并
优化后的代码
import pandas as pd # 初始化临时DataFrame存储所有求和列 sum_cols_df = pd.DataFrame() for col_base in sum_cols_list: out_col_name = f'sum_{col_base}' # 生成当前基础列对应的_round列名列表 target_cols = [f'{col_base}_{i}' for i in range(1, 6)] # 过滤出DataFrame中实际存在的列 existing_cols = [col for col in target_cols if col in df.columns] if existing_cols: # 直接对行求和生成新列 sum_cols_df[out_col_name] = df[existing_cols].sum(axis=1) else: logger.error(f'基础列 {col_base} 对应的_round列均不存在') # 一次性合并原DataFrame和所有求和列 df = pd.concat([df, sum_cols_df], axis=1)
额外优化细节
- 用
df.columns判断列存在性比col in df更高效 - 利用Pandas原生的
sum(axis=1)替代循环累加,代码更简洁且性能更优 - 如果担心内存占用,也可以用列表存储单个Series,最后再合并:
sum_series_list = [] for col_base in sum_cols_list: out_col_name = f'sum_{col_base}' target_cols = [f'{col_base}_{i}' for i in range(1, 6)] existing_cols = [col for col in target_cols if col in df.columns] if existing_cols: sum_series = df[existing_cols].sum(axis=1).rename(out_col_name) sum_series_list.append(sum_series) else: logger.error(f'基础列 {col_base} 对应的_round列均不存在') df = pd.concat([df] + sum_series_list, axis=1)
内容的提问来源于stack exchange,提问作者olives
相关产品推荐
相关产品推荐

