Python中替代apply的可扩展高效实现方案咨询
高效实现方案
原方案用apply逐行遍历DataFrame,在大数据集下性能瓶颈主要来自:
- 逐行操作的循环开销
- 每行都重复执行
df.columns筛选feat列的逻辑,冗余计算
以下是两种更高效的矢量化实现方式:
方法一:利用dot方法快速拼接列名
import pandas as pd import numpy as np df = pd.DataFrame({'ID':[1,2,3], 'feat1_tax':[1,0,0], 'feat2_move':[1,0,0], 'feat3_coffee': [0,1,0], 'scored':[0,0,1]}) # 提前提取所有feat开头的列,避免重复计算 feat_cols = df.columns[df.columns.str.startswith('feat')] # 用dot方法将值为1的列名拼接,原理是矩阵乘法:每行值与列名相乘后求和 df['reason'] = df[feat_cols].dot(feat_cols + ', ').str.rstrip(', ') # 处理scored=1或无匹配列的情况,设为None df['reason'] = df['reason'].mask( (df['scored'] == 1) | (df['reason'] == ''), None ) print(df)
方法二:结合where和agg的矢量化拼接
import pandas as pd import numpy as np df = pd.DataFrame({'ID':[1,2,3], 'feat1_tax':[1,0,0], 'feat2_move':[1,0,0], 'feat3_coffee': [0,1,0], 'scored':[0,0,1]}) feat_cols = df.columns[df.columns.str.startswith('feat')] # 构造临时DataFrame:值为1的位置保留列名,否则为空字符串 temp_df = df[feat_cols].where(df[feat_cols] == 1, '') # 每行拼接非空的列名 df['reason'] = temp_df.agg(', '.join, axis=1) # 修正scored=1和无匹配的情况 df['reason'] = np.where( (df['scored'] == 1) | (df['reason'] == ''), None, df['reason'] ) print(df)
两种方法的输出结果与原方案完全一致:
ID feat1_tax feat2_move feat3_coffee scored reason 0 1 1 1 0 0 feat1_tax, feat2_move 1 2 0 0 1 0 feat3_coffee 2 3 0 0 0 1 None
性能优势说明
这两种方法都采用矢量化操作,避免了逐行遍历的循环开销,同时提前提取feat列,消除了冗余计算。在十万级以上的数据集上,性能会比原apply方案提升数倍甚至数十倍。
内容的提问来源于stack exchange,提问作者Henri
相关产品推荐
相关产品推荐

