IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 【scikit-learn】K近邻(KNN) -> 正文阅读

[人工智能]【scikit-learn】K近邻(KNN)

KNN

KNN(K-Nearest Neighbor)是最简单的机器学习算法之一,可以用于分类和回归,是一种监督学习算法。它的思路是这样,如果一个样本在特征空间中的K个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。也就是说,该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。

KNN用于分类

  1. 计算待分类点与已知类别的点之间的距离
  2. 按照距离递增次序排序
  3. 选取与待分类点距离最小的K个点
  4. 确定前K个点所在类别的出现次数
  5. 返回前K个点出现次数最高的类别作为待分类点的预测分类

KNN回归预测

回归中,一般采用平均值法或者加权平均值法

平均值法: 每个邻近样本的权重是一样的,最终预测的结果为所有邻近样本目标属性值的均值
加权平均值法:一般采用权重和距离成反比的方式计算

KNN算法要注意的问题

无论是分类还是回归,KNN算法的几个关键点:

  • 算法超参数K
  • 距离度量,特征空间中样本点的距离是样本点间相似程度的反映
  • 分类决策规则,少数服从多数。

算法超参数K

如果选择较小的K值,就相当于用较小的邻域中的训练实例进行预测,“学习”的近似误差会减小,只有输入实例较近的训练实例才会对预测结果起作用。但缺点是“学习”的估计误差会增大,预测结果会对近邻实例点非常敏感。如果邻近的实例点恰巧是噪声,预测就会出错。换句话说,K值得减小就意味着整体模型非常复杂,容易发生过拟合。
如果选择较大的K值,就相当于用较大邻域中的训练实例进行预测,其实优点是减少学习的估计误差,但缺点是学习的近似误差会增大。这时与输入实例较远的训练实例也会起预测作用,使预测发生错误,k值的增大就意味着整体的模型变得简单,容易发生欠拟合。可以假定极端条件K=N,那么无论输入实例是什么,都将简单的预测它属于训练实例中最多的类。这时,模型过于简单,完全忽略训练中的大量有用信息,是不可取的。
在应用中,通常采用交叉验证法来选择最优K值。从上面的分析也可以知道,一般K值取得比较小。我们会选取K值在较小的范围,同时在验证集上准确率最高的那一个确定为最终的算法超参数K。

距离度量

常用的距离有三种,分别为曼哈顿距离、欧式距离和闵可夫斯基距离

KNN的优缺点

优点:
1)算法简单,理论成熟,既可以用来做分类也可以用来做回归。
2)可用于非线性分类。
3)没有明显的训练过程,而是在程序开始运行时,把数据集加载到内存后,不需要进行训练,直接进行预测,所以训练时间复杂度为0。
4)由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属的类别,因此对于类域的交叉或重叠较多的待分类样本集来说,KNN方法较其他方法更为适合。
5)该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量比较小的类域采用这种算法比较容易产生误分类情况。

缺点:
1)需要算每个测试点与训练集的距离,当训练集较大时,计算量相当大,时间复杂度高,特别是特征数量比较大的时候。
2)需要大量的内存,空间复杂度高。
3)样本不平衡问题(即有些类别的样本数量很多,而其它样本的数量很少),对稀有类别的预测准确度低。
4)是lazy learning方法,基本上不学习,导致预测时速度比起逻辑回归之类的算法慢。

实战


'''
数据集:Mnist
训练集数量:60000
测试集数量:10000(实际使用:10)可更改
'''

import time
import numpy as np
import sys
import os

# 导入处于不同目录下的Mnist.load_data
parent_path=os.path.dirname(os.path.dirname(sys.argv[0])) # 获取上级目录
sys.path.append(parent_path) # 修改sys.path
from torchvision.datasets.mnist import MNIST


from torch.utils.data import DataLoader
from torchvision import datasets
import torchvision
import torchvision.transforms as transforms




class KNN:
    def __init__(self, x_train, y_train, x_test, y_test, k):
        '''
        Args:
            x_train [Array]: 训练集数据
            y_train [Array]: 训练集标签
            x_test [Array]: 测试集数据
            y_test [Array]: 测试集标签
            k [int]: k of kNN
        '''
        self.x_train, self.y_train = x_train, y_train
        self.x_test, self.y_test = x_test, y_test
        # 将输入数据转为矩阵形式,方便运算
        self.x_train_mat, self.x_test_mat = np.mat(
            self.x_train), np.mat(self.x_test)
        self.y_train_mat, self.y_test_mat = np.mat(
            self.y_test).T, np.mat(self.y_test).T
        self.k = k

    def _calc_dist(self, x1, x2):
        '''计算两个样本点向量之间的距离,使用的是欧氏距离
        :param x1:向量1
        :param x2:向量2
        :return: 向量之间的欧式距离
        '''
        return np.sqrt(np.sum(np.square(x1 - x2)))

    def _get_k_nearest(self,x):
        '''
        预测样本x的标记。
        获取方式通过找到与样本x最近的topK个点,并查看它们的标签。
        查找里面占某类标签最多的那类标签
        :param trainDataMat:训练集数据集
        :param trainLabelMat:训练集标签集
        :param x:待预测的样本x
        :param topK:选择参考最邻近样本的数目(样本数目的选择关系到正确率,详看3.2.3 K值的选择)
        :return:预测的标记
        '''
        # 初始化距离列表,dist_list[i]表示待预测样本x与训练集中第i个样本的距离
        dist_list=[0]* len(self.x_train_mat)

        # 遍历训练集中所有的样本点,计算与x的距离
        for i in range( len(self.x_train_mat)):
            # 获取训练集中当前样本的向量
            x0 = self.x_train_mat[i]
            # 计算向量x与训练集样本x0的距离
            dist_list[i] = self._calc_dist(x0, x)

        # 对距离列表排序并返回距离最近的k个训练样本的下标
        # ----------------优化点-------------------
        # 由于我们只取topK小的元素索引值,所以其实不需要对整个列表进行排序,而argsort是对整个
        # 列表进行排序的,存在时间上的浪费。字典有现成的方法可以只排序top大或top小,可以自行查阅
        # 对代码进行稍稍修改即可
        # 这里没有对其进行优化主要原因是KNN的时间耗费大头在计算向量与向量之间的距离上,由于向量高维
        # 所以计算时间需要很长,所以如果要提升时间,在这里优化的意义不大。
        k_nearest_index = np.argsort(np.array(dist_list))[:self.k]  # 升序排序
        return k_nearest_index


    def _predict_y(self,k_nearest_index):
        # label_list[1]=3,表示label为1的样本数有3个,由于此处label为0-9,可以初始化长度为10的label_list
        label_list=[0] * 10
        for index in k_nearest_index:
            one_hot_label=self.y_train[index]
            number_label=np.argmax(one_hot_label)
            label_list[number_label] += 1
        # 采用投票法,即样本数最多的label就是预测的label
        y_predict=label_list.index(max(label_list))
        return y_predict

    def test(self,n_test=10):
        '''
        测试正确率
        :param: n_test: 待测试的样本数
        :return: 正确率
        '''
        print('start test')

        # 错误值计数
        error_count = 0
        # 遍历测试集,对每个测试集样本进行测试
        # 由于计算向量与向量之间的时间耗费太大,测试集有6000个样本,所以这里人为改成了
        # 测试200个样本点,若要全跑,更改n_test即可
        for i in range(n_test):
            # print('test %d:%d'%(i, len(trainDataArr)))
            print('test %d:%d' % (i, n_test))
            # 读取测试集当前测试样本的向量
            x = self.x_test_mat[i]
            # 获取距离最近的训练样本序号
            k_nearest_index=self._get_k_nearest(x)
            # 预测输出y
            y=self._predict_y(k_nearest_index)
            # 如果预测label与实际label不符,错误值计数加1
            if y != np.argmax(self.y_test[i]):
                error_count += 1
            print("accuracy=",1 - (error_count /(i+1)))

        # 返回正确率
        return 1 - (error_count / n_test)


if __name__ == "__main__":

    k=1
    start = time.time()

    train_dataset = datasets.MNIST(root = '../datasets', train = True,transform = transforms.ToTensor(), download = True)
    test_dataset = datasets.MNIST(root = '../datasets', train = False, transform = transforms.ToTensor(), download = True)

    # batch_size = len(train_dataset)
    train_loader = DataLoader(dataset=train_dataset, batch_size=60000, shuffle=True)
    test_loader = DataLoader(dataset=test_dataset, batch_size=1000, shuffle=True)
    x_train,y_train = next(iter(train_loader))
    x_test,y_test = next(iter(test_loader))
    x_train = x_train.squeeze(1).view(60000,-1)
    x_test = x_test.squeeze(1).view(1000,-1)


    model=KNN( x_train, y_train, x_test, y_test,k)
    accur=model.test()
    end = time.time()
    print("total acc:",accur)
    print('time span:', end - start)
start test
test 0:10
accuracy= 1.0
test 1:10
accuracy= 1.0
test 2:10
accuracy= 1.0
test 3:10
accuracy= 1.0
test 4:10
accuracy= 1.0
test 5:10
accuracy= 1.0
test 6:10
accuracy= 1.0
test 7:10
accuracy= 1.0
test 8:10
accuracy= 1.0
test 9:10
accuracy= 1.0
total acc: 1.0
time span: 17.0129714012146

使用sklearn

  1. 将数据集分割成测试数据集和训练数据集
from sklearn.model_selection import train_test_split

X_train,X_test,y_train,y_test =train_test_split(X,y)
  1. 创建一个KNeighborsClassifier 对象
from sklearn.neighbors import KNeighborsClassifier

knn= KNeighborsClassifier()
  1. 使用KNeighborsClassifier 对象进行fit创建出模型,得出分类准确度
knn.fit(X_train,y_train)
knn.score(X_test,y_test)
  1. 使用模型预测测试集
y_predict = knn.predict(X_test)

KNN的初始函数(构造函数)的参数和默认参数是(n_neighbors=5,weights=’uniform’, algorithm=’auto’, leaf_size=30, p=2, metric=’minkowski’,metric_params=None, n_jobs=1, **kwargs)

[n_neighbors] 也就是K,默认参数为5。

[weights] str参数,为了降低k值的影响所设置的权重值,即每个拥有投票权的样本是按什么比重投票,'uniform'表示等比重投票,'distance'表示按距离 反比投票,[callable]表示自己定义的一个函数,这个函数接收一个距离数组,返回一个权值数组。默认参数为‘uniform’。

[algorithm] str参数,即内部采用什么数据结构实现。有以下几种选择参:'ball_tree':球树、'kd_tree':kd树、'brute':暴力搜索、'auto':自动根据数据的类型和结构选择合适的算法。默认情况下是‘auto’。暴力搜索就不用说了大家都知道。具体前两种树型数据结构哪种好视情况而定。KD树是依次对K维坐标轴,以中值切分构造的树,每一个节点是一个超矩形,在维数小于20时效率最高。ball tree 是为了克服KD树高维失效而发明的,其构造过程是以质心C和半径r分割样本空间,每一个节点是一个超球体。一般低维数据用kd_tree速度快,用ball_tree相对较慢。超过20维之后的高维数据用kd_tree效果反而不佳,而ball_tree效果要好,具体构造过程及优劣势的理论大家有兴趣可以去具体学习。

[leaf_size] int参数,基于以上介绍的算法,此参数给出了kd_tree或者ball_tree叶节点规模,叶节点的不同规模会影响数的构造和搜索速度,同样会影响用于储存树的内存的大小。具体最优规模是多少视情况而定。

[matric] str或者距离度量对象,即怎样度量距离,前面有具体介绍。默认minkowski。

[p] int参数,就是以上闵氏距离各种不同的距离参数,默认为2,即欧氏距离。p=1代表曼哈顿距离等等。

[metric_params] 距离度量函数的额外关键字参数,一般不用管,默认为None。

[n_jobs] int参数,指并行计算的线程数量,默认为1表示一个线程,为-1的话表示为CPU的内核数,也可以指定为其他数量的线程,这里不是很追求速度的话不用管,需要用到的话去看看多线程。
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-12-28 22:55:34  更:2021-12-28 22:57:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 23:29:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码