【python机器学习】KNN算法实现分类(基于鸢尾花数据集)

KNN(k-nearest neighbor)算法,即K近邻算法。当需要表示一个样本(值)时,就使用与该样本最接近的K个邻居来决定。KNN既可以用于分类,也可以用于回归。

KNN算法过程:
1.从训练集中选择离待预测样本最近的k个样本
2.根据这k个样本计算待预测样本的值(属于哪个类别或者一个具体的数值)

本文基于鸢尾花 数据集实现
数据集:数据集网盘下载
提取码:p2v9

数据集准备:
import numpy as np
import pandas as pd
#数据集准备 鸢尾花数据集
#读取鸢尾花数据集,header参数来指定标题的行,默认是0,如果没有标题,则使用None
data = pd.read_csv(r"dataset/iris.arff.csv", header=0)
#data.head() #头5行
# data.tail() #末5行
#默认随机抽取一样本 可以指定参数
data.sample(15)

# 删除不必要的id列
#data.drop("id",axis=1,inplace=True)

将特征class(分类名称)映射为数字,方便处理

data["class"] = data["class"].map({"Iris-virginica":0,"Iris-setosa":1,"Iris-versicolor":2}) # 类别名称映射为数字

剔除重复值

# 观察是否有重复值
data.duplicated().any() #结果为true说明,有重复列
# 查看原始数据集记录数目
print(len(data)) #150

# 删除重复记录  inplace=True在原有数据集上操作
data.drop_duplicates(inplace=True)
print(len(data)) #147

150
147

# 查看各个类别的鸢尾花具有多少条记录
data["class"].value_counts()

2 50
0 49
1 48
Name: class, dtype: int64

一点关于ndarray的预备知识
x = np.array([1,2,3])
y = np.array([[4,5,6],
              [3,4,5],
              [7,8,9]])
print(np.sum((x - y)**2,axis=1))
#(x - y)**2


x = np.array([50,20,-18,3])
# 排序后[-18 ,3 ,20 ,50]
print(x.argsort())


x = np.array([50,20,-18,3])
print(x[[0,2]])

#返回每个元素出现的次数
y = np.array([1,2,1,3,4,1,2,1])
print(np.bincount(y))
"""
[0 4 2 1 1]
0 出现了0次
1 出现了4次
...
"""

[ 27 12 108]
[2 3 1 0]
[ 50 -18]
[0 4 2 1 1]

KNN算法实现
class KNN:
    """使用python语言实现k近邻算法。(实现分类)"""
    def __init__(self,k):
        """始化方法
        Parameters
        ------
        k:int 
           邻居的个数。
        """
        self.k = k
        
    def fit(self,X,y):
        """训练方法
        Parameters:
        -------------
        X:类数组类型,形状为:[样本数量,特征数量]
          待训练的样本特征(属性)
        y: 类数组类型,形状为:[样本数量]
           每个样本的目标值(标签)。
        """
        #将X转换成ndarray数组类型。
        self.X = np.asarray(X)
        self.y = np.asarray(y)
        
    def predict(self,X):
        """根据参数传递的样本,对样本数据进行预测
        Parameters
        ----------
        X:类数组类型,形状为:[样本数量,特征数量]
          待训练的样本特征(属性)
          
        Return
        ----------
        result: 数组类型
              预测的结果
        """
        
        X = np.asarray(X)
        result = []
        # 对ndarray数组进行遍历,每次取数组一行(一个样本)。
        # x:当前测试集中的样本  self.X 训练集中的样本
        for x in X:
            # 对于测试集中的每一个样本依次与训练集中所有样本求距离
            dis = np.sqrt(np.sum((x - self.X) **2,axis=1))
            # 返回数组排序后,每个元素在原数组(排序之前的数组)中的索引
            index = dis.argsort()
            # 进行截断,只取前k个元素,【取距离最近k个元素的索引】
            index = index[:self.k]
            # 返回数组中每个元素中出现的次数,元素必须是非负整数
            count = np.bincount(self.y[index])
            # 返回ndarray数组中,值最大的元素对应的索引,该索引就是我们判别的类别
            # 最大元素,就是出现次数最多的元素
            result.append(count.argmax())
        return np.asarray(result)
        
测试与验证

数据集简单处理:

# 提取出每个类别鸢尾花的数据
t0 = data[data["class"] == 0] #49
t1 = data[data["class"] == 1] #48
t2 = data[data["class"] == 2] #50
#对每个类别数据进行洗牌。
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 = KNN(k=3)
# 进行训练
knn.fit(train_X,train_y)
# 进行测试 获得测试结果
result = knn.predict(test_X)
# display(result)                 
# display(test_y)

display(np.sum(result == test_y))
display(np.sum(result == test_y) / len(result))

26
0.9629629629629629

发现27个测试集中有26个判别正确。准确率达到96%

可视化
import matplotlib as mpl
import matplotlib.pyplot as plt
# 默认 matplotlib不支持中文,我们需要进行设置

#设置字体为字体,以支持中文显示
mpl.rcParams["font.family"] = "simHei"
#设置在中文字体时,能正常显示负号(-)
mpl.rcParams["axes.unicode_minus"] = False

# {"Iris-virginica":0,"Iris-setosa":1,"Iris-versicolor":2}
#设置画布大小
plt.figure(figsize=(10,8))
# 绘制训练集数据
plt.scatter(x=t0["sepallength"][:40],y=t0["petallength"][:40],color="r",label="Iris-virginica")
plt.scatter(x=t1["sepallength"][:40],y=t1["petallength"][:40],color="g",label="Iris-setosa")
plt.scatter(x=t2["sepallength"][:40],y=t2["petallength"][:40],color="b",label="Iris-versicolor")
# 绘制测试集数据
right = test_X[result == test_y] #预测正确的
wrong = test_X[result != test_y] #预测错误的
plt.scatter(x=right["sepallength"],y=right["petallength"],color="c",marker="x",label="right")
plt.scatter(x=wrong["sepallength"],y=wrong["petallength"],color="m",marker=">",label="wrong")
plt.xlabel("花萼长度")
plt.ylabel("花瓣长度")
plt.title("KNN分类结果显示")
plt.legend(loc="best")
plt.show()
最后效果

在这里插入图片描述

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值