一、KNN算法简介

邻近算法,或者说K最近邻(kNN,k-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一。所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。

kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 kNN方法在类别决策时,只与极少量的相邻样本有关。由于kNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,kNN方法较其他方法更为适合。

python实现KNN分类算法

二、算法过程

1.读取数据集

2.处理数据集数据 清洗,采用留出法hold-out拆分数据集:训练集、测试集

3.实现KNN算法类:

   1)遍历训练数据集,离差平方和计算各点之间的距离

   2)对各点的距离数组进行排序,根据输入的k值取对应的k个点

   3)k个点中,统计每个点出现的次数,权重为距离的导数,得到最大的值,该值的索引就是我们计算出的判定类别

三、代码实现及数据分析

import numpy as np
import pandas as pd
 
# 读取鸢尾花数据集,header参数来指定标题的行。默认为0。如果没有标题,则使用None。
data = pd.read_csv("你的目录/Iris.csv",header=0)
# 显示前n行记录。默认n的值为5。
#data.head()
# 显示末尾的n行记录。默认n的值为5。
#data.tail()
# 随机抽取样本。默认抽取一条,我们可以通过参数进行指定抽取样本的数量。
# data.sample(10)
# 将类别文本映射成为数值类型
 
data["Species"] = data["Species"].map({"Iris-virginica": 0, "Iris-setosa": 1, "Iris-versicolor": 2})
# 删除不需要的Id列。
data.drop("Id", axis=1, inplace=True )
data.drop_duplicates(inplace=True)
## 查看各个类别的鸢尾花具有多少条记录。
data["Species"].value_counts()

分析:首先读取数据集,如下图

python实现KNN分类算法

最后一列为数据集的分类名称,但是在程序中,我们更倾向于使用如0、1、2数字来表示分类,所以对数据集进行处理,处理后的数据集如下:

python实现KNN分类算法

然后采用留出法对数据集进行拆分,一部分用作训练,一部分用作测试,如下图:

#构建训练集与测试集,用于对模型进行训练与测试。
# 提取出每个类比的鸢尾花数据
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)#截取前40行,除最后列外的列,因为最后一列是y
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类,用于分类,类中定义两个预测方法,分为考虑权重不考虑权重两种情况
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 : 类数组类型,形状为:[样本数量, 特征数量]
   待训练的样本特征(属性) 
  
  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]
   # 返回数组中每个元素出现的次数。元素必须是非负的整数。【使用weights考虑权重,权重为距离的倒数。】
   count = np.bincount(self.y[index], weights= 1 / dis[index])
   # 返回ndarray数组中,值最大的元素对应的索引。该索引就是我们判定的类别。
   # 最大元素索引,就是出现次数最多的元素。
   result.append(count.argmax())
  return np.asarray(result)
#创建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

得出该模型计算的结果中,有26条记录与测试集相等,准确率为96%

接下来绘制散点图:

#导入可视化所必须的库。
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams["font.family"] = "SimHei"
mpl.rcParams["axes.unicode_minus"] = False
 
#绘制散点图。为了能够更方便的进行可视化,这里只选择了两个维度(分别是花萼长度与花瓣长度)。
# {"Iris-virginica": 0, "Iris-setosa": 1, "Iris-versicolor": 2})
# 设置画布的大小
plt.figure(figsize=(10, 10))
# 绘制训练集数据
plt.scatter(x=t0["SepalLengthCm"][:40], y=t0["PetalLengthCm"][:40], color="r", label="Iris-virginica")
plt.scatter(x=t1["SepalLengthCm"][:40], y=t1["PetalLengthCm"][:40], color="g", label="Iris-setosa")
plt.scatter(x=t2["SepalLengthCm"][:40], y=t2["PetalLengthCm"][:40], color="b", label="Iris-versicolor")
# 绘制测试集数据
right = test_X[result == test_y]
wrong = test_X[result != test_y]
plt.scatter(x=right["SepalLengthCm"], y=right["PetalLengthCm"], color="c", marker="x", label="right")
plt.scatter(x=wrong["SepalLengthCm"], y=wrong["PetalLengthCm"], color="m", marker=">", label="wrong")
plt.xlabel("花萼长度")
plt.ylabel("花瓣长度")
plt.title("KNN分类结果显示")
plt.legend(loc="best")
plt.show()

程序运行结果如下:

python实现KNN分类算法

四、思考与优化

①尝试去改变邻居的数量。

②在考虑权重的情况下,修改邻居的数量。

③对比查看结果上的差异。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

华山资源网 Design By www.eoogi.com
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
华山资源网 Design By www.eoogi.com

《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线

暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。

艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。

《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。