1.基本概念
k近邻算法:通过测量待预测点和已知点的特征值之间的距离,选取前k个距离近的,根据多数表决的方法来分类。
训练过程:无训练过程。
测试过程:根据距离来分类。
k越小,模型越复杂,越容易过拟合。
需要对各个属性(特征)进行归一化,防止数值较大的属性对分类器的影响过大。
2. 优缺点
优点:精度高,异常值不敏感,对输入格式无要求。
缺点:时间空间复杂度高。无法给出数据的基础结构信息,无法分析数据特征。
适用数据范围:标量和数值型。
3. 常用距离
样本一:x = (x1, x2, ..., xn)
样本二:y = (y1, y2, ..., yn)
欧氏距离:
曼哈顿距离:
距离最大值:
4. 代码实现
参考:《机器学习实战》
源码地址以及数据:https://github.com/JieruZhang/MachineLearninginAction_src
手写python KNN:
from numpy import *
import operator
import matplotlib
import matplotlib.pyplot as plt
#处理文档
def file2mat(file):
f = open(file)
lines = f.readlines()
nums = len(lines)
mat = zeros((nums,3))
classes = []
index = 0
for line in lines:
line = line.strip()
line = line.split('\t')
mat[index,:] = line[0:3]
classes.append(int(line[-1]))
index += 1
return mat, classes
#归一化:由于各个种类特征的数字差异大,例如属性1是百级的,属性2是小数级的,则属性1对距离的影响大。为了使各个特征之间重要性相同,需要归一化。
#归一化方法:new = (old - min)/(max-min),使分布到0和1之间。
def autoNorm(dataSet):
minVals = dataSet.min(0)
maxVals = dataSet.max(0)
ranges = maxVals - minVals
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m,1))
normDataSet = normDataSet/tile(ranges,(m,1))
return normDataSet, ranges, minVals
#分类,计算距离
def classifyKNN(test, dataSet, labels, k):
size = dataSet.shape[0]
#计算距离
distance = (((tile(test, (size,1)) - dataSet)**2).sum(axis=1))**0.5
#距离由短到长排序, 将对应的index存入列表
sortIndices = distance.argsort()
#找到前k个最近的样本对应的类别
classCount = {}
for i in range(k):
label = labels[sortIndices[i]]
#get() 函数返回指定键的值,如果值不在字典中返回默认值。
classCount[label] = classCount.get(label,0) + 1
#将前k个classCount按照value的大小排序
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1), reverse=True)
#返回最大的标签数目对应的标签
return sortedClassCount[0][0]
#测试
def test():
ratio = 0.1
mat, labels = file2mat('datingTestSet.txt')
normMat, ranges, minVals = autoNorm(mat)
m = normMat.shape[0]
numTest = int(m*ratio)
errorCount = 0.0
for i in range(numTest):
res = classifyKNN(normMat[i,:], normMat[numTest:m,:], labels[numTest:m],3)
if res != labels[i]:
errorCount += 1
print('error rate: %f' % (errorCount/float(numTest)))
datingMat, datingLabels = file2mat('datingTestSet.txt')
normMat, ranges, minVals = autoNorm(datingMat)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingMat[:,1], datingMat[:,2], 15.0*array(datingLabels), 15.0*array(datingLabels))
plt.show()
test()
sklearn 实现:
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
def sklearnKNN():
ratio = 0.1
mat, labels = file2mat('datingTestSet.txt')
normMat, ranges, minVals = autoNorm(mat)
m = normMat.shape[0]
numTest = int(m*ratio)
train_mat = normMat[numTest:m,:]
test_mat = normMat[0:numTest,:]
train_labels = labels[numTest:m]
test_labels = labels[0:numTest]
knn = KNeighborsClassifier(n_neighbors = 3)
knn.fit(train_mat, train_labels)
print('error rate is : ', 1 - knn.score(test_mat, test_labels))
sklearnKNN()