欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

KNN分类python实现

程序员文章站 2022-04-07 23:01:13
...
import numpy as np
import pandas as pd

KNN算法过程

  • 从训练集中选择离预测样本最近的K个样本。
  • 根据这K个样本计算这个样本的值(属于哪个类别或具体数值)

对数据集的操作

#读取鸢尾花数据集,header参数来指定标题的行,默认为0,如果没有标题,则使用None
data=pd.read_csv(r"F:\数据集\Iris数据集\iris.csv",header=0)
#data  默认显示全部行  中间用省略号
#data.head()只显示头5行(默认)
#data.head(n)显示头n行
#data.tail()默认显示后5行
#data.tail(n)显示后n行
#data.sample()默认随机抽取一行显示
#data.sample(n)随机抽取n条样本
data.sample(10)
#将Species这一列的各种值映射为相应的数值
data["Species"]=data["Species"].map({"versicolor":0,"setosa":1,"virginica":2})
#data
#删除不需要的	Unnamed: 0列 axis=1表示删除列   默认为0,表示删除行
#data=data.drop("Unnamed",axis=1)与下面这行等价  
data.drop("Unnamed: 0",axis=1,inplace=True)
#判断数据集中是否有重复的值,  只要有一个重复则返回true,否则返回false
data.duplicated().any()
#输出原有鸢尾花记录数:150条
len(data)
#删除重复记录,加上inplace=True使其在原有的数据集上操作,而不是在其副本上操作
data.drop_duplicates(inplace=True)
#删除重复记录后:149条
len(data)
#查看各个类别的鸢尾花具有多少条记录
data["Species"].value_counts()
1    50
0    50
2    49
Name: Species, dtype: int64

编写KNN的类

class KNN:
    """ 使用python语言实现K近邻算法。(实现分类)"""
    #定义初始化方法(init两边是两杠)
    def __init__(self,k):
        """
        初始化方法
        paramters
        --------
        k:int
            邻居的个数.
        """
        self.k=k
    #定义fit(训练)方法
    def fit(self,X,y):
        """训练方法
        Parameters
        -------
        X:类数组类型,形状为:[样本数量,特征数量]
          待训练的样本特征
        y:类数组类型,形状为:[样本数量]
           每个样本的目标值(标签) 
        
        """
        #为了统一处理list和dataFrame,将X转化为ndarray数组形式,若X本身就是ndarray类型则什么都不做
        self.X=np.asarray(X)
        #同理转换y
        self.y=np.asarray(y)
    #定义预测方法  参数X是测试集的样本,没有考虑权重
    def predict(self,X):
        """根据参数传递的样本,对样本数据进行预测
        Parameters
        ---------
        X:类数组类型,形状为:[样本数量,特征数量]
          待训练的样本特征
        Return:
        --------
        result:数组类型
               预测的结果 
        """
        X=np.asarray(X)
        result=[]
        #对ndarray数组进行遍历,每次取数组中的一行(一个样本)。
        # self.X是训练集的样本  这里用欧式距离
        #注意,x是一行,self.X是多行,在做减法是先会对x进行扩展,使其行数和self.X 一样,再对应元素想减
        for x in X:
            #axis=1 指定按行的方式求和,否则是将数组所有的值求和成一个数值
            #对于测试集中的每一个样本,一次与训练集中的所有样本求距离
            dis=np.sqrt(np.sum((x-self.X)**2,axis=1))
            #返回数组排序后每个元素在原数组中的索引(原数组:排序之前的数组)
            index=dis.argsort()
            #进行截断,只取前k个元素【取距离最近的k个元素的索引】
            index=index[:self.k]
            #找到距离最近的k个节点的标签  index不论是list还是ndarray都行(都返回对应位置的标签)
            #self.y[index]
            #返回数组中每个元素(0、1、2.。。数据最大值 等出现的次数)出现的次数,但元素必须是非负的整数
            count=np.bincount(self.y[index])
            #返回ndarray数组中,值最大的元素对应的索引,就是出现次数最多的元素的索引,该索引就是我们判定的类别
            #count.argmax()
            #将判定的类别加到结果中
            result.append(count.argmax())
        #写成np.array(result)也行(用result创建ndarray数组)
        #这里写成np.asarray(result)是将result转化为ndarray数组
        return np.asarray(result)
        
       #定义预测方法2  参数X是测试集的样本,考虑权重 
    def predict2(self,X):
        """根据参数传递的样本,对样本数据进行预测(考虑权重,使用距离的倒数使用权重)
        Parameters
        ---------
        X:类数组类型,形状为:[样本数量,特征数量]
          待训练的样本特征
        Return:
        --------
        result:数组类型
               预测的结果 
        """
        X=np.asarray(X)
        result=[]
        #对ndarray数组进行遍历,每次取数组中的一行(一个样本)。
        # self.X是训练集的样本  这里用欧式距离
        #注意,x是一行,self.X是多行,在做减法是先会对x进行扩展,使其行数和self.X 一样,再对应元素想减
        for x in X:
            #axis=1 指定按行的方式求和,否则是将数组所有的值求和成一个数值
            #对于测试集中的每一个样本,一次与训练集中的所有样本求距离
            dis=np.sqrt(np.sum((x-self.X)**2,axis=1))
            #返回数组排序后每个元素在原数组中的索引(原数组:排序之前的数组)
            index=dis.argsort()
            #进行截断,只取前k个元素【取距离最近的k个元素的索引】
            index=index[:self.k]
            #找到距离最近的k个节点的标签  index不论是list还是ndarray都行(都返回对应位置的标签)
            #self.y[index]
            #返回数组中每个元素(0、1、2.。。数据最大值 等出现的次数)出现的次数,但元素必须是非负的整数
            #[使用weights考虑权重,权重为距离的倒数]
            count=np.bincount(self.y[index],weights=1/dis[index])
            #返回ndarray数组中,值最大的元素对应的索引,就是出现次数最多的元素的索引,该索引就是我们判定的类别
            #count.argmax()
            #将判定的类别加到结果中
            result.append(count.argmax())
        #写成np.array(result)也行(用result创建ndarray数组)
        #这里写成np.asarray(result)是将result转化为ndarray数组
        return np.asarray(result)

训练与测试:

#提取出每个类别的鸢尾花数据
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)
#构建训练集和测试集  axix=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.predict1(test_X)
result=knn.predict2(test_X)
#display(result)
#display(test_y)
display(np.sum(result==test_y))
#display(len(result))
display((np.sum(result==test_y))/len(result))
28



0.9655172413793104

KNN可视化

import matplotlib as mpl
import matplotlib.pyplot as plt

绘制数据

#默认情况下matplotlib不支持中文显示,我们需要设置一下,使其支持
#设置字体为黑体,以支持中文显示
mpl.rcParams["font.family"]="SimHei"
#设置在中文字体是,能正常显示负号(-)
mpl.rcParams["axes.unicode_minus"]=False
#{"versicolor":0,"setosa":1,"virginica":2}
#  设置画布的大小

plt.figure(figsize=(8,8))
#绘制训练集数据散点图  选择花瓣、花萼长度这两个维度  注意:不要将label写成lable了
plt.scatter(x=t0["Sepal.Length"][:40],y=t0["Petal.Length"][:40],color="r",label="versicolor")
plt.scatter(x=t1["Sepal.Length"][:40],y=t1["Petal.Length"][:40],color="g",label="setosa")
plt.scatter(x=t2["Sepal.Length"][:40],y=t2["Petal.Length"][:40],color="b",label="virginica")

#绘制测试集数据  返回数组给right 和 wrong
right=test_X[result==test_y]
wrong=test_X[result!=test_y]
plt.scatter(x=right["Sepal.Length"],y=right["Petal.Length"],color="c",marker="x",label="right")
plt.scatter(x=wrong["Sepal.Length"],y=wrong["Petal.Length"],color="m",marker=">",label="wrong")
plt.xlabel("花萼长度")
plt.ylabel("花瓣长度")
plt.title("KNN分类结果显示")
# 设置图例显示位置  默认best  最合适的地方
plt.legend(loc="best")
#显示图形
plt.show()

KNN分类python实现