KNN算法导入
KNN算法的大致思路如图所示。采用数据集是教材使用的燕尾花数据集。
以下是在KNN函数中几个变量的用法
*
- dist 列表 暂放训练集的点到测试点的距离
- nearest 数组 对dist列表里的距离从大到小按索引排序返回的
- valuest 列表 前k个距离最近的训练集的标签值(花的种类)
- count 字典 统计每个种类出现的频率(种类:次数)*
对距离dist[]的大小进行从大到小排序按索引进行排序,以数组形式返回
nearest = np.argsort(dist)
nearest = np.argsort(dist)
进而获得前k个距离最近的训练集
valuest = [value[m] for m in nearest[:k]]
利用字典count{}再对标签出现的次数统计 确定前k个点出现的频率。
count ={} #标签:次数
for i in range(k):
key = valuest[i]
if(key in count.keys()):
count[key]+=1
else:
count[key]=1
利用lambda再对字典中以值的大小从大到小排序,确定最多的那个类别
countList = sorted(count.items(),key = lambda x:x[1],reverse=True)
test_result.append(countList[0][0])
代码
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import mglearn
import math
'''分析步骤:
1.计算测试数据和每个训练数据的距离;
2.对距离的大小进行从小到大排序
3.选取距离最小的k个点
4.确定前k个点类别的出现频率
5.出现频率最高的类别就是预测类别了'''
def loadDataSet(): #加载燕尾花数据
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
iris_dataset = load_iris() #加载了数据集
return train_test_split(iris_dataset['data'],iris_dataset['target'],random_state=0) #返回的形式是数组
def euclidean_Distance(X1,X2):#计算欧式距离
distance = 0;
distance =sum((X1 - X2)**2)
return np.sqrt(distance)
#train:训练集 value:训练集标签 test测试集 k:指定邻近的个数
def knn(train,value,test,k):
test_result=[] #用来存放测试集标签(结果)
for i in range(len(test)):#迭代每个测试数据
dist =[] #暂放数据的距离的列表
#计算每个测试数据和每个训练数据的距离
for j in range(len(train)):
dist.append(euclidean_Distance(train[j],test[i]))
#对距离的大小进行从小到大排序 按索引进行排序
nearest = np.argsort(dist)
valuest = [value[m] for m in nearest[:k]] #获取前k个距离最近的训练集的标签值
#对标签出现的次数统计 确定前k个点出现的频率
count ={} #标签:次数
for i in range(k):
key = valuest[i]
if(key in count.keys()):
count[key]+=1
else:
count[key]=1
#通过排序确定最多的那个类别
countList = sorted(count.items(),key = lambda x:x[1],reverse=True)
test_result.append(countList[0][0])
return test_result;
def main():
k=3
#train:训练集 train value:训练集标签 test 测试集数据 test——value:测试集标签
train,test,train_value,test_value=loadDataSet()
result=knn(train,train_value,test,k)
print('数据集提供的测试集标签:',test_value)
print('knn后测试集标签:',result)
#计算精度
m=0
test_value = test_value.tolist()
n = len(test_value)
for i in range(n):
if test_value[i]==result[i]:
m+=1
accuracy = m/n
print('knn分类后的精度为:',accuracy)
main()
结果
总结
- 对标签频率进行统计,参考了网络上的资料,很多都是使用collection中的Counter() 实现统计,而我使用更底层的算法:利用字典进行统计,键是种类,值是出现次数(频率),最后利用lambda表达式排序取最高的那一个;
- 在对距离的大小排序后获取训练数据样本对应的标签值上,dist[]列表来保存距离。使用了numpy库中的argsort( )对获取距离从小到大排序所对应dist[]的索引值(即:按索引进行排序),方便后面获取训练集的标签。比我一开始想的训练集多加一列,把距离加到那一列上,再进行排序方便了很多。
- 总体设计完后,感觉有些情况下用数组计算,会比其他的序列(列表、字
典)等的直接计算更为方便。总体上,对Python接触还不够多,看似简单
的一个作业,其实编码过程中还走了不少弯路。