pythonKNN算法实现鸢尾花数据集分类
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
pythonKNN算法实现鸢尾花数据集分类
⼀、knn算法描述
1.基本概述
knn算法,⼜叫k-近邻算法。
属于⼀个分类算法,主要思想如下:
⼀个样本在特征空间中的k个最近邻的样本中的⼤多数都属于某⼀个类别,则该样本也属于这个类别。
其中k表⽰最近邻居的个数。
⽤⼆维的图例,说明knn算法,如下:
⼆维空间下数据之间的距离计算:
在n维空间两个数据之间:
2.具体步骤:
(1)计算待测试数据与各训练数据的距离
(2)将计算的距离进⾏由⼩到⼤排序
(3)找出距离最⼩的k个值
(4)计算找出的值中每个类别的频次
(5)返回频次最⾼的类别
⼆、鸢尾花数据集
Iris 鸢尾花数据集内包含 3 类分别为⼭鸢尾(Iris-setosa)、变⾊鸢尾(Iris-versicolor)和维吉尼亚鸢尾(Iris-virginica),共150 条记录,每类各 50 个数据,每条记录都有 4 项特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度,可以通过这4个特征预测鸢尾花卉属于哪⼀品种。
iris数据集包含在sklearn库当中,具体在sklearn\datasets\data⽂件夹下,⽂件名为iris.csv。
以本机为例。
其路径如下:
D:\python\lib\site-packages\sklearn\datasets\data\iris.csv
其中数据如下格式:
第⼀⾏数据意义如下:
150:数据集中数据的总条数
4:特征值的类别数,即花萼长度、花萼宽度、花瓣长度、花瓣宽度。
setosa、versicolor、virginica:三种鸢尾花名
从第⼆⾏开始:
第⼀列为花萼长度值
第⼆列为花萼宽度值
第三列为花瓣长度值
第四列为花瓣宽度值
第五列对应是种类(三类鸢尾花分别⽤0,1,2表⽰)
三、算法实现
1.算法流程图:
从以上流程图可以看出,knn算法包含后四步操作,所以将整个程序分为三个模块。
2.具体实现
(1)⽅法⼀
①利⽤slearn库中的load_iris()导⼊iris数据集
②使⽤train_test_split()对数据集进⾏划分
③KNeighborsClassifier()设置邻居数
④利⽤fit()构建基于训练集的模型
⑤使⽤predict()进⾏预测
⑥使⽤score()进⾏模型评估
说明:本代码来源于《Python机器学习基础教程》在此仅供学习使⽤。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
# 载⼊数据集
iris_dataset = load_iris()
# 数据划分
X_train, X_test, y_train, y_test = train_test_split(iris_dataset['data'], iris_dataset['target'], random_state=0)
# 设置邻居数
knn = KNeighborsClassifier(n_neighbors=1)
# 构建基于训练集的模型
knn.fit(X_train, y_train)
# ⼀条测试数据
X_new = np.array([[5, 2.9, 1, 0.2]])
# 对X_new预测结果
prediction = knn.predict(X_new)
print("预测值%d" % prediction)
# 得出测试集X_test测试集的分数
print("score:{:.2f}".format(knn.score(X_test,y_test)))
(2)⽅法⼆
①使⽤读取⽂件的⽅式,使⽤open、以及csv中的相关⽅法载⼊数据
②输⼊测试集和训练集的⽐率,对载⼊的数据使⽤shuffle()打乱后,计算训练集及测试集个数对特征值数据和对应的标签数据进⾏分割。
③将分割后的数据,计算测试集数据与每⼀个训练集的距离,使⽤norm()函数直接求⼆范数,或者载⼊数据使⽤
np.sqrt(sum((test - train) ** 2))求得距离,使⽤argsort()将距离进⾏排序,并返回索引值,
④取出值最⼩的k个,获得其标签值,存进⼀个字典,标签值为键,出现次数为值,对字典进⾏按值的⼤⼩递减排序,将字典第⼀个键的值存⼊预测结果的列表中,计算完所有测试集数据后,返回⼀个列表。
⑤将预测结果与测试集本⾝的标签进⾏对⽐,得出分数。
import csv
import random
import numpy as np
import operator
def openfile(filename):
"""
打开数据集,进⾏数据处理
:param filename: 数据集的路径
:return: 返回数据集的数据,标签,以及标签名
"""
with open(filename) as csv_file:
data_file = csv.reader(csv_file)
temp = next(data_file)
# 数据集中数据的总数量
n_samples = int(temp[0])
# 数据集中特征值的种类个数
n_features = int(temp[1])
# 标签名
target_names = np.array(temp[2:])
# empty()函数构造⼀个未初始化的矩阵,⾏数为数据集数量,列数为特征值的种类个数
data = np.empty((n_samples, n_features))
# empty()函数构造⼀个未初始化的矩阵,⾏数为数据集数量,1列,数据格式为int
target = np.empty((n_samples,), dtype=np.int)
for i, j in enumerate(data_file):
# 将数据集中的将数据转化为矩阵,数据格式为float
# 将数据中从第⼀列到倒数第⼆列中的数据保存在data中
data[i] = np.asarray(j[:-1], dtype=np.float64)
# 将数据集中的将数据转化为矩阵,数据格式为int
# 将数据集中倒数第⼀列中的数据保存在target中
target[i] = np.asarray(j[-1], dtype=np.int)
# 返回数据,标签和标签名
return data, target, target_names
def random_number(data_size):
"""
该函数使⽤shuffle()打乱⼀个包含从0到数据集⼤⼩的整数列表。
因此每次运⾏程序划分不同,导致结果不同改进:
可使⽤random设置随机种⼦,随机⼀个包含从0到数据集⼤⼩的整数列表,保证每次的划分结果相同。
:param data_size: 数据集⼤⼩
:return: 返回⼀个列表
"""
number_set = []
for i in range(data_size):
number_set.append(i)
random.shuffle(number_set)
return number_set
def split_data_set(data_set, target_data, rate=0.25):
"""
说明:分割数据集,默认数据集的25%是测试集
:param data_set: 数据集
:param target_data: 标签数据
:param rate: 测试集所占的⽐率
:return: 返回训练集数据、训练集标签、训练集数据、训练集标签
"""
# 计算训练集的数据个数
train_size = int((1-rate) * len(data_set))
# 获得数据
data_index = random_number(len(data_set))
# 分割数据集(X表⽰数据,y表⽰标签),以返回的index为下标
x_train = data_set[data_index[:train_size]]
x_test = data_set[data_index[train_size:]]
y_train = target_data[data_index[:train_size]]
y_test = target_data[data_index[train_size:]]
return x_train, x_test, y_train, y_test
def data_diatance(x_test, x_train):
"""
:param x_test: 测试集
:param x_train: 训练集
:return: 返回计算的距离
"""
# sqrt_x = np.linalg.norm(test-train) # 使⽤norm求⼆范数(距离)
distances = np.sqrt(sum((x_test - x_train) ** 2))
return distances
def knn(x_test, x_train, y_train, k):
"""
:param x_test: 测试集数据
:param x_train: 训练集数据
:param y_train: 测试集标签
:param k: 邻居数
:return: 返回⼀个列表包含预测结果
"""
# 预测结果列表,⽤于存储测试集预测出来的结果
predict_result_set=[]
# 训练集的长度
train_set_size = len(x_train)
# 创建⼀个全零的矩阵,长度为训练集的长度
distances = np.array(np.zeros(train_set_size))
# 计算每⼀个测试集与每⼀个训练集的距离
for i in x_test:
for indx in range(train_set_size):
# 计算数据之间的距离
distances[indx] = data_diatance(i, x_train[indx])
# 排序后的距离的下标
sorted_dist = np.argsort(distances)
class_count = {}
# 取出k个最短距离
for i in range(k):
# 获得下标所对应的标签值
sort_label = y_train[sorted_dist[i]]
# 将标签存⼊字典之中并存⼊个数
class_count[sort_label]=class_count.get(sort_label, 0) + 1
# 对标签进⾏排序
sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True) # 将出现频次最⾼的放⼊预测结果列表
predict_result_set.append(sorted_class_count[0][0])
# 返回预测结果列表
return predict_result_set
def score(predict_result_set, y_test):
"""
:param predict_result_set: 预测结果列表
:param y_test: 测试集标签
:return: 返回测试集精度
"""
count = 0
for i in range(0, len(predict_result_set)):
if predict_result_set[i] == y_test[i]:
count += 1
score = count / len(predict_result_set)
return score
if __name__ == "__main__":
iris_dataset = openfile('iris.csv')
# x_new = np.array([[5, 2.9, 1, 0.2]])
x_train, x_test, y_train, y_test = split_data_set(iris_dataset[0], iris_dataset[1])
result = knn(x_test,x_train, y_train, 6)
print("原有标签:", y_test)
# 为了⽅便对⽐查看,此处将预测结果转化为array,可直接打印结果
print("预测结果:", np.array(result))
score = score(result, y_test)
print("测试集的精度:%.2f" % score)
四、运⾏结果
结果不同,因为每次划分的训练集和测试集不同,具体见random_number()⽅法。
五、总结
在本次使⽤python实现knn算法时,遇到了很多困难,如数据集的加载,数据的格式不能满⾜后续需要,因此阅读了sklearn库中的⼀部分代码,有选择性的进⾏了复⽤。
数据与标签⽆法分离,或是数据与标签排序后后⽆法对应的情况,查询许多资料后使⽤argsort()完美解决该问题。
出现了n多错误,通过多次调试之后最终完成。
附:本次实验参考:
①*郑捷《机器学习算法原理与编程实践》
②《Python机器学习基础教程》
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。