Pandas中替代DataFrame切片的多指标作者高效排名方案
多指标交集下的作者快速排名方案
问题说明
我需要基于两个指标的交集(不适合用平均方式)为每个观测值对应的作者排名。目前的做法是对DataFrame逐行切片,再统计唯一作者数量,但这种方法运行速度极慢,想找更高效的解决方案。
示例数据及当前低效实现代码:
df = pd.DataFrame([["a", 2, 0], ["b", 3, 0.15], ["b", 3, 0.4], ["c", 7, 0.49], ["d", 3, 0.17]], columns=['author', 'metric1', 'metric2']) df['score'] = df.apply(lambda x: len(df[(df['metric2']>= x['metric2']) & (df['metric1']>= x['metric1'])]['author'].unique()), axis=1)
高效解决方案
核心思路是用向量化运算替代逐行循环,同时预处理作者的有效指标点,减少不必要的计算。
步骤1:预处理作者的有效指标点
同作者的多条记录中,部分记录会被其他记录支配(比如作者b的(3, 0.15)被(3, 0.4)覆盖,因为后者的两个指标都不弱于前者)。我们可以先筛选每个作者的帕累托最优指标点,只保留无法被同作者其他记录覆盖的点,减少后续比较的数量:
def get_pareto_frontier(points): # 按metric1降序、metric2降序排序,筛选帕累托最优点 points = points.sort_values(by=['metric1', 'metric2'], ascending=[False, False]) frontier = [] max_m2 = -float('inf') for _, row in points.iterrows(): if row['metric2'] > max_m2: frontier.append(row) max_m2 = row['metric2'] return pd.DataFrame(frontier) # 先去重同作者的重复指标组合,再筛选帕累托最优 author_unique_points = df.drop_duplicates(subset=['author', 'metric1', 'metric2']) author_pareto = author_unique_points.groupby('author').apply(get_pareto_frontier).reset_index(drop=True)
步骤2:向量化计算覆盖作者数
利用numpy广播特性,一次性完成所有行与所有作者有效点的比较,再统计满足条件的唯一作者数量:
# 提取预处理后的作者指标和ID数组 author_m1 = author_pareto['metric1'].values author_m2 = author_pareto['metric2'].values author_ids = author_pareto['author'].values # 将当前df的指标转为列向量,实现广播匹配 current_m1 = df['metric1'].values[:, None] current_m2 = df['metric2'].values[:, None] # 计算每个当前行指标是否被作者的某个有效点覆盖(metric1>=当前值 且 metric2>=当前值) mask = (author_m1 >= current_m1) & (author_m2 >= current_m2) # 统计每个行对应的满足条件的唯一作者数 mask_df = pd.DataFrame(mask, columns=author_ids) df['score'] = mask_df.groupby(axis=1, level=0).any().sum(axis=1)
为什么更快?
- 避免了
apply逐行循环的Python级遍历,改用numpy向量化运算,速度提升几个数量级; - 预处理筛选帕累托最优点,大幅减少了需要比较的指标点数量,进一步压缩计算量。
内容的提问来源于stack exchange,提问作者user1627466
相关产品推荐
相关产品推荐

