文章目录

  • 前言
  • 一、K是什么?
  • 二、算法步骤
  • 三、缺点
  • 四、代码实现
  • 五、测试结果

前言

邻近算法,或者说K最邻近(KNN,K-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一。

该方法的思路非常简单直观:根据其最近的K个样本的分类确定它自身类别的分类算法。

一般来说在计算距离时,可以使用他们之间的直线距离即欧氏距离,或坐标绝对值之和,即曼哈顿距离。

一、K是什么?

所谓K最近邻,就是K个最近的邻居的意思,说的是每个样本都可以用它最接近的K个邻近值来代表。

K的取值非常重要。

K太小:受到个例影响严重,波动较大。
K太大:受到距离较远数据影响,分类模糊。

K的取值受数据集大小影响。一般需要反复尝试,根据经验调整或者使用均方根误差来选取。

二、算法步骤

  1. 计算新样本和所有样本之间的距离。
  2. 按照由小到大排序。
  3. 根据K值选取取前K个样本。
  4. 加权平均。(计算总距离D以及目标到这个样本的距离d,knn可以判断序列相似吗 knn算法的k如何确定_机器学习

三、缺点

  1. 数据越多计算量越大,效率越低。
  2. 难以运用到较大的数据集中。

四、代码实现

  1. 导入必要的库:
import numpy as np
  1. KNN实现:
class KNN(object):
   def __init__(self, data, targets, k, distance='E'):
       # 'E' 欧氏距离
       # 'M' 曼哈顿距离
       self.targets = targets
       self.data = data
       # data = [[x1,x2,x3,x4,y]]
       self.k = k
       self.result = []
       self.maxDistance = []
       distance = distance.upper()
       if distance == 'E' or distance == 'M':
           self.way = distance
       else:
           raise Exception("未定义的距离公式")

   def __distance(self, target):
       distances = []
       if self.way == 'E':
           for i in self.data:
               diff = i[:-1] - target
               distance = np.sum(np.power(diff, 2))
               distances.append((distance, i))
       else:
           for i in self.data:
               diff = i[:-1] ** 2 ** 0.5 - target ** 2 ** 0.5
               distance = np.sum(diff)
               distances.append((distance, i))
       return distances

   def classify(self):
       for target in self.targets:
           distances = self.__distance(target)
           neighbors = sorted(distances, key=lambda distances: distances[0])[:self.k]
           total_distance = 0
           for distance in neighbors:
               total_distance += distance[0]

           weights = {}
           for item in neighbors:
               if item[1][-1] not in weights:
                   weights[item[1][-1]] = 1 - (item[0] / total_distance)
               else:
                   weights[item[1][-1]] += 1 - (item[0] / total_distance)
           maxValue = 0
           res = None
           for key in weights.keys():
               if weights.get(key) > maxValue:
                   res = key
                   maxValue = weights.get(key)
           self.result.append(res)
           self.maxDistance.append(neighbors[self.k - 1][0] ** 0.5)
  1. 绘制分类图(二维情况下):
def plotKNN(classifier):
   colors = ['r', 'g', 'b', 'c', 'm', 'y', 'k']
   figure, axes = plt.figure(), plt.gca()
   for i in range(len(classifier.data)):
       x = np.array([classifier.data[i][0]])
       y = np.array([classifier.data[i][1]])
       plt.plot(x, y,
                color=colors[int(classifier.data[i][-1])],
                marker='o',  # 点的形状为圆点
                ms=7,
                linestyle='')  # 线型为空,也即点与点之间不用线连接

   for i in range(len(classifier.targets)):
       x = np.array([classifier.targets[i][0]])
       y = np.array([classifier.targets[i][1]])
       plt.plot(x, y,
                color=colors[int(classifier.result[i])],
                marker='*',  # 点的形状为星形
                ms=20,
                linestyle='')  # 线型为空,也即点与点之间不用线连接
       circle = plt.Circle((x[0], y[0]), classifier.maxDistance[i], fill=False,
                           color=colors[int(classifier.result[i])])
       axes.add_patch(circle)

   plt.axis('equal')
   plt.grid(True)
   plt.title("KNN")
   plt.show()
  1. 测试及评估:
import random
import numpy as np
from KNN import KNN
import csv

if __name__ == '__main__':
   data = []
   classification = {'M': 1, 'B': 0}
   with open('E:\\ML\\dataset\\prostate-cancer\\Prostate_Cancer.csv', 'r') as f:
       f_csv = csv.reader(f)
       header = next(f_csv)
       for row in f_csv:
           row.append(classification[row[1]])
           del row[1]
           del row[0]
           data.append(np.array(row, dtype='float64'))

   random.shuffle(data)
   n = len(data) // 3
   test_data = data[:n]
   test_data_labels = []
   for i in range(len(test_data)):
       test_data_labels.append(test_data[i][-1])
       test_data[i] = test_data[i][:-1]
   train_data = data[n:]

   # 测试
   correct = 0
   incorrect = 0

   classifier = KNN(train_data, test_data, 5, 'E')
   classifier.classify()
   result = classifier.result

   # 62个M,38个B

   for i in range(len(test_data)):
       if test_data_labels[i] == result[i]:
           correct += 1
       else:
           incorrect += 1
   print("Correct: " + str(correct))
   print("Incorrect: " + str(incorrect))
   print("AC Rate: {:.2f}%".format(100 * (correct/(correct + incorrect))))

五、测试结果

knn可以判断序列相似吗 knn算法的k如何确定_数据挖掘_02