最近在看《机器学习实战》这本书,书中的机器学习算法都很经典,写的也很详细,是一本不错的书,适合夯实基础,不过有一点缺陷就是书中使用的Python2的编译器代码,多多少少会与当前主流的Python3有些出入,所以小编在看书之余也准备将本书中的代码重新敲一遍到Python3,一起学习,一起进步,本栏目持续更新,知道本博主看完敲完这本书。
K-近邻算法的概述
k-近邻算法说到底,就是求取待测试数据向量与所有已知标签数据向量的二范数,也就是两向量之间的距离,从而通过得到大量样本数据中与之最接近的那一点,从而以此标准求出待测试数据的标签。选用机器学习实战里面电影的例子:
电影名称 | 打斗镜头 | 接吻镜头 | 电影类型 |
California Man | 3 | 104 | 爱情片 |
He's Not Really into Dudes | 2 | 100 | 爱情片 |
Beautiful Woman | 1 | 81 | 爱情片 |
Kevin Longblade | 101 | 10 | 动作片 |
Robo Slayer 3000 | 99 | 5 | 动作片 |
Amped 2 | 98 | 2 | 动作片 |
? | 18 | 90 | 未知 |
从上表的数据中我们可以看到电影有两个特征(feature),分别是打斗镜头和接吻镜头,所以我们求取未知电影的这两个特征与标签化的样本数据特征向量的距离,距离最短也便是最相似的,所以很显然这部待定电影是爱情电影。这就是k-近邻算法的思想,很形象,也很容易理解。
电影名称 | 与未知电影的距离 |
California Man | 20.5 |
He's Not Really into Dudes | 18.7 |
Beautiful Woman | 19.2 |
Kevin Longblade | 115.3 |
Robo Slayer 3000 | 117.4 |
Amped 2 | 118.9 |
算法代码详解
1.k-近邻算法的一般流程(将书中的流程精简了一下)
(1)收集和处理数据:将数据进行结构化,变成代码可处理的数据结构
(2)分析数据:通过算法进行数据分析,本文使用的是k-近邻算法
(3)训练算法:由于k-近邻算法无需训练,所以本文不使用训练算法
(4)测试算法:用来测试准确度
2.收集和处理数据
#本代码之前需要添加:import numpy as np
link = {'didntLike':1,'smallDoses':2,'largeDoses':3} #将喜欢程度按数字分级
def file2matrix(filename): #将.txt文件中的数据转换为数据矩阵的形式
with open(filename) as fr:
arrayolines = fr.readlines(); #将文件数据读取为一个列表后进行处理
lengthOfdata = len(arrayolines) #获取样本的数量
ReturnMat = np.zeros((lengthOfdata,3)); #初始化数据矩阵
labels = [] #初始化标签列表
index = 0
for line in arrayolines:
line = line.strip() #去除头尾的空格
arrayfromline = line.split('\t') #按照空格分离成一个新的向量
ReturnMat[index,:] = arrayfromline[0:3] #更新数据矩阵
labels.append(link[arrayfromline[-1]]) #更新标签列表
index += 1 #索引自增,以便更新下一行的数据矩阵
return ReturnMat,labels
3.分析数据
首先为了使不同特征的数据对结果的影响有相同的效果,我们需要对数据进行归一化,归一化的公式是:
def autoNorm(dataset): #数据归一化
minVals = dataset.min(0) #获取最小值
maxVals = dataset.max(0) #获取最大值
range = maxVals-minVals #获得max-min
length = dataset.shape[0] #获得矩阵的行数
normDataSet = (dataset - np.tile(minVals,(length,1)))/np.tile(range,(length,1))
return normDataSet
然后使用K-近邻算法进行分析
def knn_classfy(inx,Dataset,labels,k):
#inx:需要进行分类的数据 Dataset:给出的标签化数据集 labels:Dataset对应的标签 k:取出前k个距离最短的点
DataSetSize = Dataset.shape[0] #获取数据集样本的个数
ErrorData = np.tile(inx,(DataSetSize,1))-Dataset #将inx的行向量重复堆叠至与数据集样本维数相同,并且与数据集矩阵相减开始计算距离
sqErrorData = ErrorData**2 #将相减的矩阵平方
sqDistance = sqErrorData.sum(axis=1) #算出平方和
Distance = sqDistance**0.5 #计算出了inx与每个样本的距离
sortindex = Distance.argsort() #将距离矩阵进行排序
classcount = [] #初始化距离排完序的矩阵
for i in range(k):
classcount.append(labels[sortindex[i]]) #将距离最短的K个数据的标签存入classcount
return classcount[0] #返回预测出的inx的标签
4.测试数据
def dataTest(): #测试函数
testper = 0.1
dataset,labels = file2matrix('datingTestSet.txt') #获得处理好的数据与标签
NumOfData = dataset.shape[0]
NumOfTest = int(testper*NumOfData) #取前10%作为测试数据
NormDataSet = autoNorm(dataset) #将数据归一化
errorcount = 0.0
for i in range(NumOfTest): #取前百分之十进行测试
knn_classfy_result = knn_classfy(NormDataSet[i,:],NormDataSet[NumOfTest:NumOfData,:],labels[NumOfTest:NumOfData],3)
print("the classifier came back with : %s,the real answer is: %s" % (knn_classfy_result,labels[i]))
if(knn_classfy_result != labels[i]): errorcount += 1.0
print("the total error rate id : %f",(errorcount/float(NumOfTest)))
总结
从测试结果上看,k-近邻算法的准确率达到92%左右,可以说效果中规中矩,本书第二章的另一个实验代码在下面的链接供读者下载:https://github.com/JeremyRen95/DataAnalysis/tree/master/kNN