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

Pandas中行子集间距离计算的高效实现方案问询

问题描述

有如下格式的Pandas DataFrame:

S1       S2      id    var
  0      1.2      3.2     A1    A
  1      3.4      0.4     A2    A
  2      -2.3     1.2     A3    A
  3      0.1      -1.3    B1    B
  4      4.5      1.3     B2    B
  5      -2.3     -1.2    C1    C

需要计算不同组间所有行的两两欧氏距离平均值:

  • dist_AB = ((A1-B1距离) + (A1-B2距离) + (A2-B1距离) + (A2-B2距离))/4
  • dist_AC = ((A1-C1距离) + (A2-C1距离) + (A3-C1距离))/3
  • dist_BC = ((B1-C1距离) + (B2-C1距离))/2

原实现采用多层循环逐行计算,处理数万行数据时效率极低,需更高效的实现方式。

高效实现方案

核心思路是用向量化运算替代逐行循环,利用数值计算库的批量处理能力,大幅提升运行效率。

方法1:使用scipy.spatial.distance.cdist批量计算

cdist是专门用于计算两组样本两两距离的函数,底层经过优化,代码简洁且性能优异:

import io
import numpy as np
import pandas as pd
from scipy.spatial.distance import cdist
import itertools

TESTDATA="""
S1       S2      id    var
1.2      3.2     A1    A
3.4      0.4     A2    A
-2.3     1.2     A3    A
0.1      -1.3    B1    B
4.5      1.3     B2    B
-2.3     -1.2    C1    C
"""
df = pd.read_csv(io.StringIO(TESTDATA), sep="\s+")

# 按var分组提取特征列数据
grouped_features = df.groupby('var')[['S1', 'S2']]
group_names = list(grouped_features.groups.keys())

# 遍历所有组对,计算平均距离
result_list = []
for v1, v2 in itertools.combinations(group_names, 2):
    # 获取两组的特征矩阵
    group1_data = grouped_features.get_group(v1).values
    group2_data = grouped_features.get_group(v2).values
    # 计算两两欧氏距离矩阵
    distance_matrix = cdist(group1_data, group2_data, metric='euclidean')
    # 计算该组对的平均距离
    avg_distance = distance_matrix.mean()
    result_list.append({'var': v1+v2, 'dist': avg_distance})

# 转换为DataFrame输出
distances_df = pd.DataFrame(result_list)
print(distances_df)

输出结果与原代码完全一致:

var      dist
0   AB  3.973345
1   AC  4.647527
2   BC  4.823540

方法2:纯Numpy广播实现(无SciPy依赖)

如果不想引入SciPy依赖,可利用Numpy的广播机制实现批量距离计算:

import io
import numpy as np
import pandas as pd
import itertools

TESTDATA="""
S1       S2      id    var
1.2      3.2     A1    A
3.4      0.4     A2    A
-2.3     1.2     A3    A
0.1      -1.3    B1    B
4.5      1.3     B2    B
-2.3     -1.2    C1    C
"""
df = pd.read_csv(io.StringIO(TESTDATA), sep="\s+")

grouped_features = df.groupby('var')[['S1', 'S2']]
group_names = list(grouped_features.groups.keys())

result_list = []
for v1, v2 in itertools.combinations(group_names, 2):
    group1_data = grouped_features.get_group(v1).values
    group2_data = grouped_features.get_group(v2).values
    # 广播计算两组样本的差值
    diff = group1_data[:, np.newaxis, :] - group2_data[np.newaxis, :, :]
    # 计算欧氏距离矩阵:差值平方和开根号
    distance_matrix = np.sqrt(np.sum(diff ** 2, axis=2))
    avg_distance = distance_matrix.mean()
    result_list.append({'var': v1+v2, 'dist': avg_distance})

distances_df = pd.DataFrame(result_list)
print(distances_df)

效率说明

  • 原循环实现:逐行迭代的Python级循环开销极大,时间复杂度为O(M*N)(M、N为两组样本量),处理大规模数据时性能断崖式下降。
  • 向量化实现:利用C语言优化的底层数值计算,同样的时间复杂度但实际运行速度比循环快100~1000倍,可轻松处理数万行甚至更大规模的数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 15:00:47