Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/315.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/243.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 使用SciKit学习和SciPy的K近邻构建/搜索速度_Python_Scipy_Scikit Learn_Nearest Neighbor_Kdtree - Fatal编程技术网

Python 使用SciKit学习和SciPy的K近邻构建/搜索速度

Python 使用SciKit学习和SciPy的K近邻构建/搜索速度,python,scipy,scikit-learn,nearest-neighbor,kdtree,Python,Scipy,Scikit Learn,Nearest Neighbor,Kdtree,我有一个大的二维点集,希望能够快速查询该集,以查找二维空间中任意点的k近邻。由于它是低维的,KD树似乎是一种很好的方法。我的初始数据集很少更新,因此查询点的时间对我来说应该比构建时间更重要。但是,每次运行程序时,我都需要重新加载对象,因此我还需要一个可以快速保存和重新加载的结构 两个现成的选择是SciPy和SciKit学习中的KDTree结构。下面,我将介绍其中的两个,以了解在大量列表长度范围内的构建速度和查询速度。我还对SciKit学习结构进行了pickle处理,并显示了从pickle中重新加

我有一个大的二维点集,希望能够快速查询该集,以查找二维空间中任意点的k近邻。由于它是低维的,KD树似乎是一种很好的方法。我的初始数据集很少更新,因此查询点的时间对我来说应该比构建时间更重要。但是,每次运行程序时,我都需要重新加载对象,因此我还需要一个可以快速保存和重新加载的结构

两个现成的选择是SciPy和SciKit学习中的KDTree结构。下面,我将介绍其中的两个,以了解在大量列表长度范围内的构建速度和查询速度。我还对SciKit学习结构进行了pickle处理,并显示了从pickle中重新加载对象的时间。在一个图表中对这些进行了比较,下面包含了用于生成计时的代码

正如我在图中所示,从pickle加载要比从头开始构建快半个数量级,这表明KDTree适合我的用例(即频繁重新加载但很少重新构建)

用于比较生成时间的代码:

# Profiling the building time for the two KD-tree structures and re-loading from a pickle
import math, timeit, pickle, sklearn.neighbors

the_lengths = [100, 1000, 10000, 100000, 1000000]

theSciPyBuildTime = []
theSklBuildTime = []
theRebuildTime = []

for length in the_lengths:
    dim = 5*int(math.sqrt(length))
    nTimes = 50
    from random import randint
    listOfRandom2DPoints = [ [randint(0,dim),randint(0,dim)] for x in range(length)]

    setup = """import scipy.spatial
import sklearn.neighbors
length = """ + str(length) + """
dim = """ + str(dim) + """
from random import randint
listOfRandom2DPoints = [ [randint(0,dim),randint(0,dim)] for x in range(length)]"""

    theSciPyBuildTime.append( timeit.timeit('scipy.spatial.KDTree(listOfRandom2DPoints, leafsize=20)', setup=setup, number=nTimes)/nTimes )
    theSklBuildTime.append( timeit.timeit('sklearn.neighbors.KDTree(listOfRandom2DPoints, leaf_size=20)', setup=setup, number=nTimes)/nTimes )

    theTreeSkl = sklearn.neighbors.KDTree(listOfRandom2DPoints, leaf_size=20, metric='euclidean')
    f = open('temp.pkl','w')
    temp = pickle.dumps(theTreeSkl)

    theRebuildTime.append( timeit.timeit('pickle.loads(temp)', 'from __main__ import pickle,temp', number=nTimes)/nTimes )
比较查询时间的代码:

# Profiling the query time for the two KD-tree structures
import scipy.spatial, sklearn.neighbors

the_lengths = [100, 1000, 10000, 100000, 1000000, 10000000]

theSciPyQueryTime = []
theSklQueryTime = []

for length in the_lengths:
    dim = 5*int(math.sqrt(length))
    nTimes = 50
    listOfRandom2DPoints = [ [randint(0,dim),randint(0,dim)] for x in range(length)]

    setup = """from __main__ import sciPiTree,sklTree
from random import randint
length = """ + str(length) + """
randPoint = [randint(0,""" + str(dim) + """),randint(0,""" + str(dim) + """)]""" 

    sciPiTree = scipy.spatial.KDTree(listOfRandom2DPoints, leafsize=20)
    sklTree = sklearn.neighbors.KDTree(listOfRandom2DPoints, leaf_size=20)

    theSciPyQueryTime.append( timeit.timeit('sciPiTree.query(randPoint,10)', setup=setup, number=nTimes)/nTimes )
    theSklQueryTime.append( timeit.timeit('sklTree.query(randPoint,10)', setup=setup, number=nTimes)/nTimes )

问题:

  • 结果:尽管他们越来越接近非常大的N, SciKit learn似乎在构建时间和查询时间方面都优于SciPy。 其他人发现了这个吗

  • 数学:是否有更好的结构可用于此? 我只在二维空间中工作(尽管数据会非常复杂) 密度如此之大,蛮力出局),是否有更好的结构 低维kNN搜索

  • 速度:看起来这两种方法的构建时间是 离我越来越近了,但是我的电脑放弃了我——有人能告诉我吗 为我验证这一点以获得更大的N?!谢谢重建时间是多少 是否继续大致呈线性增长

  • 实用性:这棵树不会泡菜。如报告所述 ,我收到以下错误“PicklingError:无法” pickle:没有找到它 scipy.spatial.kdtree.innernode”-我认为这是因为它是一个 嵌套结构。根据一份报告中的回答, 嵌套结构可以用莳萝浸泡。然而,迪尔给了我 同样的错误-这是为什么


  • 在回答问题之前,我想指出,当您有一个使用大量数字的程序时,您应该始终使用
    numpy.array
    from来存储此类数据。我不知道Python的哪个版本,您正在使用哪个版本,但我使用的是Python 3.7.3、scikit learn 0.21.3和SciPy 1.3.0。当我运行代码来比较构建时间时,我得到了
    AttributeError:'list'对象没有属性'size'
    。此错误表示list
    listOfRandom2DPoints
    没有属性
    size
    。问题是
    sklearn.neights.KDTree
    需要
    numpy.array
    ,该数组具有属性
    size
    。类
    scipy.spatial.KDTree
    用于Python列表,但正如您在中看到的,第一行是
    self.data=np.asarray(data)
    ,这意味着数据将转换为
    numpy.array

    因此,我改变了你的台词:

    from random import randint
    listOfRandom2DPoints = [ [randint(0,dim),randint(0,dim)] for x in range(length)]
    
    致:

    (此更改不影响速度比较,因为在设置代码中进行了更改。)

    现在回答您的问题:

  • 就像你说的,scikit learn似乎在构建时变得很简单。发生这种情况的原因不是因为scikit learn有更快的算法,而是
    sklearn.neights.KDTree
    是在()中实现的,而
    scipy.spatial.KDTree
    是用纯Python代码()编写的

    (如果你不知道Cython是什么,一个过于简单的解释可能会 Cython使用Python和main编写C代码成为可能 这样做的原因是C比Python快得多)

    SciPy库在Cython
    SciPy.spatial.cKDTree
    ()中也有实现,它的工作原理与
    SciPy.spatial.KDTree
    相同,如果比较
    sklearn.neights.KDTree
    SciPy.spatial.cKDTree
    的构建时间:

    timeit.timeit('scipy.spatial.cKDTree(npListOfRandom2DPoints, leafsize=20)', setup=setup, number=nTimes)
    timeit.timeit('sklearn.neighbors.KDTree(npListOfRandom2DPoints, leaf_size=20)', setup=setup, number=nTimes)
    
    构建时间非常相似,当我运行代码时,
    scipy.spatial.cKDTree
    快了一点(大约20%)

    由于查询时间的情况非常相似,
    scipy.spatial.KDTree
    (纯Python实现)大约比
    sklearn.neights.KDTree
    (Cython实现)慢十倍,而
    scipy.spatial.cKDTree
    (Cython实现)大约和
    sklearn.neights.KDTree
    一样快。我测试了N=10000000的查询次数,得到了与您相同的结果。查询时间保持不变,与N无关(这意味着
    scipy.spatial.KDTree
    的查询时间对于N=1000和N=1000000是相同的,对于
    sklearn.neights.KDTree
    scipy.spatial.cKDTree
    的查询时间也是相同的)。这是因为查询(搜索)时间复杂度为O(logN),即使对于N=1000000,logN也非常小,因此差异太小,无法测量

  • sklearn.neights.KDTree
    \uuu init\uuu
    类的方法)的构建算法的时间复杂度为O(KNlogN)(),因此在您的例子中,它将是O(2NlogN),实际上是O(NlogN)。基于
    sklearn.neights.KDTree
    scipy.space.cKDTree
    非常相似的构建时间,我假设
    scipy.space.cKDTree
    的构建算法也具有O(NlogN)的时间复杂度。我不是最近邻搜索算法的专家,但基于一些在线搜索,我想说,对于低维最近邻搜索算法,这是尽可能快的。如果你去的话,你会看到有和。是精确的方法,它是的子类型。在所有空间划分方法中(仅适用于最近的nei的快速精确方法
    timeit.timeit('scipy.spatial.cKDTree(npListOfRandom2DPoints, leafsize=20)', setup=setup, number=nTimes)
    timeit.timeit('sklearn.neighbors.KDTree(npListOfRandom2DPoints, leaf_size=20)', setup=setup, number=nTimes)