统计学习方法——K近邻python实现

K近邻

1.k近邻法是基本且简单的分类与回归方法。k近邻法的基本做法是:对给定的训练实例点和输入实例点,首先确定输入实例点的k个最近邻训练实例点,然后利用这个训练实例点的类的多数来预测输入实例点的类。

2.k近邻模型对应于基于训练数据集对特征空间的一个划分。k近邻法中,当训练集、距离度量、k值及分类决策规则确定后,其结果唯一确定。

3.k近邻法三要素:距离度量、k值的选择和分类决策规则。常用的距离度量是欧氏距离及更一般的pL距离。k值小时,近邻模型更复杂;k值大时,近邻模型更简单。k值的选择反映了对近似误差与估计误差之间的权衡,通常由交叉验证选择最优的。

常用的分类决策规则是多数表决,对应于经验风险最小化。

4.k近邻法的实现需要考虑如何快速搜索 k 个最近邻点。kd树是一种便于对 k 维空间中的数据进行快速检索的数据结构。kd 树是二叉树,表示对维空间的一个划分,其每个结点对应于维空间划分中的一个超矩形区域。利用kd树可以省去对大部分数据点的搜索, 从而减少搜索的计算量。

暴力遍历代码

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

iris = load_iris()    #加载数据集
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df[label] = iris.target

data = df.iloc[:100,:2].values
target = df.loc[:99,label].values#如果使用:100会取到100,获得长度101的label,有点奇怪
X_train, X_test, y_train, y_test = train_test_split(data, target, test_size=0.2)

class KNN:
    def __init__(self, n:int, p:int, X_train, y_train):
        """
        n:邻居个数
        p:距离度量范数
        X_train:训练数据
        y_train:训练标签

        """
        self.n = n
        self.p = p
        self.X_train = X_train
        self.y_train = y_train
    
    def predict(self, point):
        dist = np.linalg.norm(point.reshape(1,2) - self.X_train, ord=self.p, axis=1)
        neighbors = self.y_train[np.argsort(dist)[:self.n]]
        return  np.argmax(np.bincount(neighbors)) #返回出现次数最多的元素

model = KNN(n=3,p=2,X_train=X_train,y_train=y_train)
predict = model.predict(X_test[0,:])
print(predict:,predict, ground truth:,y_test[0])

df = pd.DataFrame(X_train)
df[label] = y_train
zero = df[df[label] == 0]
one = df[df[label] == 1]
plt.scatter(zero.iloc[:,0], zero.iloc[:,1] , marker=o, label = 0)
plt.scatter(one.iloc[:,0], one.iloc[:,1] , marker=x, label = 1)
plt.scatter(X_test[0,0], X_test[0,1] , marker=+, label = predict)
plt.legend()
plt.show()

kd树版

首先看一下kd树的划分过程: 一个三维k-d树。第一次划分(红色)把根节点(白色)划分成两个节点,然后它们分别再次被划分(绿色)为两个子节点。最后这四个子节点的每一个都被划分(蓝色)为两个子节点。因为没有更进一步的划分,最后得到的八个节点称为叶子节点。(摘自wiki百科) 上图的分割方法就是kd树最经典的生成方法:

    随着树的深度轮流选择轴当作分割面。(例如:在三维空间中根节点是 x 轴垂直分割面,其子节点皆为 y 轴垂直分割面,其孙节点皆为 z 轴垂直分割面,其曾孙节点则皆为 x 轴垂直分割面,依此类推。) 点由垂直分割面之轴座标的中位数区分并放入子树
经验分享 程序员 微信小程序 职场和发展