Python循环计算点间欧氏距离出错,求排查及与SAS Proc SQL对齐
循环计算欧氏距离出错排查
我想用Python循环计算每个点到所有点的欧氏距离,已有SAS Proc SQL的实现方案,但Python循环得到的结果不符合预期,麻烦帮忙找出循环里的问题。
数据与单点正确计算代码
import pandas as pd import numpy as np data = { 'object': ['A', 'B', 'C', 'D'], 'value1': [79.826732673, 78.268876611, 64.04744255, 58.866103739], 'value2': [2.7227722772, 2.7624309392, 2.8910303929, 3.6188178528] } df = pd.DataFrame(data)
针对点A的正确计算代码(能得到该点到所有点的距离及平均值):
x = df["value1"] y = df["value2"] x_ref = 79.826732673 y_ref = 2.7227722772 dist = np.sqrt((x-x_ref)**2 + (y-y_ref)**2) # 欧氏距离 np.mean(dist)
错误的循环代码
运行下面的循环后,只得到了最后一个点的距离结果,且不符合预期:
for i in range(0,3): x_ref = df.iloc[i]["value1"] y_ref = df.iloc[i]["value2"] eklidean = np.sqrt((df["value1"] - x_ref)**2 + (df["value2"] - y_ref)**2) eklidean # 输出结果: # object # A 15.780187 # B 14.222015 # C 0.000000 # D 5.232203 # dtype: float64
循环中的错误分析
- 循环范围缺失:
range(0,3)只遍历了索引0、1、2(对应点A、B、C),漏掉了索引3的点D,导致D点的距离完全没计算。 - 结果被覆盖:每次循环都把计算结果赋值给同一个变量
eklidean,前三次循环的结果(A、B点的距离)被最后一次循环(C点)的结果覆盖,最终只保留了C点的计算值。 - 未保存与汇总结果:没有保存每个点对应的距离数据,也没有像SAS代码那样计算每个点到所有点距离的平均值。
修正后的实现方式
方式1:修正循环逻辑
import pandas as pd import numpy as np # 初始化空字典保存每个点的距离结果 dist_results = {} for i in range(len(df)): obj = df.iloc[i]['object'] x_ref = df.iloc[i]['value1'] y_ref = df.iloc[i]['value2'] # 计算当前点到所有点的距离 dist = np.sqrt((df['value1'] - x_ref)**2 + (df['value2'] - y_ref)**2) # 保存距离序列和对应的平均值 dist_results[obj] = { 'distances': dist, 'avg_distance': np.mean(dist) } # 查看每个点的结果 for obj, res in dist_results.items(): print(f"点{obj}的距离结果:") print(res['distances']) print(f"平均距离:{res['avg_distance']}\n")
方式2:无循环高效实现(推荐)
利用numpy广播或scipy的距离计算函数,无需手动循环:
from scipy.spatial.distance import cdist # 提取数值列 points = df[['value1', 'value2']].values # 计算所有点对的欧氏距离 distance_matrix = cdist(points, points, metric='euclidean') # 转换为DataFrame,方便查看 dist_df = pd.DataFrame(distance_matrix, index=df['object'], columns=df['object']) # 计算每个点的平均距离 dist_df['avg_distance'] = dist_df.mean(axis=1) print(dist_df)
SAS Proc SQL参考实现
DATA points; INPUT object $ value1 value2; DATALINES; A 79.826732673 2.7227722772 B 78.268876611 2.7624309392 C 64.04744255 2.8910303929 D 58.866103739 3.6188178528 ; RUN; PROC SQL; CREATE TABLE kombinations AS SELECT a.object, A.value1, B.value1 as value1_dup, A.value2, B.value2 as value2_dup FROM points a, points b; QUIT; proc sql; create table calculation as select *, sqrt((value1 - value1_dup)**2 + (value2 - value2_dup)**2) as euklidean from kombinations; quit; proc sql; create table object_group as select object, avg(euklidean) as avg_euklidean from calculation group by object; quit;
内容的提问来源于stack exchange,提问作者Kristián Övári
相关产品推荐
相关产品推荐

