机器学习实战--笔记2(k-近邻算法)

时间:2021-06-23 21:24:43


1:算法简单描述

       给定训练数据样本和标签,对于某测试的一个样本数据,选择距离其最近的k个训练样本,这k个训练样本中所属类别最多的类即为该测试样本的预测标签。简称kNN。通常k是不大于20的整数,这里的距离一般是欧式距离。

2:python代码实现

创建一个kNN.py文件,将核心代码放在里面了。

(1)   创建数据

[python] view plain copy print ?
  1. #创造数据集  
  2. def createDataSet():  
  3.     group = array([[1.01.1], [1.01.0], [00], [00.1]])  
  4.     labels = [’A’‘A’‘B’‘B’]  
  5.     return group, labels  
#创造数据集
def createDataSet():
group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
labels = ['A', 'A', 'B', 'B']
return group, labels

(2)   构照kNN分类器

[python] view plain copy print ?
  1. #第一个kNN分类器  inX-测试数据 dataSet-样本数据  labels-标签 k-邻近的k个样本  
  2. def classify0(inX,dataSet, labels, k):  
  3.     #计算距离  
  4.     dataSetSize = dataSet.shape[0]  
  5.     diffMat = tile(inX, (dataSetSize,1))- dataSet  
  6.     sqDiffMat = diffMat ** 2  
  7.     sqDistances = sqDiffMat.sum(axis = 1)  
  8.     distances = sqDistances **0.5  
  9.     sortedDistIndicies = distances.argsort()  
  10.     classCount = {}  
  11.     #选择距离最小的k个点  
  12.     for i in range(k):  
  13.         voteIlabel = labels[sortedDistIndicies[i]]  
  14.         classCount[voteIlabel] = classCount.get(voteIlabel,0)+1  
  15.     #排序  
  16.     sortedClassCount = sorted(classCount.iteritems(), key = operator.itemgetter(1),reverse = True)  
  17.     return sortedClassCount[0][0]  
#第一个kNN分类器  inX-测试数据 dataSet-样本数据  labels-标签 k-邻近的k个样本
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 = {}
#选择距离最小的k个点
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
#排序
sortedClassCount = sorted(classCount.iteritems(), key = operator.itemgetter(1),reverse = True)
return sortedClassCount[0][0]

代码讲解:(a)tile函数 tile(inX, i);扩展长度  tile(inX, (i,j)) ;i是扩展个数,j是扩展长度。如:

                      机器学习实战--笔记2(k-近邻算法)

                (b) python代码路径,需要导入os文件,os.getcwd()显示当前目录,os.chdir(‘’)改变目录,listdir()显示当前目录的所有文件。此外如果修改了当前.py文件,需要在python shell中重新加载该py文件(reload(kNN.py)),以确保更新的内容可以生效,否则python将继续使用上次加载的kNN模块。如:

 机器学习实战--笔记2(k-近邻算法)

机器学习实战--笔记2(k-近邻算法)

          (c)注意列表求平方,求和

           如:

机器学习实战--笔记2(k-近邻算法)

3:案例—约会网站

案例描述:

机器学习实战--笔记2(k-近邻算法)

机器学习实战--笔记2(k-近邻算法)

(1)   从文本文件中解析数据

[python] view plain copy print ?
  1. # 将文本记录到转换numPy的解析程序  
  2. def file2matrix(filename):  
  3.     #打开文件并得到文件行数  
  4.     fr = open(filename)  
  5.     arrayOLines = fr.readlines()  
  6.     numberOfLines = len(arrayOLines)  
  7.     #创建返回的numPy矩阵  
  8.     returnMat = zeros((numberOfLines, 3))  
  9.     classLabelVector = []  
  10.     index =0  
  11.     #解析文件数据到列表  
  12.     for line in arrayOLines:  
  13.         line = line.strip()  
  14.         listFormLine = line.split(’\t’)  
  15.         returnMat[index,:] = listFormLine[0:3]  
  16.         classLabelVector.append(int(listFormLine[-1]))  
  17.         index += 1  
  18.     return returnMat, classLabelVector  
# 将文本记录到转换numPy的解析程序
def file2matrix(filename):
#打开文件并得到文件行数
fr = open(filename)
arrayOLines = fr.readlines()
numberOfLines = len(arrayOLines)
#创建返回的numPy矩阵
returnMat = zeros((numberOfLines, 3))
classLabelVector = []
index =0
#解析文件数据到列表
for line in arrayOLines:
line = line.strip()
listFormLine = line.split('\t')
returnMat[index,:] = listFormLine[0:3]
classLabelVector.append(int(listFormLine[-1]))
index += 1
return returnMat, classLabelVector

代码讲解:(a)首先使用函数line.strip()截取掉所有的回车字符,然后使用tab字符\t将上一步得到的整行数据分割成一个元素列表

          (b)int(listFormLine[-1]);python中可以使用索引值-1表示列表中的最后一列元素。此外这里我们必须明确的通知解释器,告诉它列表中存储的元素值为整型,否则python语言会将这些元素当做字符串处理。

(2)使用绘图工具matplotlib创建散点图—可以分析数据

机器学习实战--笔记2(k-近邻算法)

机器学习实战--笔记2(k-近邻算法)

机器学习实战--笔记2(k-近邻算法)

(3)归一化数值

   为了防止特征值数量的差异对预测结果的影响(比如计算距离,量值较大的特征值影响肯定很大),我们将所有的特征值都归一化到[0,1]

[python] view plain copy print ?
  1. #归一化特征值  
  2. def autoNorm(dataSet):  
  3.     minVals = dataSet.min(0);  
  4.     maxVals = dataSet.max(0);  
  5.     ranges = maxVals - minVals;  
  6.     normDataSet = zeros(shape(dataSet))  
  7.     m = dataSet.shape[0]  
  8.     normDataSet = dataSet - tile(minVals, (m,1))  
  9.     normDataSet = normDataSet/tile(ranges,(m,1))  
  10.     return normDataSet, ranges, minVals  
#归一化特征值
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
机器学习实战--笔记2(k-近邻算法)

(4)测试代码

     测试代码以90%的作为训练样本,10%的作为测试数据

[python] view plain copy print ?
  1. #测试代码  
  2. def datingClassTest():  
  3.     hoRatio = 0.10    #测试数据占的百分比  
  4.     datingDataMat, datingLabels = file2matrix(’datingTestSet2.txt’)  
  5.     normMat, ranges, minVals = autoNorm(datingDataMat)  
  6.     m = normMat.shape[0]  
  7.     numTestVecs = int(m*hoRatio)  
  8.     errorCount = 0.0  
  9.     for i in range(numTestVecs):  
  10.         classifierResult = classify0(normMat[i,:], normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)  
  11.         print ‘the classifier came back with: %d, the real answer is: %d’ %(classifierResult, datingLabels[i])  
  12.         if(classifierResult != datingLabels[i]): errorCount += 1.0  
  13.     print “the total error rate is: %f ” % (errorCount/float(numTestVecs))  
#测试代码
def datingClassTest():
hoRatio = 0.10 #测试数据占的百分比
datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
normMat, ranges, minVals = autoNorm(datingDataMat)
m = normMat.shape[0]
numTestVecs = int(m*hoRatio)
errorCount = 0.0
for i in range(numTestVecs):
classifierResult = classify0(normMat[i,:], normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
print 'the classifier came back with: %d, the real answer is: %d' %(classifierResult, datingLabels[i])
if(classifierResult != datingLabels[i]): errorCount += 1.0
print "the total error rate is: %f " % (errorCount/float(numTestVecs))

(5)输入某人的信息,便得出对对方的喜欢程度

[python] view plain copy print ?
  1. #输入某人的信息,便得出对对方喜欢程度的预测值  
  2. def classifyPerson():  
  3.     resultList = [’not at all’‘in small doses’‘in large doses’]  
  4.     percentTats = float(raw_input(”percentage of time spent playing video games?”))  
  5.     ffMiles = float(raw_input(”frequent flier miles earned per year?”))  
  6.     iceCream = float(raw_input(”liters of ice cream consumed per year?”))  
  7.     datingDataMat, datingLabels = file2matrix(’datingTestSet2.txt’)  
  8.     normMat, ranges, minVals = autoNorm(datingDataMat)  
  9.     inArr = array([ffMiles, percentTats, iceCream])  
  10.     classifierResult = classify0((inArr - minVals)/ranges, normMat, datingLabels,3)  
  11.     print ‘You will probably like this person: ’, resultList[classifierResult - 1]  
#输入某人的信息,便得出对对方喜欢程度的预测值
def classifyPerson():
resultList = ['not at all', 'in small doses', 'in large doses']
percentTats = float(raw_input("percentage of time spent playing video games?"))
ffMiles = float(raw_input("frequent flier miles earned per year?"))
iceCream = float(raw_input("liters of ice cream consumed per year?"))
datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
normMat, ranges, minVals = autoNorm(datingDataMat)
inArr = array([ffMiles, percentTats, iceCream])
classifierResult = classify0((inArr - minVals)/ranges, normMat, datingLabels,3)
print 'You will probably like this person: ', resultList[classifierResult - 1]

代码讲解:python中raw_input允许用户输入文本行命令并返回用户所输入的命令

 机器学习实战--笔记2(k-近邻算法)

4:案例—手写识别系统

        这里可以将手写字符看做由01组成的32*32个二进制文件,然后转换为1*1024的向量即为一个训练样本,每一维即为一个特征值

(1)   将一个32*32的二进制图像转换成1*1024的向量

[python] view plain copy print ?
  1. #将一个32*32的二进制图像矩阵转换成1*1024的向量  
  2.   
  3. def img2vector(filename):  
  4.     returnVect = zeros((1,1024))  
  5.     fr = open(filename)  
  6.     for i in range(32):  
  7.         lineStr = fr.readline()  
  8.         for j in range(32):  
  9.             returnVect[032*i+j] = int(lineStr[j])  
  10.     return returnVect  
#将一个32*32的二进制图像矩阵转换成1*1024的向量

def img2vector(filename):
returnVect = zeros((1,1024))
fr = open(filename)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVect[0, 32*i+j] = int(lineStr[j])
return returnVect

(2)   手写识别系统测试代码

[python] view plain copy print ?
  1. #手写识别系统测试代码  
  2. def handwritingClassTest():  
  3.     hwLabels = []  
  4.     trainingFileList = listdir(’trainingDigits’)   #获取目录内容  
  5.     m = len(trainingFileList)  
  6.     trainingMat = zeros((m, 1024))  
  7.     for i in range(m):  
  8.         fileNameStr = trainingFileList[i]              #分割得到标签  从文件名解析得到分类数据  
  9.         fileStr = fileNameStr.split(’.’)[0]  
  10.         classStr = int(fileStr.split(’_’)[0])  
  11.         hwLabels.append(classStr)                 #测试样例标签  
  12.         trainingMat[i,:] = img2vector(’trainingDigits/%s’ % fileNameStr)  
  13.     testFileList = listdir(’testDigits’)  
  14.     errorCount = 0.0  
  15.     mTest = len(testFileList)  
  16.     for i in range(mTest):  
  17.         fileNameStr = testFileList[i]  
  18.         fileStr = fileNameStr.split(’.’)[0]  
  19.         classStr = int(fileStr.split(’_’)[0])  
  20.         vectorUnderTest = img2vector(’testDigits/%s’ % fileNameStr)  
  21.         classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)  
  22.         print ‘the classifier came back with: %d, the real answer is: %d’ % (classifierResult, classStr)  
  23.         if(classifierResult != classStr): errorCount += 1.0  
  24.     print “\nthe total numbers of errors is : %d” % errorCount  
  25.     print “\nthe total error rate is: %f” % (errorCount/float(mTest))  
  26.           
#手写识别系统测试代码
def handwritingClassTest():
hwLabels = []
trainingFileList = listdir('trainingDigits') #获取目录内容
m = len(trainingFileList)
trainingMat = zeros((m, 1024))
for i in range(m):
fileNameStr = trainingFileList[i] #分割得到标签 从文件名解析得到分类数据
fileStr = fileNameStr.split('.')[0]
classStr = int(fileStr.split('_')[0])
hwLabels.append(classStr) #测试样例标签
trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
testFileList = listdir('testDigits')
errorCount = 0.0
mTest = len(testFileList)
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0]
classStr = int(fileStr.split('_')[0])
vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
print 'the classifier came back with: %d, the real answer is: %d' % (classifierResult, classStr)
if(classifierResult != classStr): errorCount += 1.0
print "\nthe total numbers of errors is : %d" % errorCount
print "\nthe total error rate is: %f" % (errorCount/float(mTest))

注明:1:本笔记来源于书籍<机器学习实战>

2:kNN.py文件及笔记所用数据在这下载(http://download.csdn.net/detail/lu597203933/7653991).

作者:小村长  出处:http://blog.csdn.net/lu597203933 欢迎转载或分享,但请务必声明文章出处。 (新浪微博:小村长zack, 欢迎交流!)