KNN-K近邻分类算法
作为机器学习入门的算法之一,其数学原理很简单
原理:
即对于测试样本点,寻找与其距离最近的K个样本点,以这K个点的类别作为参考依据,用来判定测试样本点的类别
其中K的取值一般为奇数(3,5,7....等),它是一种基于实例的学习,使用算法时必须有接近实际数据的训练样本。
优点:
1.新数据可以加入数据集而无需再次训练
2.理论简单,易于实现
缺点:
1.必须保存全部数据,对于样本容量大的数据集计算量较大
2.KNN每一次分类都会进行一次全局计算
3.样本不平衡时,计算偏差大
4.K值的大小需要人为选择
5.忽略了样本数据之间的内在联系
如何选择k的值:
- K值较小就相当于用较小的领域中的训练实例进行预测,“学习”近似误差会减小,只有与输入实例较近或相似的训练实例才会对预测结果起作用,与此同时带来的问题是“学习”的估计误差会增大,换句话说,K值的减小就意味着整体模型变得复杂,容易发生过拟合;
- K值较大可以减少学习的估计误差,但是学习的近似误差会增大,与输入实例较远的训练实例也会对预测起作用,使预测发生错误,k值增大模型的复杂度会下降。
- 在应用中,k值一般取一个比较小的值,通常采用交叉验证法来来选取最优的K值。
Python代码如下:
import numpy as np
import operator
import matplotlib.pyplot as plt
# KNN
def KNN(x_test, dataSet, labels, k):
m = len(dataSet)
diff = dataSet - np.tile(x_test, (m,1))
distance = np.sqrt((diff**2).sum(axis=1))
sortedDist = distance.argsort() # 对数字从小到大排序,返回索引值
classCount= {}
for i in range(k):
voteIlabel = labels[sortedDist[i]]
if voteIlabel not in classCount.keys():
classCount[voteIlabel] = 0
classCount[voteIlabel] += 1
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # 对字典的keys按照value值从大到小排序
return sortedClassCount[0][0]
# Load dataset
def createdataset(filename):
fr = open(filename).readlines()
x_Mat = [];y_Mat =[]
for line in fr:
data = [float(example) for example in line.strip().split('\t')]
x_Mat.append(data[:-1])
y_Mat.append(data[-1])
return np.array(x_Mat), np.array(y_Mat)
# Normalization
def autoNorm(dataSet):
minvalue = np.min(dataSet, axis=0)
maxvalue = np.max(dataSet, axis=0)
ranges = maxvalue - minvalue
normDataSet = (dataSet - minvalue)/ranges
return normDataSet, minvalue, ranges
# Test
def datingClassTest():
x_Mat, y_Mat = createdataset('datingTestSet2.txt')
m = len(x_Mat)
# 使用Matplotlib绘制原始数据的散点图
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(x_Mat[:, 0], x_Mat[:, 1], 15.0*np.array(y_Mat), 15.0*np.array(y_Mat))
plt.show()
# 前90%的数据作为训练集,后10&用于测试
train_x, train_y = x_Mat[:int(m*0.9), :], y_Mat[:int(m*0.9)]
test_x, test_y = x_Mat[int(m*0.9):m, :], y_Mat[int(m*0.9):m]
normDataSet, minvalue, ranges = autoNorm(train_x)
test_x = (test_x - minvalue)/ranges
errorCount = 0
for i in range(len(test_x)):
result = KNN(test_x[i], normDataSet, train_y, k=3)
print("the classifier came back with: %d, the real answer is: %d" % (result, test_y[i]))
if result != test_y[i]: errorCount += 1
print("The number of errr is: %d" % int(errorCount))
print("The total error rate is: %f" % (errorCount / float(len(test_x))))
if __name__ == '__main__':
datingClassTest()