1.作业题目
原生python实现knn分类算法,用鸢尾花数据集。
2.算法设计
首先需要设置数据集(以50个为例),然后在程序中导入数据集,根据数据集画出散点图。另外还需要定义两个函数,其中一个函数来计算两个数据点之间的欧氏距离,另一个函数设置knn模型,即计算训练数据与测试数据之间的欧氏距离,然后根据距离来排序,提取top k近邻,并且计算邻居中出现次数最多的类。最后还需要设置测试集(设置不同的k值)用来测试程序正确性。
数据集存入到文件“dataset.csv”中,具体数据为:
sepal_length,sepal_width,petal_length,petal_width,species
5.1,3.5,1.4,0.2,setosa
4.9,3,1.4,0.2,setosa
4.7,3.2,1.3,0.2,setosa
4.6,3.1,1.5,0.2,setosa
5,3.6,1.4,0.2,setosa
5.4,3.9,1.7,0.4,setosa
4.6,3.4,1.4,0.3,setosa
5,3.4,1.5,0.2,setosa
4.4,2.9,1.4,0.2,setosa
4.9,3.1,1.5,0.1,setosa
5.4,3.7,1.5,0.2,setosa
4.8,3.4,1.6,0.2,setosa
4.5,2.3,1.3,0.3,setosa
4.4,3.2,1.3,0.2,setosa
5,3.5,1.6,0.6,setosa
4.6,3.2,1.4,0.2,setosa
5.3,3.7,1.5,0.2,setosa
7,3.2,4.7,1.4,versicolor
6.4,3.2,4.5,1.5,versicolor
6,2.7,5.1,1.6,versicolor
5.6,3,4.1,1.3,versicolor
5.5,2.5,4,1.3,versicolor
5.5,2.6,4.4,1.2,versicolor
6.1,3,4.6,1.4,versicolor
5.8,2.6,4,1.2,versicolor
5,2.3,3.3,1,versicolor
5.6,2.7,4.2,1.3,versicolor
5.7,3,4.2,1.2,versicolor
5.7,2.9,4.2,1.3,versicolor
6.2,2.9,4.3,1.3,versicolor
5.1,2.5,3,1.1,versicolor
5.7,2.8,4.1,1.3,versicolor
6.3,3.3,6,2.5,virginica
5.8,2.7,5.1,1.9,virginica
7.1,3,5.9,2.1,virginica
6.3,2.9,5.6,1.8,virginica
6.5,3,5.8,2.2,virginica
7.6,3,6.6,2.1,virginica
4.9,2.5,4.5,1.7,virginica
7.3,2.9,6.3,1.8,virginica
6.7,2.5,5.8,1.8,virginica
7.2,3.6,6.1,2.5,virginica
6.5,3.2,5.1,2,virginica
6.4,2.7,5.3,1.9,virginica
6.8,3,5.5,2.1,virginica
5.7,2.5,5,2,virginica
5.8,2.8,5.1,2.4,virginica
6.4,3.2,5.3,2.3,virginica
6.5,3,5.5,1.8,virginica
3.源代码如下
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import os
import operator
import csv
#读取数据
data=pd.read_csv(os.getcwd() + '/data/' + os.sep + 'dataset.csv')
#输出数据
print('数据集为:')
print(data)
#绘制散点图
def draw_iris_data(csvpath='data/dataset.csv'):
x_list1=[]
y_list1=[]
x_list2=[]
y_list2=[]
x_list3=[]
y_list3=[]
csv_reader=csv.reader(open(csvpath))
for one_line in csv_reader:
if one_line[4]=='setosa':#类1
x_list1.append(one_line[0])
y_list1.append(one_line[1])
if one_line[4]=='versicolor':#类2
x_list2.append(one_line[0])
y_list2.append(one_line[1])
if one_line[4]=='virginica':#类3
x_list3.append(one_line[0])
y_list3.append(one_line[1])
#设置xy坐标
plt.xlabel('x')
plt.ylabel('y')
plt.title("iris_data_pic")
plt.scatter(x_list1,y_list1,c='g',marker='.')#类1表示为“ . ”
plt.scatter(x_list2,y_list2,c='b',marker='+')#类2表示为“ + ”
plt.scatter(x_list3,y_list3,c='y',marker='*')#类3表示为“ * ”
plt.legend('123')
#画图
plt.show()
print('数据集绘制的散点图如下:')
draw_iris_data()
#定义一个函数来计算两个数据点之间的欧氏距离
def CalculateDistance(data1, data2, length):
distance = 0
for x in range(length):
distance += np.square(data1[x] - data2[x])
return np.sqrt(distance)
#定义KNN模型
def knn(trainingSet, testInstance, k):
length = testInstance.shape[1]
distances = {}
#计算训练数据与测试数据之间的欧氏距离
for x in range(len(trainingSet)):
dist = CalculateDistance(testInstance, trainingSet.iloc[x], length)
distances[x] = dist[0]
#根据距离来排序
sorted_d = sorted(distances.items(), key=operator.itemgetter(1))
neighbors = []
#提取top k近邻
for x in range(k):
neighbors.append(sorted_d[x][0])
classVotes = {}
#计算邻居中出现次数最多的类
for x in range(len(neighbors)):
answer = trainingSet.iloc[neighbors[x]][-1]
if answer in classVotes:
classVotes[answer] += 1
else:
classVotes[answer] = 1
sortedVotes = sorted(classVotes.items(), key=operator.itemgetter(1), reverse=True)
return(sortedVotes[0][0])
#创建一个测试集
testSet = [[5.1, 3.5, 4.8, 2.7]]
test = pd.DataFrame(testSet)
print('测试数据',end='')
print(testSet)
#设置k为1
k = 1
print('k=1时即选取一个邻居来判断时结果为:')
result = knn(data, test, k)
print(result)
#设置k为3
k = 3
print('k=3时即选取三个邻居来判断时结果为:')
result = knn(data, test, k)
print(result)
#设置k为5
k = 5
print('k=5时即选取五个邻居来判断时结果为:')
result = knn(data, test, k)
print(result)