sklearn之KNN算法

KNN算法

核心思想

未标记的数据样本,通过距离其最近的k个数据样本进行投票

算法原理

便利所有的样本点,计算每个样本点与待分类数据的距离,找出k个距离最近的点,统计每个类别的个数,投票数据最多的类别即为样本点的类别。

优点

准确性高,对异常值和噪声的容忍度较高

缺点

计算量大,需要将所有数据在内存中计算。

算法参数

k,k越大,模型偏差越大,对噪声的容忍度越大,容易造成欠拟合,k越小,模型方差越大,容易过拟合

算法变种

  1. 增加邻近数据的权重,距离越近权重越高,通过weights设置
  2. 使用半径范围取代k个点,sklearn中,RadiusNeighborsClassifier类实现了该方法

使用KNN分类示例

使用KNeighborsClassifier方法

from sklearn.neighbors import KNeighborsClassifier # 导入knn算法类
from matplotlib import pyplot as plt
import numpy as np
centers = [[-2,2],[2,2],[0,4]]
X,y = make_blobs(n_samples=60,centers=centers,random_state=0,cluster_std=0.6)  # 
生成聚类使用的数据
plt.figure(figsize=(16,10),dpi=144)c = np.array(centers)   # 将数据转为np array
plt.scatter(X[:,0],X[:,1],c=y,s=100,cmap="cool")
plt.scatter(c[:,0],c[:,1],s=100,marker="^",c="orange")  # 画出散点图
k= 5 # 设置k参数为5
clf = KNeighborsClassifier(n_neighbors=k)   # 定义knn的算法模型
clf.fit(X,y)
X_sample = np.array([0,2]).reshape(1, -1)   # 新版本的sklearn中所有的输入必须为2D的数据,所以这里使用了np reshape
y_sample = clf.predict(X_sample)  # 预测
neighbors = clf.kneighbors(X_sample,return_distance=False)  # 取出最邻近的k个数据样本plt.scatter(X_sample[:,0],X_sample[:,1],marker="x",c=y_sample,s=100,cmap="cool")
for i in neighbors[0]:    
    plt.plot([X[i][0],X_sample[:,0]],[X[i][1],X_sample[:,1]],"k--",linewidth =0.6)
plt.show()

在这里插入图片描述

使用KNN回归示例

使用KNeighborsRegressor方法

n_dots =40
X = 5*np.random.rand(n_dots,1)
y = np.cos(X).ravel()
y+= 0.2*np.random.rand(n_dots)-1
k = 5
knn=KNeighborsRegressor(n_neighbors=k)
knn.fit(X,y)
T = np.linspace(0,5,500)[:,np.newaxis]
y_pred = knn.predict(T)
knn.score(X,y)
plt.figure(figsize=(16,10),dpi=144)plt.scatter(X,y,c="g",label="data",s=100)
plt.plot(T,y_pred,c="k",label="pred",lw=4)
plt.axis("tight")
plt.title("KNN")
plt.show()

在这里插入图片描述

使用三种方法做分类

  1. 原始knn
  2. 带权重的knn
  3. 指定半径的knn
data = pd.read_csv("diabetes.csv")
X = data.iloc[:,0:8]
Y = data.iloc[:,-1]
from sklearn.model_selection import train_test_split
X_train,X_test,Y_train,Y_test = train_test_split(X,Y,test_size=0.2) # 将数据集分为测试集和训练集models = []
models.append(("KNN",KNeighborsClassifier(n_neighbors=2)))
models.append(("KNN with 
weights",KNeighborsClassifier(n_neighbors=2,weights="distance")))
models.append(("KNN 
RadiusNeighborsClassifier",RadiusNeighborsClassifier(n_neighbors=2,radius=500)))
result = []
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
for name,model in models:    
    kflod = KFold(n_splits=10)    
    cv_result = cross_val_score(model,X,Y,cv=kflod)    # model.fit(X_train,Y_train)                    result.append((name,cv_result))
for i in range(len(result)):
    print("name:{} score:{}".format(result[i][0],result[i][1].mean()))

特征选择

选出相关度最高的两个特征,通过卡方值来判断

from sklearn.feature_selection import SelectKBest
selector = SelectKBest(k=2)
X_new = selector.fit_transform(X,Y)

KNN算法蛮力实现

类似于暴力破解法

KNN KD树实现原理

KD树的建立

从m个样本的n维特征中,计算每个维度的方差,然后使用方差最大的特征作为根节点,对于这个特征,选取中位值的样本点作为划分点,对于小于该特征的划分到左子树,大于的划分到右子树,递归生成KD树。

示例

有数据
(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)

  1. 计算方差,第一维方差为6.97 ,第二维的方差为5.37,则选取第一维作为根节点,中位值为7,所以以(7,2)划分
  2. 分割超平面x=7将整个空间分为两部分:x<=7的部分为左子空间,包含3个节点={(2,3),(5,4),(4,7)};另一部分为右子空间,包含2个节点={(9,6),(8,1)}
  3. 用同样的办法划分左子树的节点{(2,3),(5,4),(4,7)}和右子树的节点{(9,6),(8,1)}。最终得到KD树。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JYJPZ1zB-1578235958718)(en-resource://database/724:0)]

KD树搜索

当我们生成KD树以后,就可以去预测测试集里面的样本目标点了。对于一个目标点,我们首先在KD树里面找到包含目标点的叶子节点。以目标点为圆心,以目标点到叶子节点样本实例的距离为半径,得到一个超球体,最近邻的点一定在这个超球体内部。然后返回叶子节点的父节点,检查另一个子节点包含的超矩形体是否和超球体相交,如果相交就到这个子节点寻找是否有更加近的近邻,有的话就更新最近邻。如果不相交那就简单了,我们直接返回父节点的父节点,在另一个子树继续搜索最近邻。当回溯到根节点时,算法结束,此时保存的最近邻节点就是最终的最近邻。

比如数据点(2,4.5)
先从根节点入手,2<7 ,进入根节点左子树,左子树根节点(5,4),根据y=4分割的,进入下一个节点(4,7),但是(2,4.5)到(4,7)的距离大于(5,4),换边,到(2,3)节点,计算(2,4.5)到(2,3)节点的距离,小于(5,4),ok,检索完毕,最近的是(2,3),找出了最近的点。
第二轮中,我们忽略上一轮中选择的点,每轮找出一个点,共找出k个,然后投票。

不过在处理分布不均匀的数据时,这种效率并不高。

sklearn参数详解

KNeighborsClassifierKNeighborsRegressorRadiusNeighborsClassifierRadiusNeighborsRegressor
n_neighbors选取最近样本数选取最近样本数xx
radiusxx样本半径样本半径
weightsuniform 权重相同,distance 权重与距离成反比同上同上同上
algorithm‘brute’对应第一种蛮力实现,‘kd_tree’对应第二种KD树实现,‘ball_tree’对应第三种的球树实现,‘auto’则会在上面三种算法中做权衡,选择一个拟合最好的最优算法同上同上同上
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值