KNN-k近邻算法

KNN-k近邻算法

k近邻算法基础

解决分类问题

问题引入:
假设我们给出肿瘤大小作为横轴,发现肿瘤时间作为纵轴的坐标图。
其中红色代表为良性肿瘤,蓝色表示为恶性肿瘤:

KNN-k近邻算法
现在,我们想根据新给出的一个肿瘤大小和发现时间的数据,来预测肿瘤是阳性还是阴性(图中绿色的点):
KNN-k近邻算法

在这个问题中,我们需要通过已有的8个数据(红,蓝点的分布情况)来判断新给出的数据(绿点)是良性还是恶性肿瘤

想要用KNN解决分类问题也十分简单:

取绿色点周围最近的k(取值自选)个点,颜色相同数最多点的颜色即为最终结果

也就是说,k近邻的判断依据就是:两个样本如果足够相似,它们就有更高的几率属于同一个类别

; 在Notebook中实现

数据的准备

  • 先创建样本数据数组 raw_data, raw_data_y
    KNN-k近邻算法
  • 再将数据集转换为numpy中的array数组
    KNN-k近邻算法
  • 将样本数据集与待预测数据绘制散点图
    KNN-k近邻算法

; KNN过程

  • 先计算所有样本数据点到待预测数据点的距离distances(向量)
    其中,计算两点间的距离我们使用欧拉距离来计算:
    KNN-k近邻算法
    KNN-k近邻算法
  • 再找出distances中距离中前k个最小的距离点的索引(这里将k=6)
    KNN-k近邻算法
  • 然后通过Counter投票找出前k个中最多的结果,就是我们的分类结果
    KNN-k近邻算法

通过函数封装来实现

代码:

import numpy as np
from math import sqrt
from collections import Counter

def kNN_classify(k, X_train, y_train, x):
    assert 1  k  X_train.shape[0], "k must be valid"
    assert X_train.shape[0] == y_train.shape[0], \
        "the size of X_train must equal to the size of y_train"
    assert X_train.shape[1] == x.shape[0], \
        "the feature number of x must be equal to X_train"

    distances = [sqrt(np.sum((x_train-x)**2)) for x_train in X_train]
    nearest = np.argsort(distances)

    topK_y = [y_train[i] for i in nearest[:k]]
    votes = Counter(topK_y)

    return votes.most_common(1)[0][0]

再通过Notebook中的魔法命令就可以直接使用了

KNN-k近邻算法

scikit-learn 中的机器学习封装

设计机器学习的大致思想:

KNN-k近邻算法
其中,对于KNN算法来说,喂入的训练集就是模型

; 使用scikit-learn中的KNN

引入sklearn包后首先需要传入设定的k值

KNN-k近邻算法
再传入样本数据集进行拟合
KNN-k近邻算法
进行预测前必须将需要预测的数据转化为矩阵形式传入,否则会报错
KNN-k近邻算法

使用自己封装好的kNN

代码如下:

import numpy as np
from math import sqrt
from collections import Counter

class KNNClassifier:
    def __init__(self, k):
        assert k >= 1, "k must be valid"
        self.k = k
        self._X_train = None
        self._y_train = None

    def fit(self, X_train, y_train):
        assert X_train.shape[0] == y_train.shape[0], \
            "the size of X_train must be equal to the size of y_train"
        assert self.k  X_train.shape[0], \
            "the size of X_train must be at least k."

        self._X_train = X_train
        self._y_train = y_train
        return self

    def predict(self, X_predict):
        assert self._X_train is not None and self._y_train is not None, \
            "must fit before predict!"
        assert X_predict.shape[1] == self._X_train.shape[1], \
            "the feature number of X_predict must be equal to X_train"

        y_predict = [self._predict(x) for x in X_predict]
        return np.array(y_predict)

    def _predict(self, x):
        assert x.shape[0] == self._X_train.shape[1], \
            "the feature number of x must be equal to X_train"

        distances = [sqrt(np.sum((x_train-x) ** 2)) for x_train in self._X_train]

        nearest = np.argsort(distances)

        topK_y = [self._y_train[i] for i in nearest[:self.k]]
        votes = Counter(topK_y)

        return votes.most_common(1)[0][0]

    def __repr__(self):
        return "kNN(k=%d)" % self.k

同样地,我们再使用魔法命令运行我们自己写的kNN

KNN-k近邻算法
即可成功运行

训练、测试数据集

在实际问题中,除了设计出机器学习模型,我们还要去测试这种学习模型的准确率。
那么有什么方法能够判断出机器训练出的模型的准确率有多少呢?
我们可以从给出的训练数据集中抽出一部分,作为测试数据

KNN-k近邻算法
根据这样的思想,我们可以测试一下我们自己刚刚编写的kNN的准确率

; 测试算法的准确率

这里我们使用sklearn中的鸢尾花数据集

首先加载鸢尾花数据集,将x,y特征值分别存入X,Y中

KNN-k近邻算法

KNN-k近邻算法

这里我们可以看到,Y的数据是很规律的,我们如果只选取前n个数据,得到的结果误差一定相当大。所以,我们需要先把数据打乱,再进行训练数据和测试数据的划分

打乱数据的索引

KNN-k近邻算法
计算测试数据集的容量(这里定为总样本的20%)
KNN-k近邻算法
将训练与测试数据集索引分离
KNN-k近邻算法
根据分离好的索引,分别求出x,y
KNN-k近邻算法

编写我们自己的分离数据函数

代码如下:

import numpy as np

def train_test_split(X, y, test_ratio=0.2, seed=None):
    assert X.shape[0] == y.shape[0], \
        "the size of X must be equal to the size of y"
    assert 0.0  test_ratio  1.0, \
        "test_train must be valid"

    if seed:
        np.random.seed(seed)

    shuffled_indexes = np.random.permutation(len(X))

    test_size = int(len(X) * test_ratio)
    test_indexes = shuffled_indexes[:test_size]
    train_indexes = shuffled_indexes[test_size:]

    X_train = X[train_indexes]
    y_train = y[train_indexes]

    X_test = X[test_indexes]
    y_test = y[test_indexes]

    return X_train, X_test, y_train, y_test

测试一下编写的代码:

KNN-k近邻算法
同样可以根据这种原理,算出我们编写程序的准确率:
KNN-k近邻算法

使用sklearn中封装好的测试模型

KNN-k近邻算法

; 分类准确度

我们通过sklearn库中的手写数据库中的数据来验证一下算法的准确度

首先,我们引入sklearn的手写数据集

KNN-k近邻算法
先用x,y分别接收一下数据
KNN-k近邻算法
我们可以取出一部分数据查看一下
KNN-k近邻算法
KNN-k近邻算法
我们随意取出一个位置(索引为666)的数据进行绘图查看一下
KNN-k近邻算法

这里可以看到是手写数字0

接下来,计算我们训练好的模型的准确率就很简单了。
先将我们通过模型预测的结果集设为y_train,测试集对应结果命名为y_test。计算y_train == y_test 的个数,该个数与y_test总个数的比值就是我们要求的精确度比值了

代码如下:

import numpy as np

def accuracy_score(y_true, y_predict):

    assert y_true.shape[0] == y_predict.shape[0], \
        "the size of y_true must be equal to the size of y_predict"

    return sum(y_true == y_predict) / len(y_true)

我们在Notebook上运行一下

KNN-k近邻算法

这样,我们就计算出了我们预测的准确值

sklearn中的accuracy_score

sklearn库中的使用方法基本和我们自己实现的方法相似

KNN-k近邻算法

; 超参数

超参数:在算法运行前需要决定的参数
模型参数:算法过程中学习的参数

其中,kNN算法没有模型参数,kNN算法中的k就是典型的超参数

我们想要寻找好的超参数,主要就由三个方面的因素决定:领域知识,经验知识和实验搜索。

接下来,我们使用模型搜索的方法来测试寻找较好的超参数

寻找好的k

这里,我们依旧选用手写数字数据集进行实验

首先,在sklearn库中载入手写数字数据,并做好准备工作

KNN-k近邻算法
然后我们使用for循环,逐个在【1,10】中寻找效果最好的k就行了
KNN-k近邻算法
这样,我们就找到了针对我们的模型的最好的k

注意:如果我们搜索出的k结果是10,也就是属于范围边缘,我们就需要扩大搜索范围,比如将范围扩大至【1,20】来搜索

; 考虑到距离因素

分类时,除了考虑按照最近距离的个数分类,有时我们还需要将距离也算进考虑范畴当中

KNN-k近邻算法

比如此图中,我们就可以把预测点与红点划为一类,因为红色点最近,即占的比重最大

想要实现,我们只需要将函数中的参数更改一下即可

KNN-k近邻算法
同样地,我们还可以更改参数p
KNN-k近邻算法

网格搜索

网格搜索的原理很简单,就是将要想要查询的信息存放为字典,多个字典用列表存储再通过GridSearchCV测试就可以了

具体实现方法:

KNN-k近邻算法
初始化的时候传入kNeighborsClassifier和param_grid
KNN-k近邻算法
我们再用训练集来拟合一下
KNN-k近邻算法

然后我们就可以查看最好的拟合效果,等结果

KNN-k近邻算法
再将knn_clf运用我们刚刚得到的最佳效果训练参数,就可以达到最好的训练效果
KNN-k近邻算法
GridSearchCV中还可以传入不同的参数(n_jobs控制运行的核的个数,verbose决定是否显示运行过程中的结果)
KNN-k近邻算法

; 数据归一化

解决实际问题时,如果不统一一个度量标准,得到的结果差距会十分大。
比如我们举出肿瘤大小与发现天数之间的关系,如果我们对肿瘤发现的时间用不同的单位来统计:

KNN-k近邻算法
KNN-k近邻算法
这样我们再套入到kNN算法中,计算出的结果会有很大的差距。前者的发现时间占主导而后者是肿瘤大小占主导。

那么有什么方法能够让我们统一不同的量度呢?

接下来我们引入两个不同的计算方法

最值归一化 Normalization

原理:将所有数据都映射到同一尺度
结果:把所有数据映射到0和1之间

计算公式:

KNN-k近邻算法

; Notebook实现

首先引入我们需要使用的模块

KNN-k近邻算法
我们先随机生成一个二维向量
KNN-k近邻算法
由于numpy默认生成的是int类型,精度还不够,我们需要强行转换为float类型
KNN-k近邻算法
套入上述公式进行计算(维度多的化可以用for循环来写)
KNN-k近邻算法
计算结果
KNN-k近邻算法
绘图查看一下结果
KNN-k近邻算法

该方法适用于以下情况:分布有明显边界

均值方差归一化 Standardization

原理:将所有数据都映射到同一尺度
结果:把所有数据映射到均值0方差为1的分布中
公式:(S表示方差)

KNN-k近邻算法

; Notebook实现

同样的,我们先随机生成一个二维随机数据集

KNN-k近邻算法
套入公式
KNN-k近邻算法
绘图查看一下
KNN-k近邻算法

上述方法适用于以下情况:
1)分布没有明显的边界
2)有可能存在极端数据值

scikit-learn中的Scaler

KNN-k近邻算法

Notebook实现

先加载鸢尾花的数据并保存到X,y中

KNN-k近邻算法
进行测试集和训练集的分离
KNN-k近邻算法
从库中加载进StandardScaler
KNN-k近邻算法
输入X_train进行拟合
KNN-k近邻算法
将归一好的X_train进行替换
KNN-k近邻算法
替换好的结果
KNN-k近邻算法
同样地,X_test也要进行归一
KNN-k近邻算法
再通过KNN看一下精确度
KNN-k近邻算法

Original: https://blog.csdn.net/qq_53421929/article/details/122473803
Author: 柴可拉夫斯基
Title: KNN-k近邻算法

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/664657/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球