Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 提高熊猫行最近邻的性能_Python_Numpy_Pandas - Fatal编程技术网

Python 提高熊猫行最近邻的性能

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

我得到了与此类似的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.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