You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无需遍历检查点DataFrame,为玩家DataFrame批量添加距离列?

问题

现有两个Pandas DataFrame:player_df(包含玩家坐标等数据)和checkpoints_df(包含检查点坐标及名称),以及一个可计算欧氏距离的distance函数。目标是为player_df添加以检查点名称命名的列,填充玩家到对应检查点的距离。

当前使用.iterrows()遍历checkpoints_df实现,但数据量大时效率极低;尝试用.apply()未成功创建目标列,现寻求无需遍历checkpoints_df的高效实现方法。

数据示例

player_df定义及数据

import pandas as pd
import numpy as np

player_df = pd.DataFrame(np.random.rand(10,3), columns=['x','y','more_cols'])

输出:

x         y  more_cols
0  0.352673  0.479360   0.638508
1  0.764669  0.326961   0.778483
2  0.805774  0.911662   0.316030
3  0.114446  0.185147   0.318742
4  0.714803  0.646525   0.084143
5  0.061614  0.837432   0.886669
6  0.179777  0.519559   0.446562
7  0.615326  0.886046   0.581127
8  0.597375  0.196619   0.310331
9  0.670061  0.471363   0.313047

checkpoints_df定义及数据

checkpoints_df = pd.DataFrame(np.random.rand(4,2), columns=['x','y'])
checkpoints_df['checkpoint_name'] = ['Alpha', 'Hotel', 'Indigo', 'Papa']

输出:

x         y checkpoint_name
0  0.616945  0.804442            Alpha
1  0.402007  0.556274            Hotel
2  0.478351  0.443920           Indigo
3  0.075494  0.803561             Papa

当前低效实现

for _, row in checkpoints_df.iterrows():
    player_df[row['checkpoint_name']] = distance(player_df['x'], player_df['y'], row['x'], row['y'])
高效实现方案

核心思路是利用向量化运算替代循环遍历,充分发挥Pandas和NumPy的底层性能优势,以下是两种可靠的实现方式:

方法一:NumPy广播批量计算

直接用NumPy广播机制一次性计算所有玩家到所有检查点的距离,再合并到原DataFrame:

# 提取坐标数组
player_coords = player_df[['x', 'y']].to_numpy()
checkpoint_coords = checkpoints_df[['x', 'y']].to_numpy()
checkpoint_names = checkpoints_df['checkpoint_name'].tolist()

# 广播计算欧氏距离:(10,2) - (4,2) → (10,4,2),平方求和后开根号
distances = np.sqrt(((player_coords[:, np.newaxis] - checkpoint_coords)**2).sum(axis=2))

# 转为DataFrame并合并
distance_df = pd.DataFrame(distances, columns=checkpoint_names, index=player_df.index)
player_df = pd.concat([player_df, distance_df], axis=1)

如果你的distance函数是自定义逻辑,可先用np.vectorize包装后结合广播;若只是标准欧氏距离,此方法效率最高。

方法二:Pandas assign批量添加列

用assign方法配合向量化函数,批量生成目标列:

# 定义向量化的欧氏距离函数
def vec_distance(p_x, p_y, cp_x, cp_y):
    return np.sqrt((p_x - cp_x)**2 + (p_y - cp_y)**2)

# 生成列名与计算逻辑的映射字典,批量添加
distance_cols = {
    name: vec_distance(player_df['x'], player_df['y'], cp_x, cp_y)
    for name, cp_x, cp_y in checkpoints_df[['checkpoint_name', 'x', 'y']].itertuples(index=False)
}

player_df = player_df.assign(**distance_cols)

这里用itertuples替代iterrows,本身性能已提升数倍,再结合向量化函数,整体效率远高于逐行遍历。

性能说明

  • 原iterrows方案:每次循环触发Pandas列赋值,Python层循环开销极大,数据量越大越慢。
  • 向量化方案:底层由NumPy的C代码执行,无Python循环开销,速度可提升数十到上百倍(数据量越大,差距越显著)。

内容的提问来源于stack exchange,提问作者Noodleking

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 10:12:42