机器学习(二)KNN分类

基于KNN 算法,实现对于鸢尾花分类

数据集的准备和处理

  • 数据集介绍

Iris数据集每个样本x包含了花萼长度(sepal length)、花萼宽度(sepal width)、花瓣长度(petal length)、花瓣宽度(petal width)四个特征。样本标签y共有三类,分别是Setosa,Versicolor和Virginica。Iris数据集总共包含150个样本,每个类别由50个样本,整体构成一个150行5列的二维表。
avator

  • 数据集的处理

1.导入 numpy库 和 pandas库提取数据

import numpy as np
import pandas as pd
data = pd.read_csv(r"iris.arff.csv", header=0)

2.对数据集进行处理使得便于进行分析

# 将鸢尾花种类名称映射为数字
data["class"] = data["class"].map({"Iris-versicolor":0,"Iris-setosa":1,"Iris-virginica":2}) 
# data = data.drop("Id",axis=1,inplace = True)  # 删除列
print(len(data))
if data.duplicated().any(): # 重复值
    data.drop_duplicates(inplace=True) #删除重复值
    print(len(data))
data["class"].value_counts()  # 查看各个类别的鸢尾花记录
150
147
0    50
2    49
1    48
Name: class, dtype: int64

KNN分类算法的实现

原理:

1.将Iris数据集分为两部分,构建训练集和测试集。其中后四十条数据设置为测试集,来进行数据的测试和验证。

提取方法:把每个类中的鸢尾花的数据进行洗牌
后按照相同比例放入建训练集和测试集

2.求测试集合的每一个数据到训练集的数据中的欧氏距离,选取距离最近的前k个元素,并取k个元素中对应的类别数组中出现次数最多的类别为判断类别

代码实现:

class KNN:
    '''使用python语言实现k邻近算法(实现分类)'''
    def __init__(self, k):
        '''初始化方法
        Parameters
        -----
        k:int
            邻居个位数
        '''
        self.k = k
        
    def fit(self, X, y):
        '''训练方法
        
        Parameeters
        -----
        X: 类数组类型(特征矩阵),可以是List也可以是Ndarray,形状为: [样本数量,特征数量]
           待训练的样本特征(属性)
        y: 类数组类型,形状为:[样本数量]
           每个样本的目标值(标签)
        
        '''
        #将X,y转换为ndarray类型
        self.X = np.asarray(X) 
        self.y = np.asarray(y)
    def predict(self, X):
        '''根据参数传递的样本,对样本数据进行预测
        
        Parameters:
        -----
        X: 类数组类型,可以是List也可以是Ndarray,形状为: [样本数量,特征数量]
        待测试的样本特征(属性)
        Returns:
        -----
        result :
        数组类型,预测结果
        
        '''
        #转换为数组类型
        X = np.asarray(X)
        #保存预测的结果值
        result = []
        #对ndarray数组进行遍历,每次取数组中的一行
        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)

训练与测试

  • 数据集的分类(原理1)
#提取出每个类中的鸢尾花的数据
t0 = data[data["class"]==0]
t1 = data[data["class"]==1]
t2 = data[data["class"]==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)
#构建训练集和测试集 ,axis=0按照纵向方式进行拼接
train_X = pd.concat([t0.iloc[:40, :-1], t1.iloc[:40, :-1], t2.iloc[:40, :-1]], axis=0)    #取前40条
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 = KNN(k = 3)
#进行训练
knn.fit(train_X,train_y)
#进行测试获,得测试结果
result = knn.predict2(test_X)
display(np.sum(result == test_y))
display(len(result))
26
27

预测了27个数据 与测试合符合26个

预测结果可视化展示

#预测结果可视化展示
import matplotlib as mpl
import matplotlib.pyplot as plt
#设置画布的大小
plt.figure(figsize=(20,10))
#默认情况下,matplotlib不支持中文显示,设置支持中文

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

#绘制训练集数据     "Iris-versicolor":0,"Iris-setosa":1,"Iris-virginica":2
plt.scatter(x = t0["sepallength"][:40], y = t0["petallength"][:40], color = 'r', label = "Iris-versicolor")
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-virginica")
#绘制测试集数据     "Iris-versicolor":0,"Iris-setosa":1,"Iris-virginica":2
right = test_X[result == test_y]
wrong = test_X[result != test_y]
plt.scatter(x = right["sepallength"], y = right["petallength"], color = 'c', label = "right", marker = "x")
plt.scatter(x = wrong["sepallength"], y = wrong["petallength"], color = 'm', label = "wrong", marker = ">")
#设置散点图参数
plt.xlabel('花萼长度')
plt.ylabel('花瓣长度')
plt.title('KNN分类结果')
plt.legend(loc='best')
plt.show()

avator

样本预测加入权重计算

  • 原理:

距离越远权重越小,使用距离的倒数作为权重

  • 对KNN类中的predict进行改写
    def predict2(self, X):
        '''对样本进行预测,加入权重计算(距离越远权重越小,使用距离的倒数作为权重)
        Parameters:
        -----
        X: 类数组类型,可以是List也可以是Ndarray,形状为: [样本数量,特征数量]
        待训练的样本特征(属性)
        Returns:
        -----
        result :
        数组类型,预测结果
        '''
        X = np.asarray(X)
        result = []
        for x in X:
            #测试集-训练集 求欧式距离
            dis = np.sqrt(np.sum((x-self.X)**2, axis=1)) 
            #返回排序后,每个元素在原数组(排序之前的数组) 中的索引
            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)

猜你喜欢

转载自blog.csdn.net/weixin_45781143/article/details/107701409