一:介绍
邻近算法,或者说K最邻近(K-Nearest Neighbor)分类算法是数据挖掘分类技术中最简单的算法之一。所谓K最邻近,就是K个最近的邻居的意思。
二:核心思想
如果一个样本在特征空间中的K个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并且具有这个类别样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 KNN方法在类别决策时,只与极少量的相邻样本有关。由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
三:代码示例
opencv-python中的KNN算法
import numpy as np
import matplotlib.pyplot as plt
import cv2
import math
'''
使用OpenCV中的KNN算法,必须要求.astype(np.float32)
'''
# 包含25个训练数据(x,y)的训练集
trainData = np.random.randint(0,100,size=(25,2)).astype(np.float32)
# 标记红蓝色,红色:0 ,蓝色:1
mark = np.random.randint(0,2,size=(25,1)).astype(np.float32)
# 标记红色
red = trainData[mark.ravel() == 0] # ravel(): 将高维数组降为一维数组
# 标记蓝色
blue = trainData[mark.ravel() == 1]
# 绘制散点图
plt.scatter(red[:,0],red[:,1],80,'r','^')
plt.scatter(blue[:,0],blue[:,1],80,'b','s')
# 新元素
newcomer = np.random.randint(0,100,size=(1,2)).astype(np.float32)
plt.scatter(newcomer[:,0],newcomer[:,1],80,'g')
plt.show()
# OpenCV--KNN算法
knn = cv2.ml.KNearest_create()
knn.train(trainData,cv2.ml.ROW_SAMPLE,mark)
ret,result,neighbours,distance = knn.findNearest(newcomer,3)
# 将result[0][0]传入,用于判断新成员所属的家族
def red_or_blue(x):
error = math.e**-5
if math.fabs(x) < error:
return 'red家族'
else:
return 'blue家族'
print('新成员属于 : '+red_or_blue(result[0][0]))
print('result : '+str(result))
print('邻居 : '+str(neighbours))
print('距离 : '+str(distance))
KNN算法
下面这个KNN算法是小编自己实现的,希望对大家有用,如果有错误的地方,望大家可以指出。
import numpy as np
import matplotlib.pyplot as plt
import math
'''
KNN算法:k-NearestNeighbor
'''
# 设置保留小数点后2位 针对numpy数组
np.set_printoptions(2)
# 训练集
trainData = np.random.randint(0,100,size=(25,2))
# 分为2个家族,分别用0,1标记
mark = np.random.randint(0,2,size=(25,1))
# 红蓝分组并画图
red = trainData[mark.ravel() == 0]
blue = trainData[mark.ravel() == 1]
plt.scatter(red[:,0],red[:,1],80,'r','^')
plt.scatter(blue[:,0],blue[:,1],80,'b','s')
# 新成员(待分类的元素)
newcomer = np.random.randint(0,100,size=(1,2))
plt.scatter(newcomer[:,0],newcomer[:,1],80,'g')
plt.show()
# 分类函数 返回一个二维数组 [[分类结果],[邻居],[距离]]
def classify(train_data,mark_data,new_data,k):
# 距离数组,存放各点到newcomer的距离
distance = []
# 计算各点到newcomer的距离
for i in range(0,int(train_data.size/2)):
dd = (train_data[i][0] - new_data[0][0])**2 + (train_data[i][1] - new_data[0][1])**2
d = math.sqrt(dd)
distance.append(d)
arg_sort_index = np.array(distance).argsort() # argsort()返回的是数组值从小到大的索引值
red_count = 0
blue_count = 0
mark_data = np.array(mark_data).ravel() # 降为一维数组
k_calssify = [] # 存放前k个邻居
k_dist = [] # 存放前k个邻居与其的距离
# 统计前k个邻近邻居中各类别的数量
for i in range(0,k):
k_calssify.append(mark_data[arg_sort_index[i]])
k_dist.append(distance[arg_sort_index[i]])
# 如果mark_data[arg_sort_index[i]]==0
if math.fabs(mark_data[arg_sort_index[i]]) < math.e**-5:
red_count = red_count + 1
else:
blue_count = blue_count + 1
if red_count > blue_count:
return ['red',k_calssify,k_dist]
else:
return ['blue',k_calssify,k_dist]
result,neighbors,dist = classify(trainData,mark,newcomer,3)
print('所属家族 : '+str(result))
print('邻居 : '+str(neighbors))
print('距离 : '+str(np.array(dist)))
四:算法改进
当样本不平衡时,比如:一个类(A)的样本容量非常大,而其它类(B、C)样本容量非常小时,有可能导致输入一个新样本时,该样本的K个邻居中A占多数。此时可以采用分配权值的方法来改进(如:权值与距离成反比)。