机器学习实战这本是用python进行开发的,python环境的安装就不用多说了。
先来说一下我自己的环境把:我用的是python 3.6.5,本书用的是python 2.7,本书的代码英文版出版商的http://www.manning.com/MachineLearninginAction可以下载到。
如果你已经配置好了相关的环境,下面可以开始相应的算法实战。
一、k临近算法(KNN)的工作原理
存在一个样本数据集,也称作训练数据集,并且样本集中每个数据都存在标签,即我们知道样本集中每个数据与所属分类的对应关系。当输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似的数据的分类标签。一般来水,我们只选择样本数据集中最相似的k个数据(通常k不大于20),再根据多数表决原则,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
k近邻算法的一般流程:
- 收集数据:可以采用公开的数据集
- 准备数据:计算距离所需要的数值
- 分析数据:剔除垃圾信息
- 测试算法:计算错误率
- 使用算法:运用在实际中,对实际情况进行预测
二、算法的具体实施过程
(1)使用python导入数据
from numpy import *
import operator
import matplotlib
import matplotlib.pyplot as plt
from os import listdir
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算法
k近邻算法对未知类别属性的数据集中每个点依次执行如下步骤:
- 计算已知类别数据集中的点与当前点之间的距离
- 按照距离递增次序排序
- 选取与当前点距离最小的k个点
- 确定前k个点所在类别的出现频率
- 返回前k个点出现频率最高的类别作为当前点的预测分类
具体代码如下:
# -------------------------构建分类器-------------------------------
# KNN算法实施
# @inX 测试样本数据
# @dataSet 训练样本数据
# @labels 测试样本标签
# @k 选取距离最近的k个点
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
print(dataSetSize) # 获取第一维的维度 4*2 也就是4
# tile 重复inX维度(4,1) inX = [0,0] ==>先横向复制4次,纵向复制1次,也就是本身 最后的维度(4,2)
# 这儿求欧式距离,都是求到0 0 的距离 以下几行都是求欧式距离
# ————————————欧式距离————————————————————
diffMat = tile(inX, (dataSetSize, 1)) - dataSet # 新样本与原样本的差值矩阵
sqDiffMat = diffMat ** 2 # 求平方
# .sum()运行加函数,参数axis=1表示矩阵每一行的各个值相加和
sqDistances = sqDiffMat.sum(axis=1)
print(sqDistances)
distances = sqDistances ** 0.5
# ————————————————————————————————————
print(distances)
# 获取排序(有小到大)后的距离值的索引(序号)
sortedDistIndicies = distances.argsort()
print(sortedDistIndicies)
classCount = {}
for i in range(k):
# 获取该索引对应的训练样本的标签
voteIlabel = labels[sortedDistIndicies[i]]
# 累加几类标签出现的次数,构成键值对key/values并存于classCount中
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
# 将字典列表中按照第二列,也就是次数标签,反序排序(由大到小排序)
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
# 返回第一个元素(最高频率)标签key
return sortedClassCount[0][0]
(3)测试分类器
实例1:使用kNN改进某约会网站的配对效果
# -------------------------约会网站配对-----------------------------------
# --------------1 将text文本数据转化为NumPy可以接受的格式---------------
def file2matrix(filename):
# 打开文件
fr = open(filename)
# 读取文件每一行到array0Lines列表
# read():读取整个文件,通常将文件内容放到一个字符串中
# readline():每次读取文件一行,当没有足够内存一次读取整个文件内容时,使用该方法
# readlines():读取文件的每一行,组成一个字符串列表,内存足够时使用
array0Lines = fr.readlines()
# 获取字符串列表行数行数
numberOfLines = len(array0Lines)
# 返回的特征矩阵大小
returnMat = zeros((numberOfLines, 3))
# list存储类标签
classLabelVector = []
index = 0
for line in array0Lines:
# 去掉字符串头尾的空格,类似于Java的trim()
line = line.strip()
# 将整行元素按照tab分割成一个元素列表
listFromLine = line.split('\t')
# 将listFromLine的前三个元素依次存入returnmat的index行的三列
returnMat[index, :] = listFromLine[0:3]
# python可以使用负索引-1表示列表的最后一列元素,从而将标签存入标签向量中
# 使用append函数每次循环在list尾部添加一个标签值
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat, classLabelVector
# ----------------2 准备数据:归一化----------------------------------------------
# 计算欧式距离时,如果某一特征数值相对于其他特征数值较大,那么该特征对于结果影响要
# 远大于其他特征,然后假设特征都是同等重要,即等权重的,那么可能某一特征对于结果存
# 在严重影响
def autoNorm(dataSet):
# 找出每一列的最小值
minVals = dataSet.min(0)
# 找出每一列的最大值
maxVals = dataSet.max(0)
ranges = maxVals - minVals
# 创建与dataSet等大小的归一化矩阵
# shape()获取矩阵大小
normDataSet = zeros(shape(dataSet))
# 获取dataSet第一维度的大小
m = dataSet.shape[0]
# 将dataSet的每一行的对应列减去minVals中对应列的最小值
normDataSet = dataSet - tile(minVals, (m, 1))
# 归一化,公式newValue=(value-minvalue)/(maxVal-minVal)
normDataSet = normDataSet / tile(ranges, (m, 1))
return normDataSet, ranges, minVals
# -------------------------3 测试算法----------------------------------------------
def datingClassTest():
# 设定用来测试的样本占比
hoRatio = 0.10
# 从文本中提取得到数据特征,及对应的标签
datingDataMat, datingLabels = file2matrix('dataTestSet2.txt')
# 对数据特征进行归一化
normMat, ranges, minVals = autoNorm(datingDataMat)
# 得到第一维度的大小
m = normMat.shape[0]
# 测试样本数量
numTestVecs = int(hoRatio * m)
# 错误数初始化
errorCount = 0.0;
for i in range(numTestVecs):
# 利用分类函数classify0获取测试样本数据的分类结果
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.0
if (classifierResult != datingLabels[i]): errorCount += 1.0
# 打印最后的误差率
print("the total error rate is: %f" % (errorCount / float(numTestVecs)))
# -------------------------4 构建可手动输入系统------------------------------------
# 用户输入相关数据,进行预测
def classifyPerson():
# 定义预测结果
resultList = ['not at all', 'in small does', 'in large does']
# 在python3.x中,已经删除raw_input(),取而代之的是input()
percentTats = float(input("percentage of time spent playing video games?"))
ffMiles = float(input("frequent filer miles earned per year?"))
iceCream = float(input("liters of ice cream consumed per year?"))
datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2], 15.0 * array(datingLabels), 15.0 * array(datingLabels))
plt.show()
normMat, ranges, minValues = autoNorm(datingDataMat)
# 将输入的数值放在数组中
inArr = array([ffMiles, percentTats, iceCream])
classifierResult = classify0((inArr - minValues) / ranges, normMat, datingLabels, 3)
print("you will probably like this person:", resultList[classifierResult - 1])
classifyPerson()
测试输入
返回结果(这里为了方便看数据,我将中间处理过程也打印了出来)
三、算法小结
如果我们改变训练样本的数目,调整相应的k值,都会对最后的预测错误率产生影响,我们可以根据错误率的情况,对这些变量进行调整,从而降低预测错误率。
k近邻算法的优缺点:
优点:k近邻算法具有精度高
缺点:对异常值不敏感的优点
k近邻算法是基于实例的学习,使用算法时我们必须有接近实际数据的训练样本数据。k近邻算法必须保存全部数据集,如果训练数据集很大,必须使用大量的存储空间。此外,由于必须对数据集中的每个数据计算距离,实际使用时也可能会非常耗时
此外,k近邻算法无法给出数据的基础结构信息,因此我们无法知道平均实例样本和典型实例样本具有怎样的特征。