- 原理
测量不同特征值之间的距离来进行分类
优点:精度高,对异常值不敏感,无数据输入假定
缺点:计算复杂度高,空间复杂度高
适用数据类型:数值型,标称型
2. 面试题
- knn三要素:k值选择;距离度量(欧式距离,马氏距离);分类决策规则(多数表决规则)
- k值选择:k值越小模型越复杂,更容易过拟合;k值越大,模型越简单,当k=N时,无论什么样本都会属于训练集中类别最多的那个类
- 优缺点 优点:思想简单,理论成熟,既可以分类又可以回归;可用于非线性分类;时间复杂度为O(n);准确率高,对数据没有假设,对异常值不敏感 缺点:计算量大;样本不平衡问题;需要大量内存
- kd树,存储数据,快速计算距离,并且在数据量大的时候可以只计算部分数据的距离(后面详细补充)
3. 实现
算法流程:
- 收集数据
- 准备数据:距离计算需要数值,结构化的数据格式
- 分析数据
- 测试算法:计算错误率
- 使用算法
算法实现(算法伪代码):使用k近邻算法将每组数据划分到某个类中:
- 对每个数据一次进行以下操作:
- 计算已知类别数据集中的点与当前点之间的距离;
- 按照距离递增次序排序;
- 选取与当前点距离最小的k个点;
- 确定前k个点所在类别的出现频率;
- 返回前k个点出现频率最高的类别作为当前点的预测分类。
4.项目练习
手写体识别
from numpy import *
import os
import operator
#将图片转换成向量
#knn算法,通过计算距离,来进行分类
def classify0(inX,dataSet,labels,k):
dataSetSize = dataSet.shape[0]
diffMat= tile(inX,(dataSetSize,1))-dataSet
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5 #计算欧式距离
sortedDistIndicies = distances.argsort() #排序
classCount={}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
def img2vector(filename):
returnVect=zeros((1,1024)) #返回32*32=1024维向量
fr = open(filename)
for i in range(32): #读取每一行
linsStr = fr.readline()
for j in range(32):
returnVect[0,32*i+j]=int (linsStr[j]) #依次按列存储 按行不行吗?
return returnVect
def handwritingTest():
hwLabels = []
trainingFileList = os.listdir('trainingDigits')
m = len(trainingFileList)
trainingMat = zeros((m,1024))
for i in range(m):
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0]
classNumStr = int(fileStr.split('_')[0])
hwLabels.append(classNumStr)
trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
testFileList = os.listdir('testDigits')
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0]
fileStr = fileNameStr.split('.')[0]
classNumStr = int(fileStr.split('_')[0])
testMat= img2vector('trainingDigits/%s' % fileNameStr)
calssifierResult = classify0(testMat,trainingMat,hwLabels,4)
print("the classifer came back with :%d, the real answer is %d" %(calssifierResult,classNumStr))
if calssifierResult!=classNumStr:
errorCount+=1
print("\n the total number of errors is :%d" %errorCount)
print("\n the total errors rate is :%f" %(errorCount/float(mTest)))
handwritingTest()