当前位置:   article > 正文

近邻算法详解

近邻算法

一、介绍

近邻算法(k-Nearest Neighbors,简称k-NN)是一种常用的机器学习算法,用于分类和回归问题。它的基本思想是根据样本之间的相似性来进行预测。在分类问题中,k-NN算法会将待预测样本的k个最近邻样本的标签进行统计,然后将出现次数最多的标签作为预测结果。在回归问题中,k-NN算法会将待预测样本的k个最近邻样本的标签进行加权平均,然后将得到的平均值作为预测结果。

二、算法步骤

  1. 计算待预测样本与每个训练样本之间的距离。常用的距离度量方法包括欧氏距离、曼哈顿距离等。

  2. 根据距离的大小,选择与待预测样本最近的k个训练样本。

  3. 统计k个最近邻样本中各类别的出现次数(对于分类问题)或计算k个最近邻样本的加权平均(对于回归问题)。

  4. 如果是分类问题,选择出现次数最多的标签作为预测结果;如果是回归问题,将加权平均作为预测结果。

三、优缺点

k-NN算法的优点是简单、易于理解和实现。它不需要进行模型的训练,直接使用训练样本进行预测。因此,k-NN算法适用于数据量较小、特征维度较低的问题。然而,k-NN算法的计算复杂度较高,特别是当训练样本数量较大时,需要计算大量的距离。此外,k-NN算法对于噪声数据较为敏感,因此需要进行数据清洗和特征选择的工作。

四、使用注意

在应用k-NN算法时,需要注意以下几点:

  1. 选择合适的k值:k值的选择会对算法的性能产生影响。较小的k值会使算法对噪声数据更敏感,较大的k值会使算法更加平滑,但可能忽略了局部结构。

  2. 特征归一化:在计算距离时,需要将特征进行归一化,以避免某些特征对距离的计算产生过大的影响。

  3. 处理数据不平衡问题:如果训练样本的类别分布存在不平衡情况,例如某一类样本数量较少,需要对样本进行采样或调整权重,以保证算法的性能。

五、算法实现

1、Python

下面是一个使用Python实现k-NN算法的简单示例:

  1. import numpy as np
  2. from collections import Counter
  3. # 计算两个样本之间的欧氏距离
  4. def euclidean_distance(x1, x2):
  5. return np.sqrt(np.sum((x1 - x2)**2))
  6. # k-NN算法
  7. def k_nearest_neighbors(X_train, y_train, X_test, k):
  8. y_pred = []
  9. for test_sample in X_test:
  10. # 计算测试样本与所有训练样本之间的距离
  11. distances = [euclidean_distance(test_sample, train_sample) for train_sample in X_train]
  12. # 按照距离从小到大排序,并取出前k个样本的索引
  13. k_indices = np.argsort(distances)[:k]
  14. # 根据索引找到对应的标签
  15. k_labels = [y_train[i] for i in k_indices]
  16. # 统计标签出现的次数,选择出现次数最多的标签作为预测结果
  17. most_common = Counter(k_labels).most_common(1)
  18. y_pred.append(most_common[0][0])
  19. return y_pred
  20. # 使用示例
  21. X_train = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
  22. y_train = np.array([0, 0, 1, 1])
  23. X_test = np.array([[2, 3], [6, 7]])
  24. k = 2
  25. y_pred = k_nearest_neighbors(X_train, y_train, X_test, k)
  26. print(y_pred)

上述代码中,我们定义了一个euclidean_distance函数来计算两个样本之间的欧氏距离。然后,我们实现了k_nearest_neighbors函数来执行k-NN算法。在该函数中,我们首先计算测试样本与训练样本之间的距离,然后按照距离排序并取出前k个最近邻样本的索引。接下来,我们根据索引找到对应的标签,并统计出现次数最多的标签作为预测结果。最后,我们使用示例数据对算法进行了简单的测试。

请注意,这只是一个简单示例,实际应用中可能需要考虑更多的因素,如特征归一化、处理数据不平衡等。另外,这里的示例是针对分类问题,如果是回归问题,需要做相应的修改,例如计算加权平均值作为预测结果。

2、Java

以下是一个使用Java实现k-NN算法的简单示例:

  1. import java.util.*;
  2. public class KNN {
  3. // 计算两个样本之间的欧氏距离
  4. public static double euclideanDistance(double[] x1, double[] x2) {
  5. double sum = 0.0;
  6. for (int i = 0; i < x1.length; i++) {
  7. sum += Math.pow(x1[i] - x2[i], 2);
  8. }
  9. return Math.sqrt(sum);
  10. }
  11. // k-NN算法
  12. public static int[] kNearestNeighbors(double[][] X_train, int[] y_train, double[][] X_test, int k) {
  13. int[] y_pred = new int[X_test.length];
  14. for (int i = 0; i < X_test.length; i++) {
  15. double[] test_sample = X_test[i];
  16. // 计算测试样本与所有训练样本之间的距离
  17. double[] distances = new double[X_train.length];
  18. for (int j = 0; j < X_train.length; j++) {
  19. distances[j] = euclideanDistance(test_sample, X_train[j]);
  20. }
  21. // 按照距离从小到大排序,并取出前k个样本的索引
  22. int[] k_indices = new int[k];
  23. for (int j = 0; j < k; j++) {
  24. k_indices[j] = j;
  25. }
  26. for (int j = k; j < distances.length; j++) {
  27. double maxDistance = distances[k_indices[0]];
  28. int maxIndex = 0;
  29. for (int l = 1; l < k; l++) {
  30. if (distances[k_indices[l]] > maxDistance) {
  31. maxDistance = distances[k_indices[l]];
  32. maxIndex = l;
  33. }
  34. }
  35. if (distances[j] < maxDistance) {
  36. k_indices[maxIndex] = j;
  37. }
  38. }
  39. // 根据索引找到对应的标签
  40. int[] k_labels = new int[k];
  41. for (int j = 0; j < k; j++) {
  42. k_labels[j] = y_train[k_indices[j]];
  43. }
  44. // 统计标签出现的次数,选择出现次数最多的标签作为预测结果
  45. Map<Integer, Integer> labelCounts = new HashMap<>();
  46. for (int label : k_labels) {
  47. labelCounts.put(label, labelCounts.getOrDefault(label, 0) + 1);
  48. }
  49. int mostCommon = -1;
  50. int maxCount = -1;
  51. for (Map.Entry<Integer, Integer> entry : labelCounts.entrySet()) {
  52. if (entry.getValue() > maxCount) {
  53. mostCommon = entry.getKey();
  54. maxCount = entry.getValue();
  55. }
  56. }
  57. y_pred[i] = mostCommon;
  58. }
  59. return y_pred;
  60. }
  61. // 使用示例
  62. public static void main(String[] args) {
  63. double[][] X_train = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
  64. int[] y_train = {0, 0, 1, 1};
  65. double[][] X_test = {{2, 3}, {6, 7}};
  66. int k = 2;
  67. int[] y_pred = kNearestNeighbors(X_train, y_train, X_test, k);
  68. for (int label : y_pred) {
  69. System.out.println(label);
  70. }
  71. }
  72. }

上述代码中,我们定义了一个euclideanDistance方法来计算两个样本之间的欧氏距离。然后,我们实现了kNearestNeighbors方法来执行k-NN算法。在该方法中,我们首先计算测试样本与训练样本之间的距离,然后按照距离排序并取出前k个最近邻样本的索引。接下来,我们根据索引找到对应的标签,并统计出现次数最多的标签作为预测结果。最后,我们使用示例数据对算法进行了简单的测试。

请注意,这只是一个简单示例,实际应用中可能需要考虑更多的因素,如特征归一化、处理数据不平衡等。另外,这里的示例是针对分类问题,如果是回归问题,需要做相应的修改,例如计算加权平均值作为预测结果。

3、MATLAB

以下是一个使用MATLAB实现k-NN算法的简单示例:

  1. function y_pred = k_nearest_neighbors(X_train, y_train, X_test, k)
  2. % 计算两个样本之间的欧氏距离
  3. euclidean_distance = @(x1, x2) sqrt(sum((x1 - x2).^2));
  4. % 初始化预测结果数组
  5. y_pred = zeros(size(X_test, 1), 1);
  6. % 对每个测试样本进行预测
  7. for i = 1:size(X_test, 1)
  8. test_sample = X_test(i, :);
  9. % 计算测试样本与所有训练样本之间的距离
  10. distances = zeros(size(X_train, 1), 1);
  11. for j = 1:size(X_train, 1)
  12. distances(j) = euclidean_distance(test_sample, X_train(j, :));
  13. end
  14. % 按照距离从小到大排序,并取出前k个样本的索引
  15. [~, k_indices] = mink(distances, k);
  16. % 根据索引找到对应的标签
  17. k_labels = y_train(k_indices);
  18. % 统计标签出现的次数,选择出现次数最多的标签作为预测结果
  19. label_counts = histcounts(k_labels, unique(y_train));
  20. [~, max_idx] = max(label_counts);
  21. y_pred(i) = label_counts(max_idx);
  22. end
  23. end
  24. % 使用示例
  25. X_train = [1 2; 3 4; 5 6; 7 8];
  26. y_train = [0; 0; 1; 1];
  27. X_test = [2 3; 6 7];
  28. k = 2;
  29. y_pred = k_nearest_neighbors(X_train, y_train, X_test, k);
  30. disp(y_pred);

上述代码中,我们定义了一个匿名函数euclidean_distance来计算两个样本之间的欧氏距离。然后,我们实现了k_nearest_neighbors函数来执行k-NN算法。在该函数中,我们首先计算测试样本与训练样本之间的距离,然后按照距离排序并取出前k个最近邻样本的索引。接下来,我们根据索引找到对应的标签,并统计出现次数最多的标签作为预测结果。最后,我们使用示例数据对算法进行了简单的测试。

请注意,这只是一个简单示例,实际应用中可能需要考虑更多的因素,如特征归一化、处理数据不平衡等。另外,这里的示例是针对分类问题,如果是回归问题,需要做相应的修改,例如计算平均值作为预测结果。

六、同类算法代码对照

以下是一个使用Python实现k-NN算法和其他常见近邻算法(包括最近邻、半径最近邻、KD树)的代码对比:

  1. from sklearn.neighbors import KNeighborsClassifier, NearestNeighbors, RadiusNeighborsClassifier, KDTree
  2. from sklearn.datasets import load_iris
  3. from sklearn.model_selection import train_test_split
  4. from sklearn.metrics import accuracy_score
  5. # 加载鸢尾花数据集
  6. iris = load_iris()
  7. X = iris.data
  8. y = iris.target
  9. # 划分数据集
  10. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
  11. # k-NN算法
  12. knn = KNeighborsClassifier(n_neighbors=3)
  13. knn.fit(X_train, y_train)
  14. y_pred_knn = knn.predict(X_test)
  15. accuracy_knn = accuracy_score(y_test, y_pred_knn)
  16. # 最近邻算法
  17. nn = NearestNeighbors(n_neighbors=3)
  18. nn.fit(X_train)
  19. distances, indices = nn.kneighbors(X_test)
  20. # 半径最近邻算法
  21. rnn = RadiusNeighborsClassifier(radius=1.0)
  22. rnn.fit(X_train, y_train)
  23. y_pred_rnn = rnn.predict(X_test)
  24. accuracy_rnn = accuracy_score(y_test, y_pred_rnn)
  25. # KD树算法
  26. tree = KDTree(X_train)
  27. distances, indices = tree.query(X_test, k=3)
  28. print("k-NN Accuracy:", accuracy_knn)
  29. print("Radius Neighbors Accuracy:", accuracy_rnn)

在上述代码中,我们首先使用sklearn库加载了鸢尾花数据集,并将数据集划分为训练集和测试集。然后,我们分别使用KNeighborsClassifierNearestNeighborsRadiusNeighborsClassifierKDTree实现了k-NN、最近邻、半径最近邻和KD树算法。接着,我们使用训练集拟合模型,并使用测试集进行预测。最后,我们使用accuracy_score计算了每个算法的准确率,并输出结果进行对比。

请注意,这里只是一个简单示例,实际应用中可能需要根据具体问题选择合适的算法,并进行参数调优和性能评估。

总结来说,k-NN算法是一种简单而有效的机器学习算法,适用于小规模和低维度的问题。它的原理简单,但需要注意调整参数和处理数据不平衡问题。

##欢迎关注交流,开发逆商潜力,提升个人反弹力:

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/767085
推荐阅读
相关标签
  

闽ICP备14008679号