关于knn的理论算法已经有很多博客了,这里就不再重述。对于代码可以直接调用sklearn。但是直接利用逻辑实现,可能会对算法理解更通透。这里大家所需要修改的就是k和df,k是所选区的周围样本个数,df是路径,按照自己的路径修改就可以了。这里是对鸢尾花进行的分类处理,由于鸢尾花每个特征有的数值大,有的数值小,所以要进行归一化处理。原来的代码里没有对数据进行归一化处理,这里修改了一下。在运行时会发现,如果k很小效果不够理想,k太大也不行,在中间某个区间里,效果是不错的
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
from collections import Counter
from sklearn.preprocessing import StandardScaler
k = 40# 选定的待分类点的所处位置周围点的个数,理论上来所k值会呈现一个山峰形式,中间某个值是最好的,超过这个值,预测效果就会越来越差
df= pd.read_csv("C:/Users/wxc/Desktop/xuexi/python/pythonProject/机器学习/分类与聚类/knn/ris.csv") # 放置文件路径
df_x= np.array(df.iloc[:, 0:4]) #这里是在读取特征与标签,并把它们全部都变成ndarray类型,便于后续处理
scaler = StandardScaler()
df_x = scaler.fit_transform(df_x) #对x的标签进行归一化
df_y= np.array(df.iloc[:,-1])
train_x,test_x,train_y,test_y=train_test_split(df_x,df_y,test_size=0.3,random_state=42) #划分测试集与训练集
# KNN算法
def calculate_distance(test_x, train_x): # 计算目标点与训练集的欧式距离,并且根据距离最近的k个选择出来
distances = []
train_yth = []
for i in range(len(test_x)):
dist=[]
j_list = []
for j in range(len(train_x)): #这里用的是长度,这样子便于后续找到标签
d = np.linalg.norm(test_x[i] - train_x[j])
dist.append((j, d)) # 这里j表示在train_x中的位置是第几个,d表示测试集与训练集特征参数的欧式距离
dist.sort(key=lambda item: item[1]) #排序,按照d的大小进行排序,筛选出距离最近的k个值
distances.append(dist[:k]) # 将所有的数据全部储存起来,便于后续输出
j_list = [item[0] for item in dist[:k]] # 提取出j,这里是为了后面筛选出对应的train_y的标签
train_yth.append(j_list) # 把所有的j全部储存起来
return train_yth # 这里k设置的是15,所以每一组会有15对数
# 统计在train_x中的标签个数
test_x_pre = []
t = calculate_distance(test_x,train_x)
train_labels = []
for i in t:# 这里是在寻找对应的train_y的标签,并且保存下来
labels = [train_y[index] for index in i]
train_labels.append(labels)
for i in train_labels: # 统计train_labels中的出现最多次数的元素
counter = Counter(i)
most_common = counter.most_common(1)
most_common_element = most_common[0][0]
most_common_count = most_common[0][1]
test_x_pre.append(most_common_element)
# 这里是在进行正确率测试
o = 0
for i in range(len(test_x_pre)):
if test_x_pre[i] == test_y[i]:
o = o+1
z= o/len(test_y)
print('准确率:',z)