如何用向量化方法高效实现同DataFrame行对比并更新列?
问题
需要在同一DataFrame中,为参考symbol(XYZ)的行新增对应其他symbol的score列并填充匹配值。当前使用的迭代代码可实现需求,但处理2万行数据耗时数小时,寻求更高效的向量化实现方式。
原迭代代码及数据转换前后示例如下:
import pandas as pd import numpy as np df = pd.DataFrame({'date': ['2022-10-01', '2022-10-02', '2022-10-03', '2022-10-01', '2022-10-02'], 'symbol': ['XYZ', 'XYZ', 'XYZ', 'ABC', 'DEF'], 'tenor': ['2022-10-31', '2022-11-30', '2022-12-31', '2022-10-31', '2022-11-30'], 'score': [2, 3, 4, 6, 7], }) ref_symbol = 'XYZ' df_xyz = df.loc[df['symbol'] == ref_symbol] sym_to_compare = list(df.symbol.unique()) sym_to_compare.remove(ref_symbol) score_columns = [f'score_{sym}' for sym in sym_to_compare] df[score_columns] = [np.NAN] * len(sym_to_compare) for idx, row in df_xyz.iterrows(): for sym in sym_to_compare: match = df.loc[(df.symbol == sym) & (df.tenor == row.tenor) & (df.date == row.date)] if len(match.index): df.at[idx, f'score_{sym}'] = match.score
数据转换前后示例
# 原始DataFrame date symbol tenor score 0 2022-10-01 XYZ 2022-10-31 2 1 2022-10-02 XYZ 2022-11-30 3 2 2022-10-03 XYZ 2022-12-31 4 3 2022-10-01 ABC 2022-10-31 6 4 2022-10-02 DEF 2022-11-30 7 # 转换后DataFrame date symbol tenor score score_ABC score_DEF 0 2022-10-01 XYZ 2022-10-31 2 6.0 NaN 1 2022-10-02 XYZ 2022-11-30 3 NaN 7.0 2 2022-10-03 XYZ 2022-12-31 4 NaN NaN 3 2022-10-01 ABC 2022-10-31 6 NaN NaN 4 2022-10-02 DEF 2022-11-30 7 NaN NaN
高效向量化实现方案
利用pandas内置的pivot_table和merge操作实现完全向量化处理,避免逐行迭代,处理大体积数据时性能会有数量级的提升:
import pandas as pd import numpy as np df = pd.DataFrame({'date': ['2022-10-01', '2022-10-02', '2022-10-03', '2022-10-01', '2022-10-02'], 'symbol': ['XYZ', 'XYZ', 'XYZ', 'ABC', 'DEF'], 'tenor': ['2022-10-31', '2022-11-30', '2022-12-31', '2022-10-31', '2022-11-30'], 'score': [2, 3, 4, 6, 7], }) ref_symbol = 'XYZ' # 1. 按date和tenor聚合,将不同symbol的score转为列 pivot_df = df.pivot_table( index=['date', 'tenor'], columns='symbol', values='score', aggfunc='first' # 确保每个(date,tenor,symbol)组合只取第一个值 ) # 2. 重命名列名,添加score_前缀,同时过滤掉参考symbol自身的列 pivot_df = pivot_df.rename( columns={sym: f'score_{sym}' for sym in pivot_df.columns if sym != ref_symbol} ) # 3. 将聚合结果合并回原DataFrame result_df = df.merge(pivot_df, on=['date', 'tenor'], how='left') # 4. 非参考symbol的行,将新增的score_列设为NaN,与原需求结果对齐 non_ref_mask = result_df['symbol'] != ref_symbol score_cols = [col for col in result_df.columns if col.startswith('score_')] result_df.loc[non_ref_mask, score_cols] = np.nan print(result_df)
方案优势
- 所有操作均为pandas优化后的向量化运算,避免了嵌套循环的O(n²)时间复杂度,处理2万行数据仅需数秒
- 代码逻辑清晰,易于维护和扩展
- 自动处理所有symbol的匹配,无需手动遍历待对比symbol列表
内容的提问来源于stack exchange,提问作者B Jacob
相关产品推荐
相关产品推荐

