本文记录机器学习实战中案例的实践过程。
配置python开发环境就不在赘述,要注意的是机器学习实战这本书用的是python2,如果像我一样用python3的话有一些代码是需要修改的。
程序清单2-1 k近邻算法(kNN)
#定义k近邻算法的函数,参数分别是:测试样本inX,训练样本集dataSet,训练样本集的标签labels,选择最近邻居的数目k
def classify0(inX,dataSet,labels,k):
#定义dataSetSize,取值为dataSet第一维的数目,即dataSet内的数据条数
dataSetSize = dataSet.shape[0]
#先将测试样本拓展成和dataSet同样的尺寸,然后相减
diffMat = tile(inX,(dataSetSize,1)) - dataSet
#将上一步得到的矩阵的每一个数据平方
sqDiffMat = diffMat**2
#将上一步得到的矩阵的每一行的元素相加得到一个新的尺寸为dataSetSize*1的矩阵
sqDistances = sqDiffMat.sum(axis=1)
#得到距离,即上面的矩阵开根号,这几步用的是数学中计算两点距离的公式 d = √[(x₁-x₂)²+(y₁-y₂)²]
distances = sqDistances**0.5
#argsort函数返回的是数组值从小到大的索引值
sortedDisInddicies = distances.argsort()
classCount={}
#找出距离最近的k个点中出现频率最高的分类
for i in range(k):
voteIlabel = labels[sortedDisInddicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
#print i,voteIlabel,classCount
sortedClassCount = sorted(classCount.items(),#sort
key = operator.itemgetter(1),reverse = True)
#print sortedClassCount
return sortedClassCount[0][0]
程序清单2-2 读入文件,转化成矩阵,用matplotlib做出图像
def file2matrix(filename):
#读文件
fr = open(filename)
arrayOlines = fr.readlines()
numberOfLines = len(arrayOlines)
#创建numpy矩阵,尺寸为numberOfLines*3,用来存放解析出的数据
returnMat = zeros((numberOfLines,3))
#创建上面矩阵的标签向量
classLabelVector = []
index = 0
#下面的循环将解析出的数据放入矩阵中
for line in arrayOlines:
#line.strip()函数删除line的头部和尾部的空白符(包括'\n','\r', '\t', ' ')
line= line.strip()
#将line按\t分割成一个一个的字符(如a\tbb\tccc\td将会被分成[a,bb,ccc,d])
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat,classLabelVector
到这里就得到了训练数据的矩阵了,下面可以用matplotlib做出它的图像:
可以写一个main.py用来做测试用,下面是main.py的代码
# -*- coding: utf-8 -*-
"""
Created on Fri Oct 6 20:37:39 2017
@author: bjk
"""
import kNN
import matplotlib
import matplotlib.pyplot as plt
from numpy import *
#得到数据,做出图像(注意此处数据文件要和工程放在同一个目录下)
datingDateMat,datingLabels = kNN.file2matrix('datingTestSet.txt')
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDateMat[:,0],datingDateMat[:,1],15.0*array(datingLabels),15.0*array(datingLabels))
plt.show()
绘制图像如下:
程序清单2-3 归一化特征值
计算距离时,根据距离公式,数值差距大的属性对距离影响很大,比如飞行里程数,这是不够准确的,所以要将数值都归一化到[0,1]区间。
def autoNorm(dataSet):
#得到dataSet的每一列的最小值
minVals = dataSet.min(0)
#得到dataSet的每一列的最大值
maxVals = dataSet.max(0)
#计算范围(这三步目的是得到属性的取值范围)
ranges = maxVals - minVals
#初始化一个尺寸和dataSet一样的矩阵,用来存放归一化后的dataSet
normDataSet = zeros(shape(dataSet))
#得到dataSet的数据条数
m = dataSet.shape[0]
#得到归一化后的矩阵,tile函数把minVals复制成与dataSet尺寸一样的矩阵
normDataSet = dataSet - tile(minVals,(m,1))
normDataSet = normDataSet/tile(ranges,(m,1))
return normDataSet,ranges,minVals
程序清单2-4 分类器针对约会网站的测试代码
def datingClassTest():
#定义用于测试的数据占总数据的10%
hoRatio = 0.10
#调用file2matrix读数据文件,得到矩阵
datingDateMat,datingLabels = file2matrix('datingTestSet.txt')
#得到归一化后矩阵
normMat,ranges,minVals = autoNorm(datingDateMat)
#用于测试的数据向量
numTestVecs = int(m*hoRatio)
#错误次数
errorCount = 0.0
#调用classify0()将测试数据(总数据前10%),训练数据(总数据后90%),训练数据标签,k传入
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]))
#若判断结果与测试数据标签不同,则错误次数+1
if(classifierResult != datingLabels[i]):
errorCount += 1.0
print("the total error rate is: %f" %(errorCount/float(numTestVecs)))
测试这段代码同样简单,将kNN.datingClassTest() 这段代码放到main.py里然后运行即可
程序清单2-5 约会网站预测函数
def classifyPerson():
resultList = ['not at all','in small doses','in big doses']
percentTats = float(input('pecentage of time spent playing viedo games ?'))
ffMiles = float(input('frequent flier miles earned per year ?'))
iceCream = float(input('liters of ice cream consumed per year ?'))
datingDateMat,datingLabels = file2matrix('datingTestSet.txt')
normMat,ranges,minVals = autoNorm(datingDateMat)
inArr = array([ffMiles,percentTats,iceCream])
classifierResult = classify0((inArr - minVals)/ranges,normMat,datingLabels,3)
print('you will probably like this person:',resultList[classifierResult - 1])
这个函数功能是接受你输入的参数,然后调用分类算法,告知你预测的结果,测试他同样简单,在main.py内加上kNN.classifyPerson()调用它即可。
点这里到下一篇机器学习实战之程序清单1-kNN(手写数字识别系统)