sklearn:最近邻搜索sklearn.neighbors 最近邻查找算法kd-tree 【机器学习】K-means聚类算法初探

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/pipisorry/article/details/53156836
http://blog.csdn.net/pipisorry/article/details/53156836

ball tree
k-d tree也有问题[最近邻查找算法kd-tree ]。矩形并不是用到这里最好的方式。偏斜的数据集会造成我们想要保持树的平衡与保持区域的正方形特性的冲突。另外,矩形甚至是正方形并不是用在这里最完美的形状,由于它的角。如果图6中的圆再大一些,即黑点距离目标点点再远一些,圆就会与左上角的矩形相交,需要多检查一个区域的点,而且那个区域是当前区域双亲结点的兄弟结点的子结点。为了解决上面的问题,我们引入了ball tree。

ball tree

解决上面问题的方案就是使用超球面而不是超矩形划分区域。使用球面可能会造成球面间的重叠,但却没有关系。ball tree就是一个k维超球面来覆盖这些观测点,把它们放到树里面。图7(a)显示了一个2维平面包含16个观测实例的图,图7(b)是其对应的ball tree,其中结点中的数字表示包含的观测点数。

   

                   图 7  ball tree对二维平面的划分和ball tree

不同层次的圆被用不同的风格画出。树中的每个结点对应一个圆,结点的数字表示该区域保含的观测点数,但不一定就是图中该区域囊括的点数,因为有重叠的情况,并且一个观测点只能属于一个区域。实际的ball tree的结点保存圆心和半径。叶子结点保存它包含的观测点。
    使用ball tree时,先自上而下找到包含target的叶子结点,从此结点中找到离它最近的观测点。这个距离就是最近邻的距离的上界。检查它的兄弟结点中是否包含比这个上界更小的观测点。方法是:如果目标点距离兄弟结点的圆心的距离大于这个圆的圆心加上前面的上界的值,则这个兄弟结点不可能包含所要的观测点。(如图8)否则,检查这个兄弟结点是否包含符合条件的观测点。

 

    图 8 点与超圆
    那么,ball tree的分割算法是什么呢?
    选择一个距离当前圆心最远的观测点i1,和距离i1最远的观测点 i2,将圆中所有离这两个点最近的观测点都赋给这两个簇的中心,然后计算每一个簇的中心点和包含所有其所属观测点的最小半径。对包含n个观测点的超圆进行分割,只需要线性的时间。
    与k-d tree一样,如果结点包含的观测点到达了预先设定的最小值,这个顶点就可以不再分割了。

[【机器学习】K-means聚类算法初探 ]

kdtree和balltree的区别和联系
个人见解,
kd-tree基于欧氏距离的特性:
balltree基于更一般的距离特性:
因此:
kd-tree只能用于欧氏距离,并且处理高维数据效果不佳。
balltree在kd-tree能够处理的数据范围内要慢于kd-tree。

皮皮blog

sklearn中使用kdtree和balltree
这个库的tree实现不太好,输入的数据会转换成ndarray,输出也是ndarray,这样就没办法传递附加数据了。。。也是烦人。。。

参数训练
KDTree(X, leaf_size=40, metric=’minkowski’, **kwargs)

BallTree(X, leaf_size=40, metric=’minkowski’, **kwargs)

参数解释

X : array-like, shape = [n_samples, n_features] 但也可以是dataframe类型(只要输入原始df数据的float类型的列(或者提前转换成)就可以)

leaf_size : positive integer (default = 40)
改变leaf_size不会改变查询结果,但是会显著影响查询速度(其实应该也包含训练速度吧)和存储内存。The amount of memory needed to store the tree scales as approximately n_samples / leaf_size. 

metric : string or DistanceMetric object 用于树的距离度量:the distance metric to use for the tree. Default=’minkowski’with p=2 (that is, a euclidean metric). See the documentationof the DistanceMetric class for a list of available metrics.ball_tree.valid_metrics gives a list of the metrics whichare valid for BallTree.

查看可用的度量方法

from sklearn import neighbors

neighbors.KDTree.valid_metrics

['chebyshev',
 'manhattan',
 'infinity',
 'p',
 'l1',
 'cityblock',
 'euclidean',
 'minkowski',
 'l2']

[sklearn距离度量函数[sklearn.neighbors.DistanceMetric¶]

近邻查找
query(X[, k, return_distance, dualtree, ...])    query the tree for the k nearest neighbors
query_radius    query_radius(self, X, r, count_only = False)
Note: 

1 query查询时返回的是距离和下标,下标对应的是输入的原始数据的下标,所以原始数据可以附加很多字段(只是不输入到树的构建数据中)就可以了。

2 lz测试时发现每次query查询时都会调用距离度量函数。

query
dist, inds = loc_kdtree.query(l_array[0].reshape(1, -1), k=5)

query返回值是距离(这里的数值就是metrics计算出来的那个数值)和samples的下标。

Note: 要注意的是index返回的是一个二维数组,第个一维数组元素对应的是一个查询的近邻结果。所以如果训练数据直接调用l_array[inds]返回的是一个三维数组,只查询一个二维数据的近邻时应该使用l_array[inds[0]]。

i : array of integers - shape: x.shape[:-1] + (k,). each entry gives the list of indices ofneighbors of the corresponding point.

query_radius半径查找
默认只返回index:ind = tree.query_radius(X[0], r=0.3)

count : if count_only == True

ind : if count_only == False and return_distance == False

(ind, dist) : if count_only == False and return_distance == True. 注意返回顺序还和query还不一样。。。

count : array of integers, shape = X.shape[:-1]  each entry gives the number of neighbors withina distance r of the corresponding point.

其它参数及其含义
# variables to keep track of building & querying stats
    cdef int n_trims
    cdef int n_leaves
    cdef int n_splits
    cdef int n_calls

    def get_tree_stats(self):
        return (self.n_trims, self.n_leaves, self.n_splits)

    def reset_n_calls(self):
        self.n_calls = 0

    def get_n_calls(self):
        return self.n_calls

    def get_arrays(self):
        return (self.data_arr, self.idx_array_arr,
self.node_data_arr, self.node_bounds_arr)

[scikit-learn/sklearn/neighbors/binary_tree.pxi]

皮皮blog

kdtree实现时的错误
还有一个坑就是sklearn版本问题,本地错误解决,放到服务器上远程跑还是出错,发现从0.18升级到0.18.1就不会报错了,也是醉了。。。

ValueError: metric PyFuncDistance is not valid for KDTree

    The ball tree works with any of the following distance metrics, which match those found in the module scipy.spatial.distance:['euclidean', 'minkowski', 'manhattan', 'chebyshev',  'seuclidean', 'mahalanobis', 'wminkowski', 'hamming',  'canberra', 'braycurtis', 'matching', 'jaccard',  'dice', 'kulsinski', 'rogerstanimoto', 'russellrao',  'sokalmichener', 'sokalsneath', 'haversine']
Alternatively, the user can specify a callable Python function to act as the distance metric. While this will be quite a bit slower than using one of the optimized metrics above, it adds nice flexibility.
    The kd-tree works with only the first four of the above metrics. This limitation is primarily because the distance bounds are less efficiently calculated for metrics which are not axis-aligned.

[Benchmarking Nearest Neighbor Searches in Python]

直接将metric写成一个函数会出错,因为metric参数接受的类型为:string or DistanceMetric object

loc_kdtree = neighbors.KDTree(l_array, metric=lambda i, j: distance.vincenty(tuple(i), tuple(j)).miles)
        if callable(metric):
            if algorithm == 'kd_tree':
                # callable metric is only valid for brute force and ball_tree
                raise ValueError(
                    "kd_tree algorithm does not support callable metric '%s'" % metric)
        elif metric not in VALID_METRICS[alg_check]:
            raise ValueError("Metric '%s' not valid for algorithm '%s'" % (metric, algorithm))

ValueError: func must be a callable taking two arrays

[Sklearn kNN usage with a user defined metric]

[Sklearn kNN usage with a user defined metric (again)]

[Sklearn kNN usage with a user defined metric]

TypeError: __init__() takes exactly 1 positional argument (0 given)
参数是func=lambda不是pyfunc=lambda

loc_kdtree = neighbors.KDTree(l_array, metric='pyfunc', func=lambda i, j: distance.vincenty(i, j).miles)

或者loc_kdtree = neighbors.KDTree(l_array, metric=neighbors.DistanceMetric.get_metric('pyfunc',func=lambda i, j: distance.vincenty(i, j).miles))

ValueError: Buffer has wrong number of dimensions (expected 2, got 1)
用于训练的数据应该是二维的,如果输入的是一维的列表什么的,可以在外面加一个[]号。

sklearn Deprecation Warning
Deprecation Warning: Passing 1d arrays as data is deprecated in 0.17 and will raise ValueError in 0.19

出错问题:

分类器分类预测时:clf.predict([1, 1])

最近邻查询时:kdtree.query(l_array[0])...

原因:输入的预测或者查询不是二维的而是一维的

解决:改成二维的:clf.predict([[1, 1]]), kdtree.query([l_array[0]])

Note: 这个warning有点坑啊,应该可以通过修复sklearn代码解决吧。

[Getting deprecation warning in Sklearn over 1d array, despite not having a 1D array]

皮皮blog


最近邻查找的应用
[Is a kd-tree suitable for 4D space-time data (x,y,z,time)?]

[Datetime as a dimension in python KDTree]

from: http://blog.csdn.net/pipisorry/article/details/53156836

ref: [scikit-learn modules 1.6. Nearest Neighbors]

[scikit-learn/sklearn/neighbors/]
————————————————
版权声明:本文为CSDN博主「-柚子皮-」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/pipisorry/article/details/53156836

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: (1)完善sift和k-means代码,实现图像表示。 SIFT(尺度不变特征转换)是一种用于提取图像中关键点的特征算法。可以使用OpenCV库中的SIFT函数来实现SIFT算法。首先,使用SIFT函数加载图像并检测图像中的关键点。然后,对于每个关键点,计算其关键点描述符,该描述符表示了关键点周围区域的特征。最后,可以将这些描述符用于图像表示,例如使用图像表示方法(如词袋模型)构建一个视觉单词词袋。 k-means算法是一种常用的聚类算法,可以用于对图像特征进行聚类分析。可以使用sklearn库中的KMeans函数来实现k-means算法。首先,将图像表示的特征向量作为输入数据。然后,使用KMeans函数对这些特征向量进行聚类分析,将其分为不同的簇。最后,可以将每个簇的中心作为代表该簇的特征向量,用于图像分类或其他应用。 (2)利用最近邻算法,实现图像的分类。 最近邻算法是一种简单但有效的分类算法,可以用于图像分类。可以使用sklearn库中的KNeighborsClassifier函数来实现最近邻算法。首先,准备用于训练和测试的图像数据集,每个图像都有对应的标签。然后,将图像表示的特征向量作为输入数据,将标签作为目标变量。接下来,使用KNeighborsClassifier函数将训练数据拟合到最近邻分类器,并对测试数据进行预测。最后,可以评估分类器的准确性,例如计算分类器在测试数据上的精确度、召回率和F1得分等指标。 通过将SIFT和k-means结合应用到图像数据集上,并利用最近邻算法进行图像分类,可以实现对图像进行有效的表示和分类。这种方法可以应用于图像检索、图像识别等各种视觉任务中。 ### 回答2: (1)完善sift和k-means代码,实现图像表示: 要实现图像表示,可以使用SIFT算法K-means聚类算法。首先,对于SIFT算法,可以使用OpenCV等图像处理库提供的函数来提取图像的SIFT特征。SIFT特征是一种局部特征,可以描述图像中关键点的位置、尺度和方向等信息。通过调用相应的函数,可以得到图像中所有关键点的SIFT描述子。 然后,对于K-means聚类算法,可以使用机器学习库如scikit-learn等来实现。K-means是一种无监督学习算法,通过将样本划分为K个聚类簇,使得每个样本到其所属簇中心的距离最小。在图像表示中,可以将每个SIFT描述子看作一个样本,并使用K-means算法将这些描述子聚类。由于SIFT描述子的维度较高,通常需要进行降维处理,可以使用主成分分析(PCA)等方法进行降维。 最后,将每个图像表示为聚类出的K个簇中的某个簇的索引,即每个图像表示为一个K维的向量。这个向量可以用来表示图像的特征,进而用于图像检索、分类等任务。 (2)利用最近邻算法,实现图像的分类: 要实现图像的分类,可以使用最近邻算法最近邻算法是一种基本的分类方法,它通过计算待分类样本与训练样本之间的距离,选择距离最近的K个样本的类别作为待分类样本的类别。 对于图像分类,可以将每个图像表示为前面提到的K维向量。然后,根据训练数据集中的图像向量和其对应的类别标签,构建最近邻算法。在进行分类时,对于一个待分类图像,计算它与每个训练数据集中图像向量的距离,并选取距离最近的K个样本。根据这K个样本的类别标签,可以采用投票法则或加权法则来决定待分类图像的类别。也就是说,最近邻算法将待分类图像的类别与K个距离最近的训练样本的类别进行比较,选择频次最高的类别作为最终的分类结果。 需要注意的是,在实际应用中,需要对图像进行预处理,如图像的灰度化、归一化等,以提高最近邻算法的分类效果。此外,还可以采用交叉验证等方法来优化算法的参数选择,提高分类的准确性。 ### 回答3: (1) 完善SIFT (尺度不变特征转换)算法K-means算法的代码,可以实现图像的表示。SIFT算法可以提取出图像中关键点的特征,这些特征是图像中的局部最大值,对于旋转、缩放和平移等变换具有不变性,因此可以用来描述图像。K-means算法是一种聚类算法,可以将提取出来的SIFT特征进行聚类,使得同一类别的特征被分配到同一类别的质心上,从而得到图像的表示。 对于SIFT算法的代码实现,可以使用opencv库中的sift函数。首先,读取图像并转为灰度图像。然后,利用sift函数,提取关键点和关键点的描述子。最后,将关键点和描述子保存起来。 对于K-means算法的代码实现,可以使用sklearn库中的KMeans类。首先,读取之前保存的关键点和描述子。然后,定义K-means模型,设定聚类数量。接着,使用fit函数对关键点进行聚类,并得到每个关键点所属的类别。最后,将每个关键点所属的类别作为图像的表示。 (2) 利用最近邻算法(K-Nearest Neighbors),可以实现图像的分类。最近邻算法是一种简单而有效的分类算法,它基于样本之间的相似性度量,将测试样本与训练样本中最相似的K个样本进行比较,然后根据这K个样本的类别进行分类。 首先,对于每个类别的训练样本,可以用之前提到的图像表示方法得到每个图像的表示向量。然后,对于一个待分类的测试图像,同样使用图像表示方法得到表示向量。接着,将测试图像的表示向量与所有训练图像的表示向量进行对比,计算相似性度量(如欧氏距离或余弦相似度)。根据最相似的K个训练样本的类别进行决策,一般使用多数投票的方法。 最后,将测试图像分类为得票最多的类别,即为所属的类别。 需要注意的是,上述方法仅仅是最近邻算法的基本流程,在实际应用中还会有很多更复杂的方法和技巧用于提高分类效果,比如特征选择、特征加权等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值