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

Pandas DataFrame行两两比较并计算欧氏距离的Pythonic实现方法

高效实现DataFrame行两两欧氏距离计算

我有如下DataFrame:

region   country   val_a   val_b 
reg1     cntr1     0.5      0.7
reg2     cntr1     1        2
reg3     cntr1     2        1.2
reg1     cntr2     3        0.3
reg44    cntr2     0.2      0.7

希望遍历该DataFrame,将每一行与其他行进行两两比较,计算每对行中val_a和val_b的欧氏距离,生成如下结构的新DataFrame:

source_region    source_country    dest_region    dest_country    distance
reg1              cntr1             reg2           cntr1            0.9
reg1               cntr1            reg3           cntr1            1.5

(注:示例中distance为随机值,只需保证两两比较逻辑正确)

目前可以用嵌套循环实现,但有没有更Pythonic的方法?


更Pythonic的实现方案

不需要嵌套循环,我们可以利用Python标准库或科学计算库的工具来高效实现:

方案一:用itertools.combinations生成行对(直观易读)

先准备好原始DataFrame,然后用itertools.combinations生成所有不重复的行索引对(避免重复比较同一对行,比如行0和行1只计算一次),再批量提取信息并计算距离:

import pandas as pd
import itertools
import numpy as np

# 构造原始DataFrame
df = pd.DataFrame({
    'region': ['reg1', 'reg2', 'reg3', 'reg1', 'reg44'],
    'country': ['cntr1', 'cntr1', 'cntr1', 'cntr2', 'cntr2'],
    'val_a': [0.5, 1, 2, 3, 0.2],
    'val_b': [0.7, 2, 1.2, 0.3, 0.7]
})

# 生成所有不重复的行索引组合(i < j,避免重复计算)
idx_pairs = itertools.combinations(df.index, 2)

# 构建结果数据
result_rows = []
for i, j in idx_pairs:
    # 提取源和目标的区域、国家
    src_reg, src_cntr = df.loc[i, ['region', 'country']]
    dest_reg, dest_cntr = df.loc[j, ['region', 'country']]
    # 计算欧氏距离
    dist = np.sqrt((df.loc[i, 'val_a'] - df.loc[j, 'val_a'])**2 + 
                   (df.loc[i, 'val_b'] - df.loc[j, 'val_b'])**2)
    # 添加到结果列表
    result_rows.append([src_reg, src_cntr, dest_reg, dest_cntr, round(dist, 2)])

# 转为目标格式的DataFrame
result_df = pd.DataFrame(
    result_rows,
    columns=['source_region', 'source_country', 'dest_region', 'dest_country', 'distance']
)

方案二:用scipy批量计算(高效适合大数据)

如果你的DataFrame行数较多,推荐用scipy.spatial.distance.pdist批量计算所有两两距离,底层是优化过的C代码,比Python循环快得多:

import pandas as pd
from scipy.spatial.distance import pdist, squareform

# 构造原始DataFrame
df = pd.DataFrame({
    'region': ['reg1', 'reg2', 'reg3', 'reg1', 'reg44'],
    'country': ['cntr1', 'cntr1', 'cntr1', 'cntr2', 'cntr2'],
    'val_a': [0.5, 1, 2, 3, 0.2],
    'val_b': [0.7, 2, 1.2, 0.3, 0.7]
})

# 提取用于计算距离的数值列
value_cols = df[['val_a', 'val_b']].values
# 批量计算所有两两行的欧氏距离(返回压缩格式的结果)
distances = pdist(value_cols, metric='euclidean')
# 转为方阵,方便通过索引取对应距离
dist_matrix = squareform(distances)

# 生成所有不重复的索引对
idx_pairs = [(i, j) for i in range(len(df)) for j in range(i+1, len(df))]

# 组装结果DataFrame
result_data = []
for i, j in idx_pairs:
    result_data.append({
        'source_region': df.loc[i, 'region'],
        'source_country': df.loc[i, 'country'],
        'dest_region': df.loc[j, 'region'],
        'dest_country': df.loc[j, 'country'],
        'distance': round(dist_matrix[i, j], 2)
    })

result_df = pd.DataFrame(result_data)

说明

  • 两种方案都避免了嵌套循环,且只计算不重复的行对(比如不会同时计算行0→行1和行1→行0),符合常规的两两比较逻辑。
  • 方案一代码直观,依赖标准库,适合中小规模数据;方案二效率更高,适合行数较多的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 18:13:30