KNN算法

K-近邻算法(KNN)概述

最简单最初级的分类器是将全部的训练数据所对应的类别都记录下来,当测试对象的属性和某个训练对象的属性完全匹配时,便可以对其进行分类。但是怎么可能所有测试对象都会找到与之完全匹配的训练对象呢,其次就是存在一个测试对象同时与多个训练对象匹配,导致一个训练对象被分到了多个类的问题,基于这些问题呢,就产生了KNN。

KNN是通过测量不同特征值之间的距离进行分类。它的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别,其中K通常是不大于20的整数。KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。

下面通过一个简单的例子说明一下:如下图,绿色圆要被决定赋予哪个类,是红色三角形还是蓝色四方形?如果K=3,由于红色三角形所占比例为2/3,绿色圆将被赋予红色三角形那个类,如果K=5,由于蓝色四方形比例为3/5,因此绿色圆被赋予蓝色四方形类。
在这里插入图片描述
由此也说明了KNN算法的结果很大程度取决于K的选择。

在KNN中,通过计算对象间距离来作为各个对象之间的非相似性指标,避免了对象之间的匹配问题,在这里距离一般使用欧氏距离或曼哈顿距离:
在这里插入图片描述
同时,KNN通过依据k个对象中占优的类别进行决策,而不是单一的对象类别决策。这两点就是KNN算法的优势。

接下来对KNN算法的思想总结一下:就是在训练集中数据和标签已知的情况下,输入测试数据,将测试数据的特征与训练集中对应的特征进行相互比较,找到训练集中与之最为相似的前K个数据,则该测试数据对应的类别就是K个数据中出现次数最多的那个分类,其算法的描述为:

1)计算测试数据与各个训练数据之间的距离;

2)按照距离的递增关系进行排序;

3)选取距离最小的K个点;

4)确定前K个点所在类别的出现频率;

5)返回前K个点中出现频率最高的类别作为测试数据的预测分类。

python实现

import numpy as np
import pandas as pd
#读取csv文件,去除重复,默认为0,第一行,如果不去除头部,可以使用None
data = pd.read_csv("iris.csv",header=0)
data
#head 默认5行
data.head()
#tail 默认后5行
data.tail(20)
#抽样方法 默认输出一条数据
data.sample(10)

data["Species"] = data["Species"].map({"virginica":0,"setosa":1,"versicolor":2})
data.sample(10)
#删除Id列 inplace设置为true,修改当前对象的值
data.drop("Id",axis=1,inplace=True)
#判断是否有重复值 False没有重复值  True数据重复
data.duplicated()
#返回true表示有重复值
data.duplicated().any()
#去除重复值
data.drop_duplicates(inplace=True)
len(data)
data["Species"].value_counts()
data
  • 清洗完后的data

在这里插入图片描述

  • 创建 KNN的类
class KNN:
    """实现 KNN算法 邻近算法 (分类)"""
    def __init__(self,k):
        """初始化方法
        k: int 获取邻近的个数
        self: 类似于java中的this  自己  当前kn对象
        """
        self.k = k
    def fit(self,X,y):
        """训练数据
        X:类数据类型,形状为:[样本数量,特征数量]
            训练样本特征(属性) 类似于5.1,3.5,1.4,0.2
        y:类数据类型,形状为:[样本数量]
            每个样本的目标值(标签)  类似于 1
        """
        #将X y转换成np array类型
        self.X = np.asarray(X)
        self.y = np.asarray(y)
    def predict(self,V):
        """根据样本传过来的特征,预测特征
        
        X:类数组类型,形状为[样本数量,特征数量]
        
        result:数组类型
          预测结果
        
        """
        V = np.asarray(V)
        result = []
        #对 测试数据集进行遍历,去除每条数据与训练数据集进行计算
        for v in V:
            #获取每一个测试集到每一个训练集的距离
            dis = np.sqrt(np.sum((v - self.X)**2,axis=1))
             #将dis距离按大小排序 不用sort 用argsort返回下标
            index = dis.argsort()
            # 取出前k个距离最近的邻居
            index = index[:self.k]
            #根据index获取y中对应的特征值
            #bincount进行统计
            count = np.bincount(self.y[index])
            #往result数组中添加count最大的
            #argmax()0是取出数组中最大值的索引
            #这个索引就是颜色
            result.append(count.argmax())
        return np.asarray(result)  
  • 获取训练和测试的数据
t0 = data[data["Species"]==0]
t1 = data[data["Species"]==1]
t2 = data[data["Species"]==2]
#数据可以重现
t1=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)
result

KNN回归算法

class KNN2:
    #回归算法
    def __init__(self,k):
        self.k=k
    def fit(self,X,y):
        self.X = np.asarray(X)
        self.y = np.asarray(y)
    def predict(self,X):
        X = np.asarray(X)
        result = []
        for x in X:
            dis = np.sum((x-self.X)**2,axis=1)
            
            index = dis.argsort()
            index = index[:self.k]
            
            result.append(np.mean(self.y[index]))
        return np.asarray(result)
    def predict2(self,X):
        
        X = np.asarray(X)
        result = []
        for x in X:
            dis = np.sum((x-self.X)**2,axis=1)
            
            index = dis.argsort()
            index = index[:self.k]
            #,倒数和避免除0加一个很小很小的数
            daoshu = 1/dis[index]+0.000000001
            he = np.sum(daoshu)
            #权重
            weight = daoshu/he
            result.append(np.mean(self.y[index]*weight))
        return np.asarray(result)

data = pd.read_csv("./iris.csv")
len(data)
data.drop(["Id","Species"],axis=1,inplace=True)
data.drop_duplicates(inplace=True)
X = data.sample(len(data),random_state=0)
train_X = X.iloc[:120,:-1]
train_y = X.iloc[:120,-1]
test_X = X.iloc[120:,:-1]
test_y = X.iloc[120:,-1]
X = data.sample(len(data),random_state=0)
train_X = X.iloc[:120,:-1]
train_y = X.iloc[:120,-1]
test_X = X.iloc[120:,:-1]
test_y = X.iloc[120:,-1]
np.sum((result-test_y.values)**2)/len(result)
import matplotlib as mpl
#import matplotlib.pyplot as plt
from matplotlib import pyplot as plt

#设置中文
mpl.rcParams["font.family"] = "SimHei"
mpl.rcParams["axes.unicode_minus"]=False
plt.figure(figsize=(8,8))
plt.plot(result,"ro-",label="预测值")
plt.plot(test_y.values,"go--",label="真实值")
plt.title("KNN回归算法")
plt.xlabel("序号")
plt.ylabel("度量值")
plt.legend()
plt.show()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值