最简单的代码_最简单的机器学习算法KNN(附代码手写)

这是最简单的机器学习算法,我找不到其他更简单的了,你只需要知道Python,和numpy的基本操作就能看懂,看不懂你打我。

先说个闲话,疫情期间我回老家过年,没想到一待就是两个多月,刚开始每天还写写代码,后来电脑被我妈抢去看剧,我就快一个多月没怎么写过代码,实现这个KNN我都差点卡壳了,所以说,代码必须常写,多练,才能保持强大。


接下来就是正题了。首先,什么是KNN?

KNN是最简单的一个分类算法(当然也可以进行回归,不过不是主流操作)。考虑到你可能不清楚什么是分类,这里我们引入一个公开的数据集来加以解释。

这个数据集叫iris,中文名是安德森鸢尾花卉数据集,iris包含150个样本,对应数据集的每行数据。每行数据包含每个样本的四个特征和样本的类别信息。

通俗地说,iris数据集是用来给花做分类的数据集,每个样本包含了花萼长度、花萼宽度、花瓣长度、花瓣宽度四个特征。一共有三种不同的鸢尾花——山鸢尾、变色鸢尾和维吉尼亚鸢尾。

对鸢尾花数据集进行分类的任务就是要根据鸢尾花的四个特征——花萼长度、花萼宽度、花瓣长度和花瓣宽度,来判断这个样本属于哪一类鸢尾花。

下面我们查看一下鸢尾花数据集。

导入数据

考虑到sklearn自带了这个数据集,所以我们直接将它导入进来就行了。

from sklearn.datasets import load_iris

载入数据

iris = load_iris()
x = iris.data
y = iris.target

查看数据

x.shape

589f4e171940370cc23bb3c0fc88640f.png
y

26ddb9447c471375a2f04b4591b4855a.png

分割训练集和测试集

#划分数据集为百分之八十的训练集,剩余百分之二十是测试集
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, random_state=666666)

查看数据

X = x_test[0] #这是我们待会输入进去的数据
X

13c61c4ed7c0adde5585ffafc100f05c.png
y_test[0]

4534d2053814bc54d4c155651ff09a18.png

KNN算法过程

现在你大概了解了什么是分类以及我们的数据集长什么样,接下来我们就要手写KNN了。

在手写KNN之前,你需要知道KNN的核心思想——谁离我最近,我就跟谁是一类

其次你需要知道K是什么,K是你人为指定的一个参数,可以根据实际需要调整。KNN其实就是找到前K个离我最近的样本,前K个样本中类别最多的那一类就和我是一类

你可能注意到了,找到前K个离我最近的样本,什么叫最近?实际上距离这个东西有很多定义,常见的有初中就学过的欧氏距离,即空间中两点的距离(这个公式应该都知道吧?)。

当然还有其他的距离算法,比如闵可夫斯基距离,Jaccard相似系数,余弦相似度,pearson相关系数。。。。。。

我们这里就先采用我们熟悉的欧氏距离。

导入我们需要的numpy

import numpy as np

计算距离

distances = []
for x_data in x_train:
    distance = np.sqrt(np.sum(x_data - X)**2) #欧式距离的公式,别说你忘了
    distances.append(distance)

b8905f5c2165d531f8166b223281d03d.png

上图所示,就是我们输入的样本X与所有训练样本的距离(只放了一部分,太长了)。算完了距离后,需要对距离排序。

对距离排序

numpy中提供了非常好的排序算法,帮我们减轻了负担

np.argsort(distances) #以下所显示的是离我们最近的样本的索引

5b346f26218ac3137a718076ae299d21.png

我们先前讲过了,KNN其实就是找到前K个离我最近的样本,前K个样本中类别最多的那一类就和我是一类

K是多少,我们不知道,并没有一个科学的选法,用专业的话讲,K就是超参数,实际中需要调整,也就是调参(你现在知道调参侠是什么了吧,调的就是超参数)。

我们这里假设k是3。

指定超参数K

k = 3
nearest = np.argsort(distances)[:k] #取前k个
top_k_y = [y_train[index] for index in nearest]
top_k_y #说实话我没想到都是2,我事先试过了,试到了40基本上都还是2,看来这个数据集非常适合KNN

e338a8f91fdaddc3014063d7eabde889.png

选出类别数量最多的做为预测结果

这里离样本最近的都是2这个类别的鸢尾花,其实不用看都知道答案了,但是为了算法具有泛化能力我们还是得把具体过程写出来

d = {}
for cls in top_k_y:
    d[cls] = d.get(cls,0) + 1
d_list = list(d.items())
d_list.sort(key=lambda x:x[1],reverse=True)
d_list[0][0] #这就是最终预测结果

2ec60757edccd1c4a4cc527f736104d5.png

至此为止,KNN的过程我们就完整的梳理了一遍

将其完整的封装好就是下面这样,可以好好看看

import numpy as np
class KNNClassifier:
    def __init__(self,k=3):
        self.k = k
        self.x_train = None
        self.y_train = None
        
    def fit(self,x_train,y_train):
        self.x_train = x_train
        self.y_train = y_train
        return self
    
    def predict(self,x_predict):
        y_predict = [self._predict(x) for x in x_predict]
        return np.array(y_predict)
    
    def _predict(self,x):
        distances = [np.sqrt(np.sum((x_train - x)**2)) for x_train in self.x_train]
        nearest = np.argsort(distances)[:self.k]
        top_k_y = [self.y_train[index] for index in nearest]
        d = {}
        for cls in top_k_y:
            d[cls] = d.get(cls,0) + 1
        d_list = list(d.items())
        d_list.sort(key=lambda x:x[1],reverse=True)
        return np.array(d_list[0][0])
    
    def __repr__(self):
        return "KNN(k={})" .format(self.k)
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值