本文未赘述原理,觉得知道knn的优秀的同志们都有一定的了解,直接上代码,本代码作为一个参考,希望大家能够结合本人的代码自己去做一遍,虽然可以直接调knn或有数据集,本文呈现的更多的是底层。
1.创建knn.py
# 定义一个knn函数,后期方便调用.
class KNN(object):
def __init__(self,k=3): # 定义内置函数,方便自己传参,默认k值为3
self.k = k # 用于整个函数可以使用k值。
def fit(self,x,y):
# 用于后期的模型计算,输入训练集目标数据以及训练数据x。
self.x = x
self.y = y # 用于后期整个函数调用
def _square_distance(self,v1,v2):
# 用于计算距离,用的最简单的欧式距离
return np.sum(np.square(v1-v2)) # 计算欧式距离 暂时未弄清楚其欧式距离的的代码实现的意思
def _vote(self,ys):
# 不知此函数的作用,先复现,后期再进行进一步的调查。估计应该是权值的计算
ys_unique = np.unique(ys) # 进行数据的去重,numpy具有神奇的传说。科学计算库
vote_dict = {} # 定义一个空字典
for y in ys: # 进行ys的遍历
if y not in vote_dict.keys():
vote_dict[y] = 1 # 通过遍历将每个值进行计算次数
else:
vote_dict[y]+=1 # 此处证明自己的对此函数的思想的错误,此函数用于对该圈进行详细记录个数,既然去重了,记录还有何用,需进一步商榷
sorted_vote_dict = sorted(vote_dict.items(), key=operator.itemgetter(1), reverse=True)
return sorted_vote_dict[0][0] # 将已经记好的数进行一个自大而小的排列(则是一个降序排序),若reverse是false,则是自小而大.(升序排序)
def predict(self,x):
y_pred = [] # 我们定义一个预测函数,将训练集输入
# 定义一个空集合,用于y_pred(预测)
for i in range(len(x)):
# 进行遍历,得到x的长度,range是一个从一开始,直到x,步长为1
dist_arr = [self._square_distance(x[i],self.x[j]) for j in range(len(self.x))] # 不太清楚此步骤的目的于作用,回过头来再想
sorted_index=np.argsort(dist_arr) # 通过pandas库,进行升序排列,并输出值的索引.
top_k_index = sorted_index[:self.k] # 不太明白其意思
y_pred.append(self._vote(ys=self.y[top_k_index])) # 调用了_vote函数,属于自身调用,去进行分类
return np.array(y_pred)
def score(self,y_true=None,y_pred=None): #不太明白此函数的功能
if y_true is None and y_pred is None:
y_pred = self.predict(self.x) # 处理特殊情况,x与y都为空时
y_true = self.y # 此函数是用于计算我们用knn进行预测与其真实值进行一个比较的.
score = 0.0
for i in range(len(y_true)):
if y_true[i] == y_pred[i]:
score += 1
score/= len(y_true)
return score
2.调用knn.py
# 本程序用于生成随机的训练样本数据并调用knn进行分类,并推测出我们的计算精度p
# 对数组以及矩阵进行基本的运算
import numpy as np
import matplotlib.pyplot as plt # python的绘图库
from knn import *
np.random.seed(314) # 生成随机数
data_size_1 = 300
x1_1 = np.random.normal(loc=5.0, scale=1.0,size=data_size_1) # 正态分布,均值,标准差,以及可选参数
x2_1 = np.random.normal(loc=4.0,scale=1.0,size=data_size_1)
y_1 = [0 for _ in range(data_size_1)]
data_size_2 = 400
x1_2 = np.random.normal(loc=10.0, scale=2.0, size=data_size_2)
x2_2 = np.random.normal(loc=8.0, scale=2.0, size=data_size_2)
y_2 = [1 for _ in range(data_size_2)]
x1 = np.concatenate((x1_1, x1_2), axis=0) # 对数据进行合并
x2 = np.concatenate((x2_1, x2_2), axis=0) # 一般自己能找到数据的就没必要随机生成数据
x = np.hstack((x1.reshape(-1, 1), x2.reshape(-1, 1))) # reshap(-1,1) 列为1,行固定,以列为一做标志去分。hstack是一个合并数组
y = np.concatenate((y_1, y_2), axis=0) # 将y数据进行合并
data_size_all = data_size_2+data_size_1
shuffled_index = np.random.permutation(data_size_all) # 对数据进行打乱
x = x[shuffled_index]
y = y[shuffled_index]
split_index = int(data_size_all*0.7) # 进行数据集的拆分
x_train = x[: split_index] # 训练集占百分之七十
y_train = y[: split_index]
x_test = x[split_index:]
y_test = y[split_index:]
# 数据可视化
plt.scatter(x_train[:, 0], x_train[:, 1], c=y_train, marker='.') # 散点图的绘制
plt.show()
plt.scatter(x_test[:, 0], x_test[:, 1], c=y_test, marker='.')
plt.show()
# 数据归一化
x_train = (x_train - np.min(x_train,axis=0)) / (np.max(x_train,axis=0)-np.min(x_train,axis=0))
x_test = (x_test - np.min(x_test,axis=0)) / (np.max(x_test,axis = 0)-np.min(x_test,axis= 0)) # 用的是minmax归一化
# 进行knn分类
clf = KNN(k=3)
clf.fit(x_train, y_train)
print('train accuracy: {:.3}'.format(clf.score()))
y_test_pred = clf.predict(x_test)
print('test accuracy: {:.3}'.format(clf.score(y_test, y_test_pred)))



