K近邻算法简介
K近邻算法(K-nearest neighbor,KNN)是一种非常直观的,易于理解的有监督的算法:对于一个待分类的样本,在已知的样本集合中寻
找与它距离最近的K个样本,及所谓的K近邻。通过这这K个近邻的所述类别来决定分类结果。
KNN算法3个要素
- 距离度量
- 分类决策
- K的选择
距离度量
距离度量方法有很多种,例如:欧式距离、曼哈顿距离、切比雪夫距离等等。
分类决策
分类决策一般是通过投票决定,当然也可以根据具体情况再做改变。常见的改进方法如距离加权:赋予距离越近的样本越大的权值。
K的选择
当K的取值很小时,决策易受到噪声的干扰;同时模型复杂,也容易造成过拟合。
当K的取值很大时,决策边缘会变得平滑,模型简单,预测结果容易出现错误。
通常采用交叉验证来选去较好的K值。
KNN算法流程
- 计算距离:计算当前待分类样本与所有已知样本的距离
- 距离排序:将距离降序排序
- 投票分类:选择K个近邻,并根据其类别决定待分类样本的类别。
代码
读取数据
本实验采用的是UCI上的iris数据集,链接如下:
iris数据集
import numpy as np
import pandas as pd
ori_data = pd.read_csv('iris.data',header=None)
处理数据
1.将标记映射为数字
label_map = {
'Iris-setosa':1,
'Iris-versicolor':2,
'Iris-virginica':3
}
data = ori_data.replace(label_map)
2.归一化
将数据归一化到[a,b]之间的函数如下:
def normalization(a, b, array):
maxcols = array.max(axis=0)
mincols = array.min(axis=0)
trans_data = np.zeros(array.shape)
[m, n] = array.shape
for i in range(n):
k = (b-a)/(maxcols[i]-mincols[i])
trans_data[:, i] = a + k * (array[:, i]-mincols[i])
return trans_data
调用处理数据
data_array = np.array(data)
[data_num, feature_num] = data_array.shape
trans_data = normalization(0, 1, data_array[:, 0:feature_num-1])
label = data_array[:, feature_num-1].reshape(data_num, 1)
trans_data = np.hstack((trans_data, label)) #按列合并
全部代码如下
import pandas as pd
import numpy as np
import math
import random
from scipy import stats
def normalization(a, b, array):
maxcols = array.max(axis=0)
mincols = array.min(axis=0)
trans_data = np.zeros(array.shape)
[m, n] = array.shape
for i in range(n):
k = (b-a)/(maxcols[i]-mincols[i])
trans_data[:, i] = a + k * (array[:, i]-mincols[i])
return trans_data
def dis(x1, x2):
return np.sqrt(np.sum(pow((x1 - x2), 2)))
#预测样本类别
def cla(x, train_x, train_y, k):
n = train_x.shape[0]
distance = np.zeros((n, 1))
for i in range(n):
x2 = train_x[i,:]
distance[i, 0] = dis(x, x2)
dis_and_y = np.hstack((distance, train_y))
index = np.argsort(dis_and_y[:, 0])
dis_and_y = dis_and_y[index]
list = dis_and_y[0:k,1]
a = stats.mode(list)[0] #计算众数
return a[0]
#计算分类精度
def predict(train_data, test_data):
train_y = train_data[:, feature_num-1].reshape(train_data.shape[0], 1)
test_y = test_data[:, feature_num-1].reshape(test_data.shape[0], 1)
train_x = train_data[:, 0:feature_num-1]
test_x = test_data[:, 0:feature_num-1]
count = 0
for i in range(test_x.shape[0]):
y = cla(test_x[i, :], train_x, train_y, 10)
if y == test_y[i, 0]:
count = count + 1
return count/test_data.shape[0]
ori_data = pd.read_csv("iris.data", header=None)
label_map = {
'Iris-setosa':1,
'Iris-versicolor':2,
'Iris-virginica':3
}
data = ori_data.replace(label_map) # 标记映射到1,2,3
data_array = np.array(data)
[data_num, feature_num] = data_array.shape
trans_data = normalization(0, 1, data_array[:, 0:feature_num-1])
label = data_array[:, feature_num-1].reshape(data_num, 1)
trans_data = np.hstack((trans_data, label)) #按列合并
for i in range(10):
#抽样
sl = random.sample(range(0, data_num), data_num//10)
test_data = trans_data[sl, :]
train_data = np.delete(trans_data, sl, axis=0)
prediction = predict(train_data, test_data)
print(prediction)
如有疑问,欢迎指出