KNN算法和sklearn中的KNN算法

本文深入浅出地介绍了KNN算法的基本思想及其实现过程,并通过Python编程实例展示了如何使用KNN进行分类。此外,还利用sklearn库实现了KNN算法,并通过网格搜索优化了超参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

KNN基本思想

KNN是通过测量不同特征值之间的距离进行分类。它的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别,其中K通常是不大于20的整数。KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。

使用图来说话比较方便:

原始数据的散点图如下:

如果增加一个数据点(增加的数据点用绿色来表示)如下:

那么新增的数据点归为哪一类呢?

如果我们测量3个点分别到绿色点的距离,那么很显然归为蓝色这一类。

如此便可以很形象的说,knn,就是选择k个点与新增加的点测量距离,距离最近点最多的意味着得到的票数越多,便归为那一类。

 

使用python进行编程:

# -*- coding: utf-8 -*-
import numpy as np
from math import sqrt
from collections import Counter

class KNN_Classifier:
    def __init__(self,k):
        """构造函数"""
        #给定k值
        self.k=k
        self.X_train=None
        self.y_train=None
    def fit(self,X_train,y_train):
        """训练模型"""
       #knn的训练模型实际上就是把训练数据集进行保存
        assert self.k<=X_train.shape[0],\
               "k的值必须小于等于X_train的第二个维度"
        self._X_train=X_train
        self._y_train=y_train
        return self
    def predicty(self,x):
        """对矩阵中的元素进行预测"""
        assert self._X_train is not None and self._y_train is not None,\
               "X_train and y_train must be fit"
        assert self._X_train.shape[1]==x.shape[1],\
               "X_train和x的维度应该相等"
        y_predict=[self._predict(m) for m in x]
        return np.array(y_predict)
    def _predict(self,m):
        """预测每个点的函数"""
        #求距离
        distances=np.array(np.array([sqrt(np.sum((x-m)**2)) for x in self._X_train]))
        #得到值从小到大后排序的索引值
        top_y=distances.argsort()
        #取出最近的k个值
        nearest=self._y_train[top_y[:self.k]]
        #得到预测值
        predict_y=Counter(nearest).most_common(1)[0][0]
        return predict_y

sklearn中的KNN

import numpy as np
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt

raw_data_X = [
    [3.393533211, 2.331273381],
    [3.110073483, 1.781539638],
    [1.343808831, 3.368360954],
    [3.582294042, 4.679179110],
    [2.280362439, 2.866990263],
    [7.423436942, 4.696522875],
    [5.745051997, 3.533989803],
    [9.172168622, 2.511101045],
    [7.792783481, 3.424088941],
    [7.939820817, 0.791637231]
]  # 两列分别代表肿瘤的长和宽 X是大写
raw_data_y = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] # 分为0,1两个类别
#x训练集
X_train=np.array(raw_data_X)
y_train=np.array(raw_data_y)

#看一下原始数据点的分布
plt.figure(1)
plt.scatter(X_train[y_train==0,0],X_train[y_train==0,1],color='red',marker='o',label='y==0')
plt.scatter(X_train[y_train==1,0],X_train[y_train==1,1],color='blue',marker='x',label='y==1')
plt.legend()
plt.show()

X_new = np.array([8.093623049, 3.365732334])#增加一个新的数据
#用散点图直观观察一下新增数据之后新的数据的分布
plt.figure(2)
plt.scatter(X_train[y_train==0,0],X_train[y_train==0,1],color='red',marker='o',label='y==0')
plt.scatter(X_train[y_train==1,0],X_train[y_train==1,1],color='blue',marker='x',label='y==1')
plt.legend()
plt.scatter(X_new[0],X_new[1],marker='+',color='green',s=100)
plt.show()

"""sklearn中的KNN"""

#创建knn类

knn=KNeighborsClassifier()
#训练knn
knn.fit(X_train,y_train)
#将X_new变成两列的
X_new=X_new.reshape(-1,2)
#输出类别
print(knn.predict(X_new))

使用knn对sklearn中的数据进行训练和预测

import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier

#加载 sklearn 中的 datasets 数据中的digits(手写字体数据)

digits=datasets.load_digits()
x=digits.data
y=digits.target

#使用 train_test_split 进行模型建立和测试的分离,加zhiqian是因为没有进行
#归一化处理

X_train_zhiqian,X_test_zhiqian,y_train,y_test=train_test_split(x,y,test_size=0.2)

#使用 StandardScaler进行归一化处理
"""为什么使用X_train_zhiqian进行归一化处理的均值和方差进行对X_test的归一化呢?
是因为要服从现实情况,如果只有一个数据进行预测,就没有办法得出均值和方差
"""

s=StandardScaler()
s.fit(X_train_zhiqian)
X_train=s.transform(X_train_zhiqian)
X_test=s.transform(X_test_zhiqian)

knn_clf=KNeighborsClassifier()
#使用网格搜索的方法进行对超参数的选取
#超参数是指在算法进行时对不确定的参数进行调整以使得算法的预测准确率最高
params=[
{"weights":["uniform"],
 "n_neighbors":[k for k in range(1,11)]
},
{"weights":["distance"],
 "n_neighbors":[k for k in range(1,11)],
 "p":[k for k in range(1,6)]
}
]

#n_jobs 这个参数是使用计算机的几个核,赋值为-1表示全都使用

gridsearch=GridSearchCV(knn_clf,params,n_jobs=-1)
gridsearch.fit(X_train,y_train)
print("best_score",gridsearch.best_score_)
print("best_params",gridsearch.best_params_)

#将最好的赋值给knn_clf
knn_clf=gridsearch.best_estimator_

print(knn_clf.score(X_test,y_test))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

随机的未知

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

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

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

打赏作者

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

抵扣说明:

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

余额充值