更多详细内容参考《机器学习实战》
k-近邻算法简介
简单的说,k-近邻算法采用测量不同特征值之间的距离方法进行分类。它的工作原理是:存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每个数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似(最近邻)数据的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后选择k个相似数据中出现次数最多的分类,作为新数据的分类。
k-近邻算法的一般流程
- 收集数据
- 准备数据
- 分析数据
- 训练算法(此步骤不适用与k-近邻算法)
- 测试算法
- 使用算法
k-近邻算法的的伪代码
对未知类别属性的数据集中的每个点依次进行以下操作:
- 计算已知类别数据集中的点与当前点之间的距离
- 按距离递增次序排列按距离递增次序排列
- 选取与当前点距离最小的k个点
- 确定前k个点所在类别的出现频率
- 返回前k个点出现频率最高的类别作为当前点的预测分类
示例
示例为kaggle上的’Digit Recognizer’,实现数字识别
具体的题目描述和数据集下载可以点击链接Digit Recognizer
代码
from numpy import *
import operator
import csv
def getTrainData(): #获取训练集的数据
with open('D:\\学习\\kaggle\\Digit Recoginzer\\train.csv') as f:
traindata=[]
datafirst=csv.reader(f) #读取csv文件
for row in datafirst: #训练数据放入列表中
traindata.append(row)
traindata.pop(0) #去除第一行文字说明
trainlabel=[] #取出训练标签
for i in traindata:
trainlabel.append(int(i[0]))
i.pop(0)
for i in range(len(traindata)): #把列表中字符类型变成整数类型
for j in range(len(traindata[0])): #同时便于计算,把非零常数改为1
if traindata[i][j]!='0':
traindata[i][j]=1
else:
traindata[i][j]=int(traindata[i][j])
return array(traindata),array(trainlabel)
def getTestData(): #获取测试集数据
with open('D:\\学习\\kaggle\\Digit Recoginzer\\test.csv') as f:
testdata=[]
datafirst=csv.reader(f)
for row in datafirst:
testdata.append(row)
testdata.pop(0)
for i in range(len(testdata)):
for j in range(len(testdata[0])):
if testdata[i][j]!='0':
testdata[i][j]=1
else:
testdata[i][j]=int(testdata[i][j])
return array(testdata)
def classify0(inX,dataSet,labels,k): #inX是一个待分类的测试向量
dataSetSize=dataSet.shape[0] #取出dataSet的行数
#tile把inX整体在行上重复dataSetSize次,列上重复1次(下面代码中) 具体可以自己试一下
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 #累加距离排名前k个中每个标签出现的次数
#把classCount中按标签的出现次数排序
sortedclassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
return sortedclassCount[0][0]
traindata,trainlabel=getTrainData()
testdata=getTestData()
testlabel=[]
for i in testdata:
testlabel.append(classify0(i,traindata,trainlabel,5))
testlabel1=[[i]for i in testlabel]
with open('testlabel.csv','w',newline='') as f: #打开当前路径下的文件
fwriter=csv.writer(f) #返回writer对象
fwriter.writerows(testlabel1) #一行行写入,每行必须是可迭代的对象,所以要把label中每一个int变成列表