算法思想
一个样本与数据集中的k个样本最相似, 如果这k个样本中的大多数属于某一个类别, 则该样本也属于这个类别。
距离度量
在选择两个样本相似性时,一般使用的欧式距离Lp距离定义:
流程
1) 计算已知类别数据集中的点与当前点之间的距离
2) 按距离递增次序排序
3) 选取与当前点距离最小的k个点
4) 统计前k个点所在的类别出现的频率
5) 返回前k个点出现频率最高的类别作为当前点的预测分类
优点:
1、简单有效
2、适用大样本自动分类
缺点:
1、类别分类不标准化
2、不均衡性
3、计算量较大
k值选择
近似误差:对现有训练集的训练误差,值小会过拟合。
估计误差:对测试集的测试误差,值小说明对未知数据的预测能力好。
如果选择较小的K值,就相当于用较小的邻域中的训练样本进行预测。近似误差小,估计误差大。如果邻近的实例点恰巧是噪声,预测就会出错。
如果选择较大K值,就相当于用较大邻域中的训练实例进行预测。估计误差小,近似误差大。
在应用中,K值一般取一个比较小的数值,通常采用交叉验证法来选取最优的K值。
交叉验证法:将数据集划分为 N个大小相似的互斥子集,并且尽量保证每个子集数据分布的一致性。这样,就可以获取 N组训练 - 测试集,从而进行 N 次训练和测试。
应用例:电影分类
import math
movie_data = {"宝贝当家": [45, 2, 9, "喜剧片"],
"美人鱼": [21, 17, 5, "喜剧片"],
"澳门风云3": [54, 9, 11, "喜剧片"],
"功夫熊猫3": [39, 0, 31, "喜剧片"],
"谍影重重": [5, 2, 57, "动作片"],
"叶问3": [3, 2, 65, "动作片"],
"伦敦陷落": [2, 3, 55, "动作片"],
"我的特工爷爷": [6, 4, 21, "动作片"],
"奔爱": [7, 46, 4, "爱情片"],
"夜孔雀": [9, 39, 8, "爱情片"],
"代理情人": [9, 38, 2, "爱情片"],
"新步步惊心": [8, 34, 17, "爱情片"]}
# 测试样本 唐人街探案": [23, 3, 17, "?片"]
#下面为求与数据集中所有数据的距离代码:
x = [23, 3, 17]
KNN = []
for key, v in movie_data.items():
d = math.sqrt((x[0] - v[0]) ** 2 + (x[1] - v[1]) ** 2 + (x[2] - v[2]) ** 2)
KNN.append([key, round(d, 2)])
# 输出所用电影到 唐人街探案的距离
print(KNN)
#按照距离大小进行递增排序
KNN.sort(key=lambda dis: dis[1])
#选取距离最小的k个样本,这里取k=5;
KNN=KNN[:5]
print(KNN)
#确定前k个样本所在类别出现的频率,并输出出现频率最高的类别
labels = {"喜剧片":0,"动作片":0,"爱情片":0}
for s in KNN:
label = movie_data[s[0]]
labels[label[3]] += 1
labels =sorted(labels.items(),key=lambda l:
l[1],reverse=True)
print(labels,labels[0][0],sep='\n')