《 机器学习实战》 学习笔记
这里记录的完全是因为个人水平差,自己挖的坑,就是学习过程中手敲代码调试时犯的一些错。
主要是按书中的章节排序,碰到了就写,后面再读时有新发现也好整理,免得要手动调整后面的序号。
文章目录
第2章 k-近邻算法
2.1 用距离来分类(k-近邻算法概述)
-
ndarray是没有取逆的方法的,因为他压根就不是矩阵!
所以会这样报错:>>> randomMat = random.rand(4, 4) >>> randomMat.I Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'numpy.ndarray' object has no attribute 'I'
用mat转化为矩阵就不会报错了:
>>> randomMat = mat(random.rand(4, 4)) >>> randomMat.I matrix([[0.8361456 , 0.18642213, 0.65247089, 0.87873974], [0.46871572, 0.35324231, 0.8407545 , 0.39883366], [0.5629274 , 0.2667139 , 0.9151684 , 0.89219693], [0.53825767, 0.71212795, 0.15016084, 0.78576378]])
-
书是旧的,技术是新的,千万要注意python版本的新变化
---> 22 sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True) AttributeError: 'dict' object has no attribute 'iteritems'
书是很早以前写的,然而在python3.5以后,iteritems就被改成items了。
-
理解维度在shape()函数和相关函数的参数里axis的不同
当我们获取一个数组或者矩阵的每一个维度的长度和定义一个矩阵或数组的维度分布时,我们会用到shape()和reshape()这样的函数,例如:>>> m = arange(24).reshape([2, 3, 4]) >>> m.shape, m ((2, 3, 4), array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]))
这里的2,3,4,可以简单理解为有2个国家,每个国家里有3个省,每个省里有4个市,但是在一些别的函数中,我们会用到axis这个参数的设置,比如矩阵的求和:
>>> m = arange(6).reshape([1, 2, 3]) >>> n = m.sum(axis=1) >>> m, n (array([[[0, 1, 2], [3, 4, 5]]]), array([[3, 5, 7]]))
这里的axis=1可能就不好理解了,这个’1’是指的什么呢?对行求和还是队列求和?怎么表述都很奇怪,没关系,在多写点代码
>>> m = arange(6).reshape([1, 2, 3]) >>> n0 = m.sum(axis=0) >>> n1 = m.sum(axis=1) >>> n2 = m.sum(axis=2) >>> m, n0, n1, n2 (array([[[0, 1, 2], [3, 4, 5]]]), array([[0, 1, 2], [3, 4, 5]]), array([[3, 5, 7]]), array([[ 3, 12]])) >>> n0.shape, n1.shape, n2.shape ((2, 3), (1, 3), (1, 2))
这个时候我们看到当axis=0时,似乎没起作用,但在axis分别为1,2时都很有“方向性”的进行了求和,但我们再次打印这个求和后的矩阵的“形状”时,就发现了问题了,之前没有仔细看[ ]层数的现在就能发现当axis=0时,返回的结果是变了的。原来是1个国家2个省3个市,现在只有2个省3个市了,继续看axis=1和2的情况,很容易发现就能看到规律了。axis就是维度的序号(第一维度是0)。sum(axis=2)表达的是对矩阵的第2维各项求和,当第2维被合并为一个数的时候,这个维度也就消失了,自然结果就少了一维。
所以做矩阵的时候还是不要再用行列这种可图形化的思路去理解了,尽量能抽象的去理解多维空间的概念,也能避免一些弯路。 -
未能重现的小问题
我在pycharm里使用jupyter notebook时,将代码分成多个cell时,莫名其妙的会找不到一些函数,比如我就纠结了很久为什么会显示‘tile函数是没有定义’的,但是将代码合并在一个cell里就好了。这个不明白,将来再看吧
本小节学到的东西:
-
tile(A, reps):扩展一个矩阵 sum(axis=):矩阵求和
-
argsort()方法:返回列表排序后的各元素在原列表中的索引
-
get(dict, default=None):返回指定键的值,如果值不在字典中返回默认值。
-
max(dict, key=dict.get):返回字典里最大值对应的键
编辑于2018年10月23日凌晨--->未完待续
2.2 实例: 利用kNN算法改进约会网站的匹配结果
-
将文本字符串转换成数字编码
classLabelVector.append(int(listFromLine[-1]))
这句程序执行报错ValueError,因为listFromLine[-1]存放的是LargeDoses等字符串,不是数字字符串。
修改的方式有很多种,这里因为只有三类,所以简单的用字典做好了(只是为了通过编译,不能通用)。labelclass ={'largeDoses': 0, 'smallDoses': 1, 'didntLike': 2} classLabelVector.append(labelclass.get(listFromLine[-1]))
-
关于reload()函数
修改kNN.py后,需要使用reload()函数重新加载到控制台,但reload函数在Python3以后移到imp标准库中,所以要from imp import reload
-
用来绘图的代码
源代码没有给出的书上用来绘图的代码如下:import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) # ax.scatter(datingDataMat[:,1], datingDataMat[:,2]) ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), 15.0*array(datingLabels)) plt.show()
别忘了在控制台操作时import array方法:
from numpy import array
编辑于2018年10月24日凌晨--->未完待续
-
对数组取最大最小值**
对于numpy.max(array, axis=0)跟之前的理解一样,抛弃行列的概念,这里是比较所有数据里第0维的数据,来获得在0维里面的最大值。比如# -*- coding:utf-8 -*- import numpy as np a = np.array([[10, 1, 2, 3], [4, 5, 16, 7], [8, 19, 10, 11]]) b = np.max(a, axis=0) print(b) # [10, 19, 16, 11] print(a.shape, b.shape) # (3, 4) (4,)
或者可以这样记忆,当对一个矩阵a,如果a.shape = (i,j,k,l)那么经过max、min、sum等类似的操作(axis=0)后,返回的结果为b,那么b.shape = (j,k,l)
-
代码读到后面发现丫的换数据了,新的数据把label换成了整数,所以我之前的小聪明把自己坑了, 为了兼容两个数据,还是在原来他的代码基础上增加判断吧,这样两个表都都可以正常操作了:
labelclass = {'largeDoses': 3, 'smallDoses': 2, 'didntLike': 1} if listFromLine[-1] in labelclass.keys(): listFromLine[-1] = labelclass[listFromLine[-1]] classLabelVector.append(int(listFromLine[-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('datingTestSet.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]
这里问题很大了,差点没有坑死我, 我在测试的时候发现分类结果很不理想啊,发现根本就找不到一个
in large doses
——十分中意的男人。怎么写参数都不行!。仔细对比才发现,测试array的顺序错了,应该是percentTats, ffMiles, iceCream
。最后我修改了代码:def classifyPerson(): resultList = ['not at all', 'in small doses', 'in large doses'] percentTats = float(input("percentage of time spent playing video games?")) ffMiles = float(input("frequent flier miles earned per year?")) iceCream = float(input("liters of ice cream consumed per year?")) datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') normMat, ranges, minVals = autoNorm(datingDataMat) inArr = array([percentTats, ffMiles, iceCream]) normArr = (inArr - minVals) / ranges classifierResult = classify0(normArr, normMat, datingLabels, 3) print(classifierResult) print("You will probably like this person: ", resultList[classifierResult - 1]) return percentTats, ffMiles, iceCream, classifierResult
添加返回值是为了画图:
import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D fig = plt.figure() ax = fig.add_subplot(111, projection='3d') colors = ['r', 'g', 'b'] ax.scatter(datingDataMat[:, 0], datingDataMat[:, 1], datingDataMat[:, 2], c=[colors[i-1] for i in datingLabels]) newPoint = classifyPerson()[:3] ax.scatter(newPoint[0], newPoint[1], newPoint[2], c='black') plt.title('red means :not at all\n' 'green means :in small doses\n' 'blue means :in large doses\n') plt.show()
效果如下:
编辑于2018年10月25日凌晨--->未完待续
2.3 示例: 手写识别系统
- 完整代码如下:
(1) kNN.py
个人理解:k-近邻算法是对数据分类的最简单有效的方法,他利用新数据与原有所有数据进行比对,找到特征最接近的K个数据,通过这K个数据的统计结果(出现频率最高的分类),对新数据进行分类。缺点是该算法必须保留所有的数据集,并对所有数据集进行计算,所以要花费最大的存储空间和不小的运算量,在有较大的数据集时,效率很低。import operator import numpy as np import os def classify0(inX, dataSet, labels, k): dataSetSize = dataSet.shape[0] diffMat = np.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 sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) return sortedClassCount[0][0] def img2vector(filename): returnVect = np.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 def handwritingClassTest(): hwLabels = [] trainingFileList = os.listdir('trainingDigits') m = len(trainingFileList) trainingMat = np.zeros((m, 1024)) for i in range(m): fileNameStr = trainingFileList[i] fileStr = fileNameStr.split('.')[0] # 去掉文件名后缀 classNumStr = int(fileStr.split('_')[0]) # 获取label hwLabels.append(classNumStr) trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr) testFileList = os.listdir('testDigits') errorCount = 0.0 mTest = len(testFileList) for i in range(mTest): fileNameStr = testFileList[i] fileStr = fileNameStr.split('.')[0] classNumStr = fileStr.split('_')[0] vectorUnderTest = img2vector('testDigits/%s' % fileNameStr) classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3) print('classifierResult:', classifierResult, ', real:', classNumStr) if classifierResult != int(classNumStr): errorCount += 1.0 print('\nthe total number of errors is:%d' % errorCount) print('\nthe total error rate is:%f' % (errorCount/float(mTest))) if __name__ == '__main__': handwritingClassTest()
第三章 决策树 decision tree
3.1 构造决策树
- 代码这里就不水了,主要要注意的问题是,这一节示例代码中数据如下:
但是在代码中是这样写的:no surfacing flippers fish? 0 1 1 yes 1 1 1 yes 2 1(true) 0(false) no 3 0 1 no 4 0 0 no
往常我们把最终的结果作为label,即正常情况下label应该是dataSet = [[1, 1, 'yes'], [1, 1, 'yes'], [1, 0, 'no'], [0, 1, 'no'], [0, 1, 'no']] labels = ['no surfacing','flippers']
所以这个小节的代码想复用,并访问一个文件时,就应该慎重考虑,并修改具体的获取文件内容的相关代码了。(我也是想着重新用决策树来分类第一章的约会数据时发现的。当然菜鸟就是菜鸟,决策树一般是操作特征值相对离散分布的数据,对于第一节的特征值接近连续的数据是要做额外处理的!)# labels = [i[2] for i in dataSet] labels = ['yes', 'yes', 'no', 'no', 'no']
编辑于2018年12月26日晚--->未完待续
3.2 绘制树形图
- 这一节绘制树突然使用了大量的 matplotlib库函数,查阅资料就花费了很大劲。
参阅 Matplotlib 教程 https://blog.csdn.net/u011497262/article/details/52325705 - 首次基础到例子中的全局变量使用方法,如下:
输出为2,即func.v为一个全局变量,即一个不用global声明的全局变量,这个特性也不知道是什么原理,但是感觉挺方便的。def func0(): pass def func1(): func0.v = 1 def func2(): func0.v = 2 func1() func2() print(func0.v)
- 计算各个节点的位置上设计比较讨巧。抽时间弄个图出来解释
编辑于2018年12月27日晚--->未完待续
另起了一篇文章,如下
https://blog.csdn.net/u012216590/article/details/85332556
编辑于2018年12月28日晚--->未完待续