动手实现knn算法

数据挖掘算法原理与实践:k-近邻 动手实现knn算法 201226

educoder 答案

任务描述

本关任务:使用python实现knn算法,并对手写数字进行识别。

相关知识

为了完成本关任务,你需要掌握:1.加权投票,2.knn算法流程。

数据集介绍

手写数字数据集一共有1797个样本,每个样本有64个特征。每个特征的值为0-255之间的像素,我们的任务就是根据这64个特征值识别出该数字属于0-9十个类别中的哪一个。

我们可以使用sklearn直接对数据进行加载,代码如下:

from sklearn.datasets import load_digits
#加载手写数字数据集
digits = load_digits()
#获取数据特征与标签
x,y = digits .data,digits .target 

当然,每一个样本就是一个数字,我们可以把它还原为8x8的大小进行查看:

import matplotlib.pyplot as plt
img = x[0].reshape(8,8)
plt.imshow(img)

photo

然后我们划分出训练集与测试集,训练集用来训练模型,测试集用来检测模型性能。代码如下:

from sklearn.model_selection import train_test_split
#划分训练集测试集,其中测试集样本数为整个数据集的20%
train_feature,test_feature,train_label,test_label = train_test_split(x,y,test_size=0.2,random_state=666)

加权投票

通过上一关,我们已经知道如何找出最近的k个样本,但是,现在还有一个问题要我们来解决:如果有两个类型的样本数一样且最多,那么最终该样本应该属于哪个类型?
其实,knn算法最后决定样本属于哪个类别,其实好比就是在投票,哪个类别票数多,则该样本属于哪个类别。而如果出现票数相同的情况,我们可以给每一票加上一个权重,用来表示每一票的重要性,这样就可以解决票数相同的问题了。很明显,距离越近的样本所投的一票应该越重要,此时我们可以将距离的倒数作为权重赋予每一票。
phote2
如上图,虽然蓝色正方形与红色三角形数量一样,但是根据加权投票的规则,绿色的圆应该属于蓝色正方形这个类别。

knn算法流程

knn算法不需要训练模型,只是根据离样本最近的几个样本类型来判别该样本类型,所以流程非常简单:

计算出新样本与每一个样本的距离
找出距离最近的k个样本
根据加权投票规则得到新样本的类别

编程要求

根据提示,在右侧编辑器Begin-End处补充代码,实现knn算法。

测试说明

正确率大于0.95则视为通关。

通关代码

# encoding=utf8
import numpy as np


def topK(i, k, sam, x, y):
    '''
    input:
        i(int):第i个样本
        k(int):最近邻样本个数
        x(ndarray):数据特征
        y(ndarray):数据标签
    output:
        topK(list):样本i的最近k个样本标签
    '''
    # 计算样本到所有样本的距离
    dis = []
    for s in range(len(x)):
        tmp = sam - x[s]
        S = 0
        for t in tmp:
            S += abs(t)
        dis.append([S, s])

    # 除样本本身外的最近的k个样本的索引
    dis = sorted(dis, key=lambda x: x[0])
    # 除样本本身外的最近的k个样本的标签
    for a in range(k):
        dis[a].append(y[dis[a][1]])
    '''
        output:
        dis中每一项是个三元组,具体为:(样本的距离,样本的索引,样本的标签)
    '''
    return dis[:k]


def knn_clf(k, train_feature, train_label, test_feature):
    '''
    input:
        k(int):最近邻样本个数
        train_feature(ndarray):训练样本特征
        train_label(ndarray):训练样本标签
        test_feature(ndarray):测试样本特征
    output:
        predict(ndarray):测试样本预测标签
    '''
    predict = []
    # 对测试集每一个样本进行遍历
    for ti in range(len(test_feature)):
        # 测试集第i个样本到训练集每一个样本的距离
        distancee = topK(ti, k, test_feature[ti], train_feature, train_label)
        # 初始化进行投票的字典,字典的键为标签,值为投票分数
        dictionary = {}
        for d in distancee:
            # 进行投票
            if d[2] not in dictionary:
                # 如果标签不在字典中则将标签加入字典的键,同时计入相应的分数
                dictionary[d[2]] = 1.0 / d[0]
            else:
                # 如果标签在字典的键中则投票计分
                dictionary[d[2]] += 1.0 / d[0]
        # 计入投票评分最高的类别最为预测结果
        predict.append(sorted(list(dictionary.items()), key=lambda x: x[1], reverse=True)[0][0])
    return predict
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值