KD树------knn的变种算法

knn:是一种蛮力实现的方法,如果数据量非常大的情况,计算量也非常大。
KNN的两个变种算法:KD树和球树

什么是KD树?

KD树建树采用是从m个样本n维特征中,分别计算n个特征的取值的方法,用方差最大的第K维特征nk来作为根节点
(选择特征nk的取值的中位数nkv对应的样本作为划分点,对于所有第k维特征的取值小于nkv的样本,划入左子树们,对于第k维特征的取值大于等于nkv的样本,划入右子树,对于左子树和右子树,采用和刚才同样的方法来找方差最大的特征来做根节点,递归的生成KD树。)
KD树搜索最近邻:
1,首先在KD树里面找到包含目标的叶子节点。
以目标点为圆心,以目标点到叶子节点样本实例的距离为半径,得到一个超球体,最近邻的点一定在这超球体内部。
2,然后返回叶子节点的父节点,检查另一个子节点包含的超矩形体和超球体相交,如果相交就到这个子节点寻找是否有更加近的近邻,有,则更新最近邻。如果不相交,直接返回父节点的父节点,在另一个子树继续搜索最近邻。
3,当回溯到根节点时,算法结束,此时保存的最近邻节点就是最终的最近邻。

什么是球树?

KD树算法虽然提高了KNN搜索效率,但是在遇到不均匀分布的数据集时,效率并不高。
(当样本中某一类特别多,而另一类特别少的时候,新的样本可能直接分到类别多的样本中了)
球树,顾名思义,就是每个分隔块都是超球体,而不是KD树里面的超矩形体。
建树流程:
1,先构建一个超球体,(这个超球体可以包含所有样本的最小球体)。
2,从球中选择一个离球的中心最远的点,然后在选择第二个点(离第一个点最远),将球中所有的点分配到离这两个聚类中心最近的一个上,并计算每个聚类的中心,以及聚类能够包含它所有数据点所需的最小半径。(这样就得到两个子超球体,和KD树里面的左右子树对应。)
3,对于2)的子超球体,递归执行2)。最终得到一个球树。
其实,就是将一个大的计算改成了几个小的计算,来提高它的计算效率
球树搜索最近邻
1,使用球树找出给定目标点的最近邻方法是:首先自上而下贯穿整棵树找出包含目标点所在的叶子,并在这个球里找出与目标点最邻近的点,这将确定出目标点距离它的最邻近的一个上限值,然后跟KD树查找一样,检查兄弟结点,如果目标点兄弟结点中心的距离超过兄弟结点的半径当前的上限值之和,那么兄弟结点不可能存在一个更近的点;否则,必须进一步检查位于兄弟结点以下的子树。
2,检查完兄弟结点后,向父节点回溯,继续搜索最小邻近值。当回溯到根节点时,此时的最小邻近值就是最终的搜索结果。

小结:

无论KD树还是球树,返回的都是一个最近邻的值。
KNN的主要优点:
1,理论成熟,思想简单,既可以做分类也可以做回归
2,可用于非线性分类
3,训练时间复杂度比支持向量机之类算法低,仅为O(n)
4,和朴素贝叶斯之类的算法比,对数据没有假设,准确度高,对异常点不敏感
5,KNN主要靠周围有限的邻域的样本(不是靠判别类域的方法来判断所属类别),对于类域交叉或重叠较多的待分样本集来说KNN比其他方法更适合
6,适用于样本容量较大的类域的自动分类(样本容量较小,容易产生误分)
主要缺点:
1,计算量大(尤其是特征特别多的时候)
2,样本不平衡的时候,对稀有类别的预测准确率低
3,KD树,球树之类的模型建立需要大量的内存
4,使用慵懒学习方法,基本上不学习,导致预测时速度比起逻辑回归之类的算法慢
5,相比决策树模型,KNN模型可解释性不强

机器学习算法库包(百度)
Sklearn基本的应用
import numpy as np 
from sklearn.neighbors import KNeighborsClassifier

if __name__ =="__main__":
    dataset=np.loadtxt("C:/Users/yanruyu/Documents/code/python/GA/dataset.txt",dtype="str",encoding="utf-8",delimiter=",")
    x=dataset[:,:-1].astype(np.float)
    y=dataset[:,-1]
    #建立模型--算法学习模型
    model=KNeighborsClassifier(n_neighbors=5,weights="distance")
    #训练模型--只要输入(输入数据和输出数据,让模型自己训练,不用管)
    model.fit(x,y)
    #预测
    predict_data=[[2,2]]    #注意预测时,输入数据维度一致
    result=model.predict(predict_data)
    print(result)
    print(model.predict_proba(predict_data))
(官网代码分析)鸢尾花为例:
#-coding:utf-8--
print ( __doc__ )

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn import neighbors , datasets

n_neighbors = 15

# import some data to play with
iris = datasets . load_iris ()

# we only take the first two features. We could avoid this ugly
# slicing by using a two-dim dataset
X = iris . data [:, : 2 ]
y = iris . target

h = .02  # step size in the mesh

# Create color maps
cmap_light = ListedColormap ([ 'orange' , 'cyan' , 'cornflowerblue' ])#背景(红绿蓝)
cmap_bold = ListedColormap ([ 'darkorange' , 'c' , 'darkblue' ])#原点

for weights in [ 'uniform' , 'distance' ]:#权重相等和权重按距离计算
    # we create an instance of Neighbours Classifier and fit the data.
    clf = neighbors . KNeighborsClassifier ( n_neighbors , weights = weights )
    clf . fit ( X , y )

    # Plot the decision boundary. For that, we will assign a color to each
    # point in the mesh [x_min, x_max]x[y_min, y_max].
    x_min , x_max = X [:, 0 ] . min () - 1 , X [:, 0 ] . max () + 1
    y_min , y_max = X [:, 1 ] . min () - 1 , X [:, 1 ] . max () + 1
    xx , yy = np . meshgrid ( np . arange ( x_min , x_max , h ),
                         np . arange ( y_min , y_max , h ))
    Z = clf . predict ( np . c_ [ xx . ravel (), yy . ravel ()])  #展开为一维(扁平化)

    # Put the result into a color plot
    Z = Z . reshape ( xx . shape )
    plt . figure ()
    plt . pcolormesh ( xx , yy , Z , cmap = cmap_light )

    # Plot also the training points
    plt . scatter ( X [:, 0 ], X [:, 1 ], c = y , cmap = cmap_bold ,
                edgecolor = 'k' , s = 20 )
    plt . xlim ( xx . min (), xx . max ())
    plt . ylim ( yy . min (), yy . max ())
    plt . title ( "3-Class classification (k =  %i , weights = ' %s ')"
              % ( n_neighbors , weights ))

plt . show ()

相关知识
**这里以[X,Y]=meshgrid(x,y)为例,**对函数进行介绍。[X,Y]=meshgrid(x,y)将向量x,y定义的区域转换成矩阵X,Y。其中矩阵X的行向量是向量x的简单复制。而矩阵Y的列向量是向量y的简单复制(注:代码中的X,Y均是数组,在文中统一称为矩阵
假设x是长度为m的向量,y是长度为n的向量,则最终生成的矩阵X,Y的维度都是nm(不是mn)

import numpy as np 
import matplotlib.pyplot as plt 
m,n=(5,3)
x=np.linspace(0,1,m)
print('x:',x)
y=np.linspace(0,1,n)
print('y:',y)
X,Y=np.meshgrid(x,y)
print(X)
print(Y)
············································
输出:
x: [0.   0.25 0.5  0.75 1.  ]
y: [0.  0.5 1. ]
[[0.   0.25 0.5  0.75 1.  ]
 [0.   0.25 0.5  0.75 1.  ]
 [0.   0.25 0.5  0.75 1.  ]]
[[0.  0.  0.  0.  0. ]
 [0.5 0.5 0.5 0.5 0.5]
 [1.  1.  1.  1.  1. ]]

了解参数,可通过原文件的的途径;
正常sklearn步骤有:建立模型,训练模型,预测三步;其他情况会有参数的选择

KNN的参数说明:

n_neighbors:KNN中的k值,默认为5(对于k值的选择,前面已经给出解释);

weights:用于标识每个样本的近邻样本的权重,可选择"uniform",“distance” 或自定义权重。默认"uniform",所有最近邻样本权重都一样。如果是"distance",则权重和距离成反比例;如果样本的分布是比较成簇的,即各类样本都在相对分开的簇中时,我们用默认的"uniform"就可以了,如果样本的分布比较乱,规律不好寻找,选择"distance"是一个比较好的选择;

algorithm:限定半径最近邻法使用的算法,可选‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’。
‘brute’对应第一种线性扫描;
‘kd_tree’对应第二种kd树实现;
‘ball_tree’对应第三种的球树实现;
‘auto’则会在上面三种算法中做权衡,选择一个拟合最好的最优算法。

leaf_size:这个值控制了使用kd树或者球树时, 停止建子树的叶子节点数量的阈值。这个值越小,则生成的kc树或者球树就越大,层数越深,建树时间越长,反之,则生成的kd树或者球树会小,层数较浅,建树时间较短。默认是30。

这个值一般依赖于样本的数量,随着样本数量的增加,这个值必须要增加,否则不光建树预测的时间长,还容易过拟合。可以通过交叉验证来选择一个适中的值。当然,如果使用的算法是蛮力实现,则这个参数可以忽略;

metric,p:距离度量(前面介绍过),默认闵可夫斯基距离 “minkowski”(p=1为曼哈顿距离, p=2为欧式距离);

metric_params:距离度量其他附属参数(具体我也不知道,一般用得少);

n_jobs:并行处理任务数,主要用于多核CPU时的并行处理,加快建立KNN树和预测搜索的速度。n_jobs= -1,即所有的CPU核都参与计算。
radius:限定半径,默认为1。半径的选择与样本分布有关,可以通过交叉验证来选择一个较小的半径,尽量保证每类训练样本其他类别样本的距离较远;
outlier_labe:int类型,主要用于预测时,如果目标点半径内没有任何训练集的样本点时,应该标记的类别,不建议选择默认值 None,因为这样遇到异常点会报错。一般设置为训练集里最多样本的类别
————————————————
原文链接:https://blog.csdn.net/qq_40195360/article/details/86714337

示例代码:
from sklearn import neighbors , datasets
from sklearn.model_selection import train_test_split
x=datasets.load_iris()
print(x.data.shape)
x_train,x_test,y_train,y_test=train_test_split(x.data,x.target,test_size=0.3)#切片 0.3是测试集
print(len(x_train),len(x_test))
··········································
输出:
(150, 4)
105 45
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AppleYRY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值