Python 提高熊猫行最近邻的性能
我得到了与此类似的8000x3数据集:Python 提高熊猫行最近邻的性能,python,numpy,pandas,Python,Numpy,Pandas,我得到了与此类似的8000x3数据集: import pandas as pd import numpy as np df = pd.DataFrame(np.random.rand(8000,3), columns=list('XYZ')) 因此,对于视觉参考,df.head(5)如下所示: X Y Z 0 0.462433 0.559442 0.016778 1 0.663771 0.092044 0.636519 2 0
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.rand(8000,3), columns=list('XYZ'))
因此,对于视觉参考,df.head(5)如下所示:
X Y Z
0 0.462433 0.559442 0.016778
1 0.663771 0.092044 0.636519
2 0.111489 0.676621 0.839845
3 0.244361 0.599264 0.505175
4 0.115844 0.888622 0.766014
我试图实现一种方法,当从数据集中给定一个索引时,它将从数据集中返回类似的项(以某种合理的方式)。目前我有:
def find_similiar_items(item_id):
tmp_df = df.sub(df.loc[item_id], axis='columns')
tmp_series = tmp_df.apply(np.square).apply(np.sum, axis=1)
tmp_series.sort()
return tmp_series
此方法获取您的行,然后从数据帧中的每一行中减去它,然后计算每一行的范数。所以这个方法只是使用欧几里德距离返回一系列离给定点最近的点
因此,您可以获得最近的5个点,例如:
df.loc[find_similiar_items(5).index].head(5)
这将产生:
X Y Z
5 0.364020 0.380303 0.623393
4618 0.369122 0.399772 0.643603
4634 0.352484 0.402435 0.619763
5396 0.386675 0.370417 0.600555
3229 0.355186 0.410202 0.616844
这个方法的问题是每次调用它大约需要半秒的时间。这对于我来说是不可接受的,因此我需要找出如何以某种方式改进此方法的性能。所以我有几个问题:
问题1是否有更有效的方法简单地计算上述欧几里德距离
问题2是否有其他技术可以产生类似这样的合理结果(例如,欧几里德距离并不重要)。在这个问题中,计算时间比内存更重要,而预处理时间并不重要;例如,我愿意构建一个新的数据帧,其大小与原始数据帧的笛卡尔积(n^2)相同(但任何超过该大小的数据帧都可能变得不合理)您最大(也是最容易)的性能增益可能来自于仅在numpy而不是pandas中这样做。从代码到numpy的快速转换,我看到了200倍的改进:
arr = df.values
def fsi_numpy(item_id):
tmp_arr = arr - arr[item_id]
tmp_ser = np.sum( np.square( tmp_arr ), axis=1 )
return tmp_ser
df['dist'] = fsi_numpy(5)
df = df.sort_values('dist').head(5)
X Y Z dist
5 0.272985 0.131939 0.449750 0.000000
5130 0.272429 0.138705 0.425510 0.000634
4609 0.264882 0.103006 0.476723 0.001630
1794 0.245371 0.175648 0.451705 0.002677
6937 0.221363 0.137457 0.463451 0.002883
检查它是否给出与函数相同的结果(因为我们有不同的随机抽取):
时间:
%timeit df.loc[ pd.DataFrame( find_similiar_items(5)).index].head(5)
1 loops, best of 3: 638 ms per loop
In [105]: %%timeit
...: df['dist'] = fsi_numpy(5)
...: df = df.sort_values('dist').head(5)
...:
100 loops, best of 3: 2.69 ms per loop
如果您计划为所有数据点预先计算最近点,我建议使用ApacheSpark,它为您提供了此类用例的开箱即用并行处理。事实上,它几乎没有用于类似工作的内置方法。例句:它已经有了一个ALS推荐系统,很难推广w.r.t.Q1和Q2。在某种程度上,你是在对同质类型的规则形状数组中的数据进行纯粹的数值运算,numpy将比pandas快很多(请注意,我添加了一个numpy标记btw)。因此,我首先要寻找好的基于numpy的方法。除此之外,还可以看看numba,numexpr,cython。哇,谢谢。我觉得这有点奇怪,因为我认为dataframe是numpy数组的一个子类。非常好的答案。这里的技巧是使用
numpy
而不是pandas
。谢谢你的建议。python 3.6的更新:使用sort\u值(“dist”)
替换sort(“dist”)
%timeit df.loc[ pd.DataFrame( find_similiar_items(5)).index].head(5)
1 loops, best of 3: 638 ms per loop
In [105]: %%timeit
...: df['dist'] = fsi_numpy(5)
...: df = df.sort_values('dist').head(5)
...:
100 loops, best of 3: 2.69 ms per loop