我有一个xyz坐标的Pandas数据框,看起来像这样。它不是完整的数据框,只是一个部分
X Y Z
0 [-5.43] [28.077] [-0.842]
1 [-3.183] [26.472] [1.741]
2 [-2.574] [22.752] [1.69]
3 [-1.743] [21.321] [5.121]
4 [0.413] [18.212] [5.392]
5 [0.714] [15.803] [8.332]
6 [4.078] [15.689] [10.138]
7 [5.192] [12.2] [9.065]
8 [4.088] [12.79] [5.475]
9 [5.875] [16.117] [4.945]
10 [8.514] [15.909] [2.22]
11 [12.235] [15.85] [2.943]
12 [13.079] [16.427] [-0.719]
每行对应于xyz平面上的一个点,每列对应于该点在空间中的位置。我想对这些数据进行处理的是通过将每个点相互比较来为此数据创建一个距离矩阵。最简单的方法是什么?
答案 0 :(得分:1)
首先,直接从每个单元格的列表中提取元素,而不要使用长度为一个的列表:
df = df.applymap(lambda x: x[0])
现在创建您的DataFrame的笛卡尔积:
df['key'] = 1
v = df.merge(df, on='key').drop('key', 1)
最后,使用numpy.linalg.norm
:
a, b = np.split(v.values, 2, axis=1)
np.linalg.norm(a-b, axis=1)
array([ 0. , 3.78112721, 6.55159408, 9.73626592, 13.05073293,
16.5094545 , 19.08991902, 21.51870493,
...,
3.80204011, 21.87054435, 19.27190362, 17.05360123, 16.66578891,
14.17596917, 15.336336 , 14.12221987, 13.25891979, 11.50788799,
9.1692209 , 5.45392244, 3.80204011, 0. ])
这是一个占用大量内存的解决方案,因为它需要O(N ^ 2)内存来创建笛卡尔积。如果这成为问题,则可以创建一个执行相同操作的生成器,但要付出一定的速度:
def lazy_distance(df):
a = df.values
for x in a:
for y in a:
yield np.linalg.norm(x - y)
In [78]: np.array_equal(np.array(list(lazy_distance(df))), np.linalg.norm(a-b, axis=1))
Out[78]: True