pandas for循环追加DataFrame行时如何用pd.concat替换df.append
问题背景
更新pandas版本后会收到如下弃用警告:
'The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.'
本次涉及的三个数据集结构如下:
- b1:b波段滤光片观测的人造星数据,列包含
['Id', 'x', 'y', 'bmag'] - i1:I波段滤光片观测的人造星数据,列包含
['Id', 'x', 'y', 'imag'] - biart:实测星数据,列包含
['Id', 'x', 'y', 'bmag', 'imag']
原代码逻辑:遍历b1中所有人造星,计算其与biart中实测星的最小径向距离,若最小距离≤0.5,则同时保留人造星与匹配到的实测星对应的Id、坐标、星等、距离字段。
直接替换append的pd.concat写法
df.append(单条记录字典, ignore_index=True)的本质是将字典转为单行表结构后,和原表做纵向拼接。替换时只需要先将待追加的字典转为单行DataFrame,再传入pd.concat即可,替换代码片段如下:
# 将待追加的字典放在列表中,转为单行DataFrame new_row = pd.DataFrame([{ 'Id_art': b1['Id'].iloc[i], 'x_art':b1['x'].iloc[i], 'y_art': b1['y'].iloc[i], 'bmag_art':b1['bmag'].iloc[i], 'imag_art':i1['imag'].iloc[i], 'dist_d':min(dist), 'Id_meas':biart['Id'].iloc[dist.idxmin()], 'x_meas':biart['x'].iloc[dist.idxmin()], 'y_meas':biart['y'].iloc[dist.idxmin()], 'bmag_meas':biart['bmag'].iloc[dist.idxmin()], 'imag_meas':biart['imag'].iloc[dist.idxmin()] }]) # 拼接时传入待拼接对象组成的列表,ignore_index=True重置行索引 extract = pd.concat([extract, new_row], ignore_index=True)
注意:字典必须放在列表中再传入pd.DataFrame,否则字典键会被识别为列索引引发报错。
高性能改写方案(推荐)
逐行遍历+每次循环拼接DataFrame的写法效率极低,每次拼接操作都会全量复制整个DataFrame,数据量较大时运行速度会非常慢。更合理的实现方式是先把所有符合条件的记录存入普通列表,遍历完成后一次性转为DataFrame,完全不需要循环内做表拼接,性能可提升数十倍到数百倍,完整代码如下:
import numpy as np import pandas as pd # 预定义输出表的列顺序 output_cols = [ 'Id_art', 'x_art', 'y_art', 'bmag_art', 'imag_art', 'dist_d', 'Id_meas', 'x_meas', 'y_meas', 'bmag_meas', 'imag_meas' ] # 用普通列表存储符合条件的记录,避免循环内重复复制DataFrame valid_records = [] for i in range(len(b1.index)): x_art = b1['x'].iloc[i] y_art = b1['y'].iloc[i] # 计算当前人造星到所有实测星的距离 dist_arr = np.sqrt((x_art - biart['x'])**2 + (y_art - biart['y'])**2) min_dist = dist_arr.min() # 距离满足阈值才保留记录 if min_dist <= 0.5: match_idx = dist_arr.idxmin() # 组装当前匹配对的记录 curr_record = [ b1['Id'].iloc[i], x_art, y_art, b1['bmag'].iloc[i], i1['imag'].iloc[i], min_dist, biart['Id'].iloc[match_idx], biart['x'].iloc[match_idx], biart['y'].iloc[match_idx], biart['bmag'].iloc[match_idx], biart['imag'].iloc[match_idx] ] valid_records.append(curr_record) # 保留原有的打印逻辑 print(*curr_record) # 遍历结束后一次性生成最终结果表 extract = pd.DataFrame(valid_records, columns=output_cols)
该写法完全规避了append弃用问题,同时运行效率远高于逐行拼接的实现。
内容的提问来源于stack exchange,提问作者mmfranco
相关产品推荐
相关产品推荐

