持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30天,点击查看活动详情
KNN (K-NearestNeighbor) K指K个邻居
(1)正如物以类聚,人以群居。越是相似的东西就越有可能是一类东西。从这张图片来看,判断Xu属于那种类别,可以取Xu最近的K个邻居(距离),在这个K个点中,那一类东西的概率最高,就把他定位为那个类别。
其中距离的求解:
曼哈顿距离:
欧氏距离:(多维空间)
KNN算法最简单粗暴的就是将预测点与所有点距离进行计算,然后保存并排序,选出前面K个值看看哪些类别比较多。
(2)应用
比如在电商中,可以根据消费者选择的东西去推荐他们可能感兴趣的的商品,还可以在一些网站可以看到相似用户这些。
代码:
1.aff内容解读
在aff文件中有3种类型的花(山鸢尾(Iris-setosa),变色鸢尾(Iris-versicolor),维吉尼亚鸢尾(Iris-virginica)),每一个花类有50个数据,每条记录有 4 项特征(花萼长度、花萼宽度、花瓣长度、花瓣宽度) 2.步骤
(1)解析文本内容,获取数据集
(2)根据获取的数据集划分训练集和测试集,在分割数据集时打乱数据索引位置,以保证在取数时更有说服性
(3)对测试集数据进行预测:对每个测试数据,取他的k个邻居,这k个邻居时距离这个测试数据最近得k个点(计算距离用的欧式距离)
(4)取出的K个邻居,判断每个邻居属于哪一类型的
(5)测试其准确度
kNN 分类器 (续)
重新实现 computeNearests, 仅需要扫描一遍训练集, 即可获得 k 个邻居
分析:
扫描一次训练集,当时我第一想法是先扫描训练集,计算测试点到训练集的距离并用距离数组进行存储,在对距离数组进行插入排序获取前k个数据,但是这样并不满足时间复杂度的要求,后面对其进行改进,在计算距离的同时对数据进行排序,这样就满足要求了(因为这个方法返回的邻居,这里借助了一个数组来存储训练集的索引并与距离数组一一对应)。经过测试,符合要求。
当时想着不用两个数组来做,用 List<Map<Integer,Double>> distance = new ArrayList<>(),键值对的形式,但是发现这个在进行交换数据比较麻烦,故放弃了。
public int[] computeNearestsNew(int paraCurrent) {
int[] resultNearests = new int[numNeighbors];
int[] trainingIndex = new int[trainingSet.length];
double[] trainingDistance = new double[trainingSet.length];
int j;
double tempData;
//在计算距离的同时进行插入排序
for (int i = 0; i < trainingSet.length; i++) {
trainingDistance[i] = distance(paraCurrent, trainingSet[i]);
tempData = trainingDistance[i];
for (j = i-1; j >= 0 && trainingDistance[j] > tempData; j--) {
trainingDistance[j+1] = trainingDistance[j];
trainingIndex[j+1] = trainingIndex[j];
}
trainingDistance[j+1] = tempData;
trainingIndex[j+1] = i;
}
//获取前面k个邻居
for (int i = 0; i < numNeighbors; i++) {
resultNearests[i] = trainingSet[trainingIndex[i]];
}
System.out.println("The nearest of " + paraCurrent + " are: " + Arrays.toString(resultNearests));
return resultNearests;
}