• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
思想人生从关注生活开始
博客园    首页    新随笔    联系   管理    订阅  订阅

K近邻(K-Nearest Neighbors,简称KNN)算法

K近邻(K-Nearest Neighbors,简称KNN)算法是一种基本的机器学习算法,主要用于分类和回归问题。以下是对KNN算法的详细介绍:

1. 定义和原理

定义:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
原理:基于类比原理,通过比较训练元组和测试元组的相似度来学习。具体来说,KNN将训练元组和测试元组看作是n维空间内的点,给定一条测试元组,搜索n维空间,找出与测试元组最相近的k个点(即训练元组),最后取这k个点中的多数类作为测试元组的类别。

2. 关键要素

K值的选择:K是KNN算法中的一个重要参数,表示需要考虑的邻居数量。K值的选择会影响算法的准确性和性能。通常,K值通过实验确定,取分类误差率最小的K值。
距离度量:在KNN算法中,相似度通常通过距离来度量。常用的距离度量方法包括欧几里得距离和曼哈顿距离。
欧几里得距离:两点之间的直线距离,计算公式为d(x,y)=√(∑(xi−yi)^2)。
曼哈顿距离:两点在标准坐标系上的绝对轴距总和,计算公式为d(x,y)=∑|xi−yi|。

3. 算法流程

准备数据:对数据进行预处理,包括数值属性规范化、缺失值处理等。
选用数据结构:选择合适的数据结构存储训练数据和测试元组。
设定参数:设定K值等参数。
搜索最近邻:对于每个测试元组,在训练数据集中搜索最近的K个邻居。
分类:根据K个最近邻的类别标签,通过“少数服从多数”的原则确定测试元组的类别。

4. 优缺点

优点:
简单易懂,易于实现。
无需训练(不需要花费时间构建模型)。
特别适合多分类问题,对异常值不敏感。
缺点:
对K值敏感,K值的选择会影响分类结果。
在高维空间中可能效果不佳,因为距离度量可能失去意义。
需要存储所有训练数据,计算量大。

5. 应用领域

KNN算法被广泛应用于各种领域,如手写数字识别、电影推荐系统、股票市场预测、医学诊断、文本分类、信用评估、图像处理等。

6.Java实现

在Java中实现K近邻(K-Nearest Neighbors, KNN)算法,通常涉及以下几个步骤:
准备数据集:这通常是一个二维数组或对象列表,其中每个对象都有特征向量和标签。
计算距离:对于给定的查询点,计算它与数据集中每个点的距离。
选择K个最近邻:根据计算出的距离,选择K个最近的邻居。
预测:根据K个最近邻的标签进行投票,以确定查询点的类别。
以下是一个简单的Java实现示例:

import java.util.*;

public class KNN {

// 假设数据集是一个二维数组,其中每行是一个样本,每列是一个特征
// 最后一列是标签(例如,对于二分类问题,可以使用0和1作为标签)
private double[][] dataset;

// 构造函数,用于初始化数据集
public KNN(double[][] dataset) {
this.dataset = dataset;
}

// 欧几里得距离
public static double euclideanDistance(double[] point1, double[] point2) {
double sum = 0;
for (int i = 0; i < point1.length; i++) {
sum += Math.pow(point1[i] - point2[i], 2);
}
return Math.sqrt(sum);
}

// 预测查询点的类别
public int predict(double[] query, int k) {
// 初始化一个存储距离和索引的优先级队列(最小堆)
PriorityQueue<DistanceIndex> pq = new PriorityQueue<>(Comparator.comparingDouble(a -> a.distance));

// 计算查询点与数据集中每个点的距离,并将距离和索引添加到最小堆中
for (int i = 0; i < dataset.length; i++) {
double distance = euclideanDistance(query, dataset[i]);
pq.offer(new DistanceIndex(distance, i));

// 如果堆的大小超过了K,则移除堆顶元素(即最远的点)
if (pq.size() > k) {
pq.poll();
}
}

// 创建一个用于存储邻居标签的映射
Map<Integer, Integer> labelCounts = new HashMap<>();

// 对K个最近邻的标签进行计数
while (!pq.isEmpty()) {
DistanceIndex di = pq.poll();
int label = (int) dataset[di.index][dataset[di.index].length - 1]; // 假设最后一列是标签
labelCounts.put(label, labelCounts.getOrDefault(label, 0) + 1);
}

// 找到最常见的标签并返回
int mostCommonLabel = Collections.max(labelCounts.entrySet(), Map.Entry.comparingByValue()).getKey();
return mostCommonLabel;
}

// 用于存储距离和索引的类
static class DistanceIndex {
double distance;
int index;

DistanceIndex(double distance, int index) {
this.distance = distance;
this.index = index;
}
}

// 主函数,用于测试
public static void main(String[] args) {
// 示例数据集(包含特征和标签)
double[][] dataset = {
{2.5, 1.2, 0},
{1.8, 1.1, 0},
{3.0, 4.0, 1},
{5.1, 3.5, 1}
};

KNN knn = new KNN(dataset);

// 示例查询点
double[] query = {1.9, 1.4};

// 使用K=3进行预测
int predictedLabel = knn.predict(query, 3);
System.out.println("Predicted label for query " + Arrays.toString(query) + ": " + predictedLabel);
}
}

 

注意:这个示例假设数据集的最后一列是标签,并且标签是整数(例如,对于二分类问题,可以使用0和1作为标签)。此外,这个示例使用了欧几里得距离作为距离度量,但你可以根据需要选择其他距离度量方法。

 

其他相关文章

常用的搜索算法之二分搜索(Binary Search) 
常用的搜索算法之哈希搜索(Hashing Search)
常用的搜索算法之深度优先搜索 
层次遍历-Level Order Traversal 
常用的搜索算法之线性搜索(Linear Search) 

常用的搜索算法之DFS和BFS的区别是什么 
Java的图数据结构探索-常用的算法快速入门
什么是有向无环图
数据结构进阶面试题-2023面试题库 
常用的搜索算法之迷宫求解问题 
树的基本概念
随机搜索(Random Search) 
网格搜索法(Grid Search)

余弦相似度(Cosine Similarity)
皮尔逊相关系数
曼哈顿距离(Manhattan Distance)
欧氏距离(Euclidean Distance)
Jaccard相似度

修正余弦相似度(Adjusted Cosine Similarity)
皮尔逊χ²检验(Pearson's Chi-squared Test)
互信息(Mutual Information, MI)
Tanimoto系数(Tanimoto Coefficient) 
切比雪夫距离(Chebyshev Distance)
汉明距离(Hamming Distance) 
朴素贝叶斯分类算法(Naive Bayes Classification Algorithm
posted @ 2024-06-10 17:37  JackYang  阅读(682)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3