美文网首页
机器学习模型1 K-Nearest Neighbor(KNN)

机器学习模型1 K-Nearest Neighbor(KNN)

作者: Python_Franklin | 来源:发表于2018-05-13 22:05 被阅读0次

    1、模型原理

    (一)原理
    1、原理:是一种常用的监督学习方法,给定测试样本,基于某种距离度量找出训练集中与其最靠近的k个训练样本,然后基于这k个“邻居”的信息来进行预测。也有无监督的最近邻,暂不讨论。
    2、判定方法主要有两种:
    (1)在分类任务中的可使用“投票法”,即选择这k个样本中出现最多的类别标记作为预测结果;
    (2)在回归任务中可使用“平均法”,即将这k个样本的标记平均值作为预测结果。
    (3)还可以根据距离远近,对样本进行加权,实现加权平均或加权投票。

    (二)注意点:
    1、距离度量方法不同,找到的“近邻”也可能有显著区别,进而导致分类结果不同。通常是用欧式距离,即平方和开根号。
    2、k在其中是一个相当重要的参数,k取值不同时,分类结果会有显著不同。
    3、

    (三)相关概念
    1、“维度灾难”,如果样本的属性维度过多,在这种高维情况下,会出现数据样本稀疏(不密集,太过分散),距离计算困难等问题,这是所有机器学习方法共同面对的问题,被称为维度灾难。
    2、由于这种情况,就需要进行降维。在低维空间中保持样本点间的距离不变,最简单的是对原始的高维空间进行线性变换,主成分分析就是最常见的一种线性降维方法。
    有时,需要非线性映射才能找到恰当的低维嵌入,就会采用比如“核技巧”等非线性降维方法。

    这里引申出来了“主成分分析”方法,可以在下面做补充。

    (四)Python实现步骤
    (1)计算已知类别数据集中的每个点依次执行以下操作;
    (2)按照距离递增次序排序(越来越大);
    (3)选取与当前点距离最小的k个点;
    (4)确定前k个点所在类别的出现频率;
    (5)返回前k个点出现频率最高的类别作为当前点的预测分类

    最近邻算法,是基于输入样本的,它和其他算法不一样,最近邻不会试图去构造一个泛化的模型(即,它的思路不是去拟合出一个含有各种参数的函数,然后把新的数据带入就可以得到新的结果),而只是去简单的使用输入训练集的所有数据,通过测算距离,来实现分类或回归。

    分为KNN分类(KNeighborsClassifier)和KNN(KNeighborsRegressor)回归两种,一种是预测属性(离散值),一种是预测数值(连续值)。

    与它对应的还有,通过设置半径R来进行分类和回归的,RadiusNeighborsClassifier和RadiusNeighborsRegressor。当用户确定了一个半径之后,这些在半径之内的点都会被考虑。
    当我们需要训练的数据不那么规范的时候RadiusNeighborsClassifier (RN)会是一个更好的选择,对于一些高维空间,RN的效率会受到影响,这也是一种“维度之殇”了吧。

    2、Python3中sklearn-KNN的代码实现

    第一,sklearn中的KNN包源代码(未查到,以后补充)

    第二,sklearn中的KNN包,有几个可调参数,及每个参数代表的意义

    KNeighborsClassifier( n_neighbors=5, weights=’uniform’, algorithm=’auto’, leaf_size=30, p=2, metric=’minkowski’, metric_params=None, n_jobs=1, **kwargs )

    • n_neighbors,即选择k值,较大的k值可以容忍较多的噪声,但是会使得分类的结果变的不那么精确;但样本不平衡时,一个类样本容量很大,其他样本容量很小,导致输入新样本时,该样本邻近中大样本占多数,因此可以采取权值的方法(和样本距离小的邻近权值大)来改进,减少k值选择对结果的影响;可以通过循环来尝试不同的k值的效果。

    • weights,即权重设置,‘uniform’和‘distance’,对每个点赋予同样的权重,或者根据距离远近,赋予不同的权重(距离越远权重越小)。

    • algorithm,即搜索最近邻算法的选择,包括ball_tree、kd_tree、brute和auto。
      brute代表Brute Force算法,就是一个最原始(蛮力)邻居搜索做法,Brute Force在寻找邻居时,会把输入的点同所有样本中的点做一个距离计算,然后再排序选择最近的点。
      kd_tree代表KD树算法,为了解决BF算法效率低下的问题,人们提出了很多树形结构的算法,树形结构的主要贡献在于,它们一般通过事先的合理组织,降低了我们搜索中的开销,也就是使用树形结构的算法,我们在搜索时可以不用每个样本都去计算距离了,这无疑降低了很多的开销。在不太高的维度(小于20)下,KD树的效果是很不错的,不过当维度走向更高时,KD树的效率也会随之下降,这也呼应了我们之前提到的“维度之殇”的问题。
      ball_tree代表Ball Tree算法,KD-Tree是为了解决Brute Force的效率问题,那么Ball-Tree也就是为了解决KD-Tree在高维情况下的效率不佳的另一个做法了,Ball树在构建的时候,比起KD树要复杂许多,不过在最后的搜索过程中,其表现就会非常好。
      三者的选取:样本≤30,用BF;样本较大,但维度≤20,用KD_tree;维度更多的,用ball tree。
      参考:知乎回答:KDtree和Ball Tree的区别
      默认值是auto,在auto下,将会从你给定的测试数据当中选择最终性能最好的哪一个算法。

    • leaf_size,设置一个数值,什么时候切换到BF暴力求解,默认是30。

    • metric ,用于树的距离度量。默认'minkowski与P = 2(即欧氏度量)。

    第三,KNN的基本操作

    from sklearn.neighbors import KNeighborsClassifier
    knn = KNeighborsClassifier(n_neighbors=6)  #设置knn中的参数,并赋予某变量
    knn.fit(x,y)                      #导入训练集,进行模型训练,x是数据,y是标签
    y_pred = knn.predict(X_new)    #带入新样本进行分类预测
    

    参考:sklearn中KNN分类的官方说明

    如何判断准确率?那只能是把有标签的数据划分为训练集、测试集,然后看它预测的准确率。

    from sklearn.model_selection import train_test_split #调用了sklearn中进行测试集和训练集分类的函数
    X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=42,stratify=y) 
    knn.score(X_test,y_test)   #  .score,就是测试准确度用的
    

    具体的用法如下:

    fit(x,y)                                #导入数据
    get_params([deep])                      #获取此估算器的参数
    kneighbors([X, n_neighbors, return_distance])    #找到一个点的n个邻居,并返回距离值
    kneighbors_graph([X, n_neighbors, mode])  # 计算X中的点的k-邻居的(加权)图
    predict(X)  #预测提供的数据的分类标签
    predict_proba(X)  #返回测试数据X的概率估计。
    score(X, y[, sample_weight])  #返回给定测试数据上的平均精确度
    set_params(**params)  #设置此估算器的参数
    

    取不同k值时,计算准确度

    #取不同k值的效率图:
    #创建一个数组储存训练和测试数据的精确度
    neighbors = np.arange(1, 9)
    train_accuracy = np.empty(len(neighbors))
    test_accuracy = np.empty(len(neighbors))
    
    # 循环对k进行赋值
    for i, k in enumerate(neighbors):
        # Setup a k-NN Classifier with k neighbors: knn
        knn = KNeighborsClassifier(n_neighbors=k)
    
        # Fit the classifier to the training data
        knn.fit(X_train,y_train)
    
        #计算训练集的准确度
        train_accuracy[i] = knn.score(X_train, y_train)
    
        #计算测试集的准确度
        test_accuracy[i] = knn.score(X_test, y_test)
    

    用一个循环对

    一个简单的小例子

    import numpy as np    
    from sklearn import neighbors   
    
    knn = neighbors.KNeighborsClassifier() #取得knn分类器    
    data = np.array([[3,104],[2,100],[1,81],[101,10],[99,5],[98,2]]) #data对应着打斗次数和接吻次数  
    labels = np.array([1,1,1,2,2,2]) #labels则是对应Romance和Action  
    knn.fit(data,labels) #导入数据进行训练   
    print(knn.predict([18,90])) 
    

    一点注意

    拿《机器学习实战》中第二章KNN部分的约会网站数据进行了测试,发现虽然直接用的是结果类别标签数据‘largeDoses’、‘smallDoses’、‘didntLike’,未进行类别变量的转换,但在模型预测时,可以正确执行预测,结果直接为‘didntLike’等。

    3、参考资料

    刘建平博客中关于KNN的部分:
    K近邻法(KNN)原理小结
    scikit-learn K近邻法类库使用小结

    以及ML:Scikit-Learn 学习笔记--- Nearest Neighbors 最近邻 1-3篇

    参考的两篇帖子,NumPy 和 sklearn入门,以及 ML神器:sklearn的快速使用
    里面提到的几个点很好,比如为什么不用Python自带的数组list,而使用Numpy的array。

    比如,sklearn中各个算法有统一的API接口,各个算法的一般实现流程是:

    step1. 数据加载和预处理

    step2. 定义分类器, 比如: lr_model = LogisticRegression()

    step3. 使用训练集训练模型 : lr_model.fit(X,Y)

    step4. 使用训练好的模型进行预测: y_pred = lr_model.predict(X_test)

    step5. 对模型进行性能评估:lr_model.score(X_test, y_test)

    引申问题

    1、计算样本间的差异有多大,也就是样本间距离。涉及到如何衡量距离。
    2、排序问题,最经典的算法问题了。
    这应该都有专门的代码。

    相关文章

      网友评论

          本文标题:机器学习模型1 K-Nearest Neighbor(KNN)

          本文链接:https://www.haomeiwen.com/subject/qxxhdftx.html