一、KNN学习
K近邻学习是一种常用的监督学习方法,是“懒惰学习”的代表,仅在训练阶段把样本保存起来,训练时间开销为零,待收到测试样本后再进行处理。工作机制很简单:
1.分类任务:可使用“投票法”,即选择这K个样本中出现的最多的类别作为预测结果;
2.回归任务:可使用“平均法”,即将K个样本出现的实值输出的标记的平均值作为预测结果;也可以基于距离远近加权平均或加权投票,距离越近的样本权重越大。
在K近邻算法中,当训练集、距离度量(如欧氏距离)、K值的选择及分类决策规则(如“投票法”)确定后,对于任何一个新的输入实例,它所属的类也会唯一的确定。
K值选择过小:
(a)容易受到噪声影响 ;
(b)模型变得复杂,容易过拟合。
K值选择过大:
(a)模型变得简单,欠拟合。
一般使用交叉验证的方法来选取最优的K值。
交叉验证的步骤:
1.将数据集分为n段(如:1,3,5…),每一段再分为训练集和测试集;
2.对这n段的数据进行KNN的训练;
3.将得到的准确率相加再除以n,得到KNN模型训练之后的准确率;
4.比较所有的n(如:1,3,5…),准确率最高的KNN最终的K值选择。
二、代码实现
代码如下
import numpy as np
import pandas as pd
def txt2mat(path):
'''
将txt文件中的数据变为features和label
'''
label = []
with open(path, 'r', encoding = "utf-8") as f:
lines = f.readlines()
feature = np.zeros((len(lines), 3))
for index, it in enumerate(lines):
it = it.strip().split('\t')
feature[index, :] = it[:3]
label.append(it[-1])
assert len(feature) == len(label)
return feature, label
def autoNorm(feature):
'''
标准化
'''
minval = feature.min(0) # 每列的最小值
maxval = feature.max(0) # 每列的最大值
norm_df = np.zeros((len(feature), len(feature)))
norm_df = feature - np.tile(minval, (len(feature), 1))
norm_df = norm_df / np.tile(maxval - minval, (len(feature), 1))
return norm_df
def train(feature, label):
errornum = 0.0
number = int(0.1 * len(feature))
#前number个数据作为测试集,后len(feature)-number个数据作为训练集
for i in range(number):
pri_number = knn(feature[i, :], feature[number:len(feature), :], label[number:len(feature)], 3)
print(f"the classifier came back with:{pri_number},the real answer is:{label[i]}")
if pri_number != label[i]:
errornum += 1.0
print(f"the total error rate is:{errornum / float(number)}")
def knn(inx, features, labels, k):
'''
inx: 需要预测的数组,用的是欧氏距离
'''
datasize = features.shape[0] # 多少行数据,也就是有多少条数据
# np.title(inx, (a, b)) 数组inx在沿行方向复制a次,沿列方向复制b次
# 将数组inx复制和features一样的矩阵,并求出他们之间的差值
# 这一步的意义也就是将数组inx和features中的每条数据求差值
diffmat = np.tile(inx, (datasize, 1)) - features
sqdiffmat = diffmat ** 2
distances = (sqdiffmat.sum(axis = 1)) ** 0.5 # 求和
index_ = distances.argsort() # 将distances的值按照从小到大的顺序将对应的索引输出
# 输出前k个数据的标签以及各个标签占据的总个数
classcount = {}
for i in range(k):
votelabel = labels[index_[i]]
classcount[votelabel] = classcount.get(votelabel, 0) + 1
# 按照value值从大到小进行排序
result = sorted(
classcount.items(),
key = lambda x: x[1],
reverse = True
)
return result[0][0]
if __name__ == "__main__":
feature, label =txt2mat('knn/datingTestSet.txt')
norm_df = autoNorm(feature)
train(norm_df, label)
三、数据链接
四、参考资料
- 《机器学习》,周志华
- 《统计学习方法(第二版)》,李航
- 《机器学习实战》,Peter Harrington