原生python实现knn分类算法

一、 题目

原生python实现knn分类算法

二、 算法设计

k 近邻(k-Nearset Neighbor,简称 kNN)学习是一种常用的监督学习方法,其工作机制非常简单:给定测试样本,基于某种距离度量找出训练集中与其最靠近的 k 个训练样本,然后基于这 k 个“邻居”的信息来进行观测。通常,在 分类任务 中可使用“投票法”,即将这 k 个样本点中出现最多的类别标记作为预测结果;在 回归任务 中可使用“平均法”,将这 k 个样本的实值输出标记的平均值作为预测结果;还可以基于距离远近进行加权平均或加权投票,距离越近的样本权重越大。

程序流图:
在这里插入图片描述

Knn 算法:

将每个样本视作一个点

  1. 载入数据集,对数据进行必要的预处理

  2. 设置参数K,K最好选择奇数,因为后续进行归类的策略是少数服从多数,设置K为奇数的话总会有结果。

  3. 计算待预测点与已知点之间的关系,这里的关系可以有多种方式来体现,常用如下:
    ①欧式距离(应用较广,其他及其算法也有广泛应用),其计算方法:
    在这里插入图片描述
    ②曼哈顿距离
    在这里插入图片描述
    ③……

  4. 之前确定了参数K,计算了待预测点与已知点之间的距离衡量,将计算的结果进行从小到大排序,取前K个点

  5. 将待预测点归类为多数的那一个类别,这便是对于未知点的类别预测结果了。

三、源代码

import numpy as np

import pandas as pd

# 读取数据集,header参数来指定参数标题的行,默认为0,第一行,如果没有标题使用None

data = pd.read_csv('iris.csv', header=0)

# 对文本进行处理,将Species列的文本映射成数值类型

data['Species'] = data['Species'].map({'virginica': 0, 'setosa': 1, 'versicolor': 2})
data.sample(10)

# 删除不需要的列

data.drop("id", axis=1, inplace=True)

# 重复值检查,any(),一旦有重复值,就返回True

data.duplicated().any()

# 删除重复的数据

data.drop_duplicates(inplace=True)

# 查看各类别的数据条数

data['Species'].value_counts()

#显示读取的数据
print(data)


# 编写KNN类

class KNN:

    def __init__(self, k):

        """

        k:int

            邻居的个数

        """

        self.k = k

    def fit(self, X, y):

        """

            X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]

            y:类似数组类型,形状为[样本数量]

                每个样本的目标值,也是就是标签

        """

        # 将X转换成ndarray类型,如果X已经是ndarray则不进行转换

        self.X = np.asarray(X)

        self.y = np.asarray(y)

    def predict(self, X):

        """根据参数传递的样本,对样本数据进行预测,返回预测之后的结果

        ----

        X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]

        Return

        ----

        result:数类型,预测的结果。

        """

        # 将测试的X转换为ndarray结构

        X = np.asarray(X)

        result = []

        for x in X:
            # ndarray相减为对应元素相减,测试的X的每一行与self.X 相减

            # 求欧氏距离:每个元素都取平方值

            dis = np.sqrt(np.sum((x - self.X) ** 2, axis=1))

            # 求最近的k个点的距离,sort()排序不适用,因为排序后打乱了顺序

            # argsort(),返回每个元素在排序之前原数组的索引

            index = dis.argsort()

            # 取前k个元素,距离最近的k的元素

            index = index[:self.k]

            # 返回数组中每个元素出现的次数,元素必须是非负整数

            count = np.bincount(self.y[index])

            # 返回ndarray之最大的元素的索引,该索引就是我们判定的类别

            result.append(count.argmax())

        return np.asarray(result)

    def predict2(self, X):

        """根据参数传递的样本,对样本数据进行预测(考虑权重,使用距离的倒数作为权重),返回预测之后的结果



        Parameters

        ----

        X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]



        Return

        ----

        result:数类型,预测的结果。

        """

        # 将测试的X转换为ndarray结构

        X = np.asarray(X)

        result = []

        for x in X:
            # ndarray相减为对应元素相减,测试的X的每一行与self.X 相减

            # 求欧氏距离:每个元素都取平方值

            dis = np.sqrt(np.sum((x - self.X) ** 2, axis=1))

            # 求最近的k个点的距离,sort()排序不适用,因为排序后打乱了顺序

            # argsort(),返回每个元素在排序之前原数组的索引

            index = dis.argsort()

            # 取前k个元素,距离最近的k的元素

            index = index[:self.k]

            # 返回数组中每个元素出现的次数,元素必须是非负整数,【使用weight考虑权重,权重为距离的倒数】

            count = np.bincount(self.y[index], weights=1 / dis[index])

            # 返回ndarray之最大的元素的索引,该索引就是我们判定的类别

            result.append(count.argmax())

        return np.asarray(result)
#数据集拆分成训练集和测试集

#1、提取每个类别鸢尾花的数量

t0 = data[data['Species']==0]

t1 = data[data['Species']==1]

t2 = data[data['Species']==2]



#打乱顺序,random_state ,记住打乱的顺序

t0 = t0.sample(len(t0),random_state=0)

t1 = t1.sample(len(t1),random_state=0)

t2 = t2.sample(len(t2),random_state=0)

train_X = pd.concat([t0.iloc[:40,:-1],t1.iloc[:40,:-1],t2.iloc[:40,:-1]],axis=0)

train_Y = pd.concat([t0.iloc[:40,-1],t1.iloc[:40,-1],t2.iloc[:40,-1]],axis=0)

test_X = pd.concat([t0.iloc[40:,:-1],t1.iloc[40:,:-1],t2.iloc[40:,:-1]],axis=0)

test_Y = pd.concat([t0.iloc[40:,-1],t1.iloc[40:,-1],t2.iloc[40:,-1]],axis=0)



#进行训练与测试

knn = KNN(k=3)

#进行训练

knn.fit(train_X,train_Y)

#进行测试

result = knn.predict(test_X)

# display(result)

# display(test_Y)

#查看预测结果

print(np.mean(result == test_Y))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值