diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..5b2c3353 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,204 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Python", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config:python.pythonPath}", + "program": "${file}", + "cwd": "${workspaceRoot}", + "env": {}, + "envFile": "${workspaceRoot}/.env", + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit", + "RedirectOutput" + ] + }, + { + "name": "PySpark", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "osx": { + "pythonPath": "${env:SPARK_HOME}/bin/spark-submit" + }, + "windows": { + "pythonPath": "${env:SPARK_HOME}/bin/spark-submit.cmd" + }, + "linux": { + "pythonPath": "${env:SPARK_HOME}/bin/spark-submit" + }, + "program": "${file}", + "cwd": "${workspaceRoot}", + "env": {}, + "envFile": "${workspaceRoot}/.env", + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit", + "RedirectOutput" + ] + }, + { + "name": "Python Module", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config:python.pythonPath}", + "module": "module.name", + "cwd": "${workspaceRoot}", + "env": {}, + "envFile": "${workspaceRoot}/.env", + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit", + "RedirectOutput" + ] + }, + { + "name": "Integrated Terminal/Console", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config:python.pythonPath}", + "program": "${file}", + "cwd": "", + "console": "integratedTerminal", + "env": {}, + "envFile": "${workspaceRoot}/.env", + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit" + ] + }, + { + "name": "External Terminal/Console", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config:python.pythonPath}", + "program": "${file}", + "cwd": "", + "console": "externalTerminal", + "env": {}, + "envFile": "${workspaceRoot}/.env", + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit" + ] + }, + { + "name": "Django", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config:python.pythonPath}", + "program": "${workspaceRoot}/manage.py", + "cwd": "${workspaceRoot}", + "args": [ + "runserver", + "--noreload" + ], + "env": {}, + "envFile": "${workspaceRoot}/.env", + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit", + "RedirectOutput", + "DjangoDebugging" + ] + }, + { + "name": "Flask", + "type": "python", + "request": "launch", + "stopOnEntry": false, + "pythonPath": "${config:python.pythonPath}", + "program": "fully qualified path fo 'flask' executable. Generally located along with python interpreter", + "cwd": "${workspaceRoot}", + "env": { + "FLASK_APP": "${workspaceRoot}/quickstart/app.py" + }, + "args": [ + "run", + "--no-debugger", + "--no-reload" + ], + "envFile": "${workspaceRoot}/.env", + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit", + "RedirectOutput" + ] + }, + { + "name": "Flask (old)", + "type": "python", + "request": "launch", + "stopOnEntry": false, + "pythonPath": "${config:python.pythonPath}", + "program": "${workspaceRoot}/run.py", + "cwd": "${workspaceRoot}", + "args": [], + "env": {}, + "envFile": "${workspaceRoot}/.env", + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit", + "RedirectOutput" + ] + }, + { + "name": "Pyramid", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config:python.pythonPath}", + "cwd": "${workspaceRoot}", + "env": {}, + "envFile": "${workspaceRoot}/.env", + "args": [ + "${workspaceRoot}/development.ini" + ], + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit", + "RedirectOutput", + "Pyramid" + ] + }, + { + "name": "Watson", + "type": "python", + "request": "launch", + "stopOnEntry": true, + "pythonPath": "${config:python.pythonPath}", + "program": "${workspaceRoot}/console.py", + "cwd": "${workspaceRoot}", + "args": [ + "dev", + "runserver", + "--noreload=True" + ], + "env": {}, + "envFile": "${workspaceRoot}/.env", + "debugOptions": [ + "WaitOnAbnormalExit", + "WaitOnNormalExit", + "RedirectOutput" + ] + }, + { + "name": "Attach (Remote Debug)", + "type": "python", + "request": "attach", + "localRoot": "${workspaceRoot}", + "remoteRoot": "${workspaceRoot}", + "port": 3000, + "secret": "my_secret", + "host": "localhost" + } + ] +} \ No newline at end of file diff --git a/docs/3.决策树.md b/docs/3.决策树.md index 29c3c8c4..8d128a45 100644 --- a/docs/3.决策树.md +++ b/docs/3.决策树.md @@ -8,6 +8,10 @@ ![决策树-流程图](/images/3.DecisionTree/决策树-流程图.jpg "决策树示例流程图") +* 简要介绍 + 根据一些 feature 进行分类,每个节点提一个问题,通过判断,将数据分为两类,再继续提问。这些数据是根据已有数据学习出来的, + 再投入新数据的时候,就可以根据这棵树上的问题,将数据划分到合适的叶子上。 + > 决策树的任务 ``` @@ -106,6 +110,15 @@ * 流程介绍图 * ![决策树流程介绍图](/images/3.DecisionTree/决策树流程介绍图.jpg) +## 决策树小结 + +``` + 决策树分类器就像带有终止块的流程图,终止块表示分类结果。 + 开始处理数据集时,我们首先需要测量集合中数据的不一致性,也就是熵,然后寻找最优方案划分数据集,直到数据集中的所有数据属于同一分类。 + ID3算法可以用于划分标称型数据集。构建决策树时,我们通常采用递归的方法将数据集转化为决策树。一般我们并不构造新的数据结构,而是使用 + Python 中内嵌的数据结构字典存储树节点信息。 +``` + * * * * **作者:[片刻](http://www.apache.wiki/display/~jiangzhonglian) [小瑶](http://www.apache.wiki/display/~chenyao)** diff --git a/docs/4.朴素贝叶斯.md b/docs/4.朴素贝叶斯.md index 5cf9468f..291d2a82 100644 --- a/docs/4.朴素贝叶斯.md +++ b/docs/4.朴素贝叶斯.md @@ -131,6 +131,10 @@ p(ci|x,y) = p(x,y|ci)·p(ci)/p(x,y) * 总结 * 这一块代码比较乱,最好先把公式理一理再看 * 可以参考一下[阮一峰的博客](http://www.ruanyifeng.com/blog/2013/12/naive_bayes_classifier.html) + * 对于分类而言,使用概率有时要比使用硬规则更为有效。贝叶斯概率及贝叶斯准则提供了一种利用已知值来估计未知概率的有效方法。 + * 可以通过特征之间的条件独立性假设,降低对数据量的需求。独立性假设是指一个词的出现概率并不依赖于文档中的其他词。当然我们也知道这个假设过于简单。 + 这就是之所以成为朴素贝叶斯的原因。尽管条件独立性假设并不正确,但是朴素贝叶斯仍然是一种有效的分类器。 + * 利用现代编程语言来实现朴素贝叶斯时需要考虑很多实际因素。下溢出就是其中一个问题,它可以通过对概率取对数来解决。 * * * diff --git a/docs/5.Logistic回归.md b/docs/5.Logistic回归.md index 430e5081..bd8a6ccb 100644 --- a/docs/5.Logistic回归.md +++ b/docs/5.Logistic回归.md @@ -9,8 +9,8 @@ ``` 假设现在有一些数据点,我们用一条直线对这些点进行拟合(该线称为最佳拟合直线),这个拟合过程就称作回归。 - 利用 Logistic回归进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类。这里的“回归”一词源于最佳拟合, - 表示要找到最佳拟合参数集,其背后的数学分析将在下一部分介绍。训练分类器时的做法就是寻找最佳拟合参数,使用的是最优化算法。 + Logistic 回归主要的用途是用来做分类,利用 Logistic 回归 进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类。 + 我们这里所说的“回归”一词源于最佳拟合,表示要找到最佳拟合参数集。训练分类器时的做法就是寻找最佳拟合参数,使用的是最优化算法。 ``` > Logistic回归特点 @@ -24,6 +24,10 @@ > Sigmoid函数简介 ``` + 我们想要的函数应该是,能接受所有的输入然后预测出类别。例如,在两个类的情况下,上述函数输出 0 和 1 。这类函数称为海维塞得阶跃函数,或者直接称之为 单位阶跃函数。 + 但是,海维塞得阶跃函数的问题在于:该函数在跳跃点上从 0 瞬间跳跃到 1,这个瞬间跳跃过程有时候很难处理。幸好,另外的一个函数也有这样的性质(这里的性质指的是可以输出0和1的性质), + 且数学上更易处理,这就是我们下边要介绍的 Sigmoid 函数。 + Sigmoid函数具体的计算公式如下: f(z) = 1 / (1 + e ^(-z)) 图5-1 给出了Sigmoid函数在不同坐标尺度下的两条曲线图。当x为0时,Sigmoid函数值为0.5。随着x的增大,对应的Sigmoid值将逼近1;而随着x的减小,Sigmoid值将逼近0。 @@ -35,6 +39,13 @@ ## 最优化理论初步 +``` + Sigmoid函数的输入记为z,由下面的公式得出 + z = w0x0 + w1x1 + w2x2 + ... +wnxn + 如果采用向量的写法,上述公式可以写成 z = wTx ,它表示将这两个数值向量对应元素相乘然后全部加起来即得到z值。其中的向量 x 是分类器的输入数据, + 向量 w 也就是我们要找到的最佳参数(系数),从而使得分类器尽可能地精确。为了寻找最佳参数,需要用到最优化理论的一些知识。 +``` + > 梯度上升法 ``` @@ -43,12 +54,43 @@ ![logistic回归梯度上升法](/images/5.Logistic/梯度上升算法.png "梯度上升法") +介绍一下几个相关的概念: +``` + 例如:y = w1x1 + w2x2 + ... + wnxn + 梯度:参考上图的例子,二维图像,x方向是代表第一个系数,也就是w1,y方向代表第二个系数也就是w2,这样的向量就是梯度。 + α:上面的梯度算法的迭代公式中的阿尔法,这个代表的是移动步长。移动步长会影响最终结果的拟合程度,最好的方法就是随着迭代次数更改移动步长。 + 步长通俗的理解,100米,如果我一步走10米,我需要走10步;如果一步走20米,我只需要走5步。这里的一步走多少米就是步长的意思。 + ▽f(w):代表沿着梯度变化的方向。 +``` + +拟合程度简介 +参考: http://blog.csdn.net/willduan1/article/details/53070777 + +下面是原始数据集: + +![拟合程度图](/images/5.Logistic/拟合程度示例图.png "拟合程度示例图") + +下面是拟合程度较好的: + +![拟合程度较好示例图](/images/5.Logistic/拟合程度较好示例图.png "拟合程度较好示例图") + +欠拟合:模型没有很好地捕捉到数据特征,不能很好地拟合数据。 + +![欠拟合示例图](/images/5.Logistic/欠拟合示例图.png "欠拟合示例图") + +过拟合:模型把数据学习的太彻底了,以至于把噪声数据的特征也学习到了,这样就会导致在后期测试的时候不能够很好地识别数据,即不能正确地分类,模型泛化能力太差。 + +![过拟合示例图](/images/5.Logistic/过拟合示例图.png "过拟合示例图") + 梯度上升法的伪代码如下: +``` 某个回归系数初始化为1 重复R次: 计算整个数据集的梯度 使用 alpha X grandient 更新回归系数的向量 返回回归系数 +``` + 梯度上升算法在每次回归系数时都需要遍历整个数据集,该方法在处理100个左右的数据集时尚可,但如果有数十亿样本和成千上万的特征, 那么该方法的计算复杂度就太高了。一种改进方法是一次仅用一个样本点来更新回归系数,该方法称为随机梯度上升算法。 @@ -117,6 +159,15 @@ * 5.5 简化的成本函数和梯度下降 * 5.6 高级优化 +## Logistic 本章小结 + +``` + Logistic回归的目的是寻找一个非线性函数 Sigmoid 的最佳拟合参数,求解过程可以由最优化算法来完成。 + 在最优化算法中,最常用的就是梯度上升算法,而梯度上升算法又可以简化为随机梯度上升算法。 + 随机梯度上升算法与梯度上升算法的效果相当,但占用更少的计算资源。 + 此外,随机梯度上升是一个在线算法,它可以在新数据到来时就完成参数更新,而不需要重新读取整个数据集来进行批处理运算。 +``` + * * * * **作者:[羊三](http://www.apache.wiki/display/~xuxin) [小瑶](http://www.apache.wiki/display/~chenyao)** diff --git a/images/5.Logistic/拟合程度示例图.png b/images/5.Logistic/拟合程度示例图.png new file mode 100644 index 00000000..6730571e Binary files /dev/null and b/images/5.Logistic/拟合程度示例图.png differ diff --git a/images/5.Logistic/拟合程度较好示例图.png b/images/5.Logistic/拟合程度较好示例图.png new file mode 100644 index 00000000..bdec6b3b Binary files /dev/null and b/images/5.Logistic/拟合程度较好示例图.png differ diff --git a/images/5.Logistic/欠拟合示例图.png b/images/5.Logistic/欠拟合示例图.png new file mode 100644 index 00000000..641e7c1a Binary files /dev/null and b/images/5.Logistic/欠拟合示例图.png differ diff --git a/images/5.Logistic/过拟合示例图.png b/images/5.Logistic/过拟合示例图.png new file mode 100644 index 00000000..5f6640e7 Binary files /dev/null and b/images/5.Logistic/过拟合示例图.png differ diff --git a/src/python/2.KNN/kNN.py b/src/python/2.KNN/kNN.py index d9abbea7..59e7d7ea 100644 --- a/src/python/2.KNN/kNN.py +++ b/src/python/2.KNN/kNN.py @@ -3,7 +3,7 @@ ''' Created on Sep 16, 2010 Update on 2017-05-18 -@author: Peter Harrington/羊山 +@author: Peter Harrington/羊三/小瑶 《机器学习实战》更新地址:https://github.com/apachecn/MachineLearning ''' from numpy import * @@ -46,15 +46,15 @@ def classify0(inX, dataSet, labels, k): In [8]: tile(inx, (3, 1)) Out[8]: - array([[1, 2], - [1, 2], - [1, 2]]) + array([[1, 2, 3], + [1, 2, 3], + [1, 2, 3]]) In [9]: tile(inx, (3, 2)) Out[9]: - array([[1, 2, 1, 2], - [1, 2, 1, 2], - [1, 2, 1, 2]]) + array([[1, 2, 3, 1, 2, 3], + [1, 2, 3, 1, 2, 3], + [1, 2, 3, 1, 2, 3]]) """ diffMat = tile(inX, (dataSetSize, 1)) - dataSet """ @@ -74,6 +74,8 @@ def classify0(inX, dataSet, labels, k): # 开方 distances = sqDistances ** 0.5 # 根据距离排序从小到大的排序,返回对应的索引位置 + # argsort() 是将x中的元素从小到大排列,提取其对应的index(索引),然后输出到y。 + # 例如:y=array([3,0,2,1,4,5]) 则,x[3]=-1最小,所以y[0]=3,x[5]=9最大,所以y[5]=5。 # print 'distances=', distances sortedDistIndicies = distances.argsort() # print 'distances.argsort()=', sortedDistIndicies @@ -84,8 +86,19 @@ def classify0(inX, dataSet, labels, k): # 找到该样本的类型 voteIlabel = labels[sortedDistIndicies[i]] # 在字典中将该类型加一 + # 字典的get方法 + # 如:list.get(k,d) 其中 get相当于一条if...else...语句,参数k在字典中,字典将返回list[k];如果参数k不在字典中则返回参数d,如果K在字典中则返回k对应的value值 + # l = {5:2,3:4} + # print l.get(3,0)返回的值是4; + # Print l.get(1,0)返回值是0; classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 # 3. 排序并返回出现最多的那个类型 + # 字典的 items() 方法,以列表返回可遍历的(键,值)元组数组。 + # 例如:dict = {'Name': 'Zara', 'Age': 7} print "Value : %s" % dict.items() Value : [('Age', 7), ('Name', 'Zara')] + # sorted 中的第2个参数 key=operator.itemgetter(1) 这个参数的意思是先比较第几个元素 + # 例如:a=[('b',2),('a',1),('c',0)] b=sorted(a,key=operator.itemgetter(1)) >>>b=[('c',0),('a',1),('b',2)] 可以看到排序是按照后边的0,1,2进行排序的,而不是a,b,c + # b=sorted(a,key=operator.itemgetter(0)) >>>b=[('a',1),('b',2),('c',0)] 这次比较的是前边的a,b,c而不是0,1,2 + # b=sorted(a,key=opertator.itemgetter(1,0)) >>>b=[('c',0),('a',1),('b',2)] 这个是先比较第2个元素,然后对第一个元素进行排序,形成多级排序。 sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) return sortedClassCount[0][0] @@ -108,18 +121,22 @@ def file2matrix(filename): :return: 数据矩阵returnMat和对应的类别classLabelVector """ fr = open(filename) - numberOfLines = len(fr.readlines()) # get the number of lines in the file + # 获得文件中的数据行的行数 + numberOfLines = len(fr.readlines()) # 生成对应的空矩阵 + # 例如:zeros(2,3)就是生成一个 2*3的矩阵,各个位置上全是 0 returnMat = zeros((numberOfLines, 3)) # prepare matrix to return classLabelVector = [] # prepare labels return fr = open(filename) index = 0 for line in fr.readlines(): + # str.strip([chars]) --返回移除字符串头尾指定的字符生成的新字符串 line = line.strip() + # 以 '\t' 切割字符串 listFromLine = line.split('\t') # 每列的属性数据 returnMat[index, :] = listFromLine[0:3] - # 每列的类别数据 + # 每列的类别数据,就是 label 标签数据 classLabelVector.append(int(listFromLine[-1])) index += 1 # 返回数据矩阵returnMat和对应的类别classLabelVector @@ -134,6 +151,7 @@ def autoNorm(dataSet): 归一化公式: Y = (X-Xmin)/(Xmax-Xmin) + 其中的 min 和 max 分别是数据集中的最小特征值和最大特征值。该函数可以自动将数字特征值转化为0到1的区间。 """ # 计算每种属性的最大值、最小值、范围 minVals = dataSet.min(0) @@ -160,6 +178,7 @@ def datingClassTest(): datingDataMat, datingLabels = file2matrix('input/2.KNN/datingTestSet2.txt') # load data setfrom file # 归一化数据 normMat, ranges, minVals = autoNorm(datingDataMat) + # m 表示数据的行数,即矩阵的第一维 m = normMat.shape[0] # 设置测试的样本数量, numTestVecs:m表示训练样本的数量 numTestVecs = int(m * hoRatio) @@ -177,8 +196,10 @@ def datingClassTest(): def img2vector(filename): """ 将图像数据转换为向量 - :param filename: 图片文件 - :return: 一纬矩阵 + :param filename: 图片文件 因为我们的输入数据的图片格式是 32 * 32的 + :return: 一维矩阵 + 该函数将图像转换为向量:该函数创建 1 * 1024 的NumPy数组,然后打开给定的文件, + 循环读出文件的前32行,并将每行的头32个字符值存储在NumPy数组中,最后返回数组。 """ returnVect = zeros((1, 1024)) fr = open(filename) @@ -221,6 +242,6 @@ def handwritingClassTest(): if __name__ == '__main__': - # test1() + test1() # datingClassTest() - handwritingClassTest() + # handwritingClassTest() diff --git a/src/python/2.KNN/sklearn-knn-demo.py b/src/python/2.KNN/sklearn-knn-demo.py new file mode 100644 index 00000000..289e9861 --- /dev/null +++ b/src/python/2.KNN/sklearn-knn-demo.py @@ -0,0 +1,69 @@ +#!/usr/bin/python +# coding:utf8 + +""" +Created on 2017-06-28 +Updated on 2017-06-28 +KNN:k近邻算法 +@author: 小瑶 +《机器学习实战》更新地址:https://github.com/apachecn/MachineLearning +""" +print(__doc__) + +import numpy as np +import matplotlib.pyplot as plt +from numpy import * +from matplotlib.colors import ListedColormap +from sklearn import neighbors, datasets + +n_neighbors = 3 + +# 导入一些要玩的数据 +# iris = datasets.load_iris() +# X = iris.data[:, :2] # 我们只采用前两个feature. 我们可以使用二维数据集避免这个丑陋的切片 +# y = iris.target + +# print 'X=', type(X), X +# print 'y=', type(y), y + +X = array([[-1.0, -1.1], [-1.0, -1.0], [0, 0], [1.0, 1.1], [2.0, 2.0], [2.0, 2.1]]) +y = array([0, 0, 0, 1, 1, 1]) + +# print 'X=', type(X), X +# print 'y=', type(y), y + +h = .02 # 网格中的步长 + +# 创建彩色的地图 +# cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF']) +# cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF']) + +cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA']) +cmap_bold = ListedColormap(['#FF0000', '#00FF00']) + +for weights in ['uniform', 'distance']: + # 我们创建了一个knn分类器的实例,并适合数据。 + clf = neighbors.KNeighborsClassifier(n_neighbors, weights=weights) + clf.fit(X, y) + + # 绘制决策边界。为此,我们将为每个分配一个颜色 + # 来绘制网格中的点 [x_min, x_max]x[y_min, y_max]. + x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 + y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 + xx, yy = np.meshgrid(np.arange(x_min, x_max, h), + np.arange(y_min, y_max, h)) + Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) + + # 将结果放入一个彩色图中 + Z = Z.reshape(xx.shape) + plt.figure() + plt.pcolormesh(xx, yy, Z, cmap=cmap_light) + + # 绘制训练点 + plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold) + plt.xlim(xx.min(), xx.max()) + plt.ylim(yy.min(), yy.max()) + plt.title("3-Class classification (k = %i, weights = '%s')" + % (n_neighbors, weights)) + +plt.show() \ No newline at end of file diff --git a/src/python/3.DecisionTree/DecisionTree.py b/src/python/3.DecisionTree/DecisionTree.py index 092d9d0b..89675d73 100755 --- a/src/python/3.DecisionTree/DecisionTree.py +++ b/src/python/3.DecisionTree/DecisionTree.py @@ -38,7 +38,7 @@ def createDataSet(): def calcShannonEnt(dataSet): - """calcShannonEnt(calculate Shannon entropy 计算label分类标签的香农熵) + """calcShannonEnt(calculate Shannon entropy 计算给定数据集的香农熵) Args: dataSet 数据集 @@ -47,13 +47,17 @@ def calcShannonEnt(dataSet): """ # 求list的长度,表示计算参与训练的数据量 numEntries = len(dataSet) + # 下面输出我们测试的数据集的一些信息 + # 例如: numEntries: 5 是下面的代码的输出 # print type(dataSet), 'numEntries: ', numEntries # 计算分类标签label出现的次数 labelCounts = {} # the the number of unique elements and their occurance for featVec in dataSet: + # 将当前实例的标签存储,即每一行数据的最后一个数据代表的是标签 currentLabel = featVec[-1] + # 为所有可能的分类创建字典,如果当前的键值不存在,则扩展字典并将当前键值加入字典。每个键值都记录了当前类别出现的次数。 if currentLabel not in labelCounts.keys(): labelCounts[currentLabel] = 0 labelCounts[currentLabel] += 1 @@ -62,8 +66,10 @@ def calcShannonEnt(dataSet): # 对于label标签的占比,求出label标签的香农熵 shannonEnt = 0.0 for key in labelCounts: + # 使用所有类标签的发生频率计算类别出现的概率。 prob = float(labelCounts[key])/numEntries # log base 2 + # 计算香农熵,以 2 为底求对数 shannonEnt -= prob * log(prob, 2) # print '---', prob, prob * log(prob, 2), shannonEnt return shannonEnt @@ -71,24 +77,42 @@ def calcShannonEnt(dataSet): def splitDataSet(dataSet, axis, value): """splitDataSet(通过遍历dataSet数据集,求出axis对应的colnum列的值为value的行) - + 就是依据axis列进行分类,如果axis列的数据等于 value的时候,就要将 axis 划分到我们创建的新的数据集中 Args: - dataSet 数据集 - axis 表示每一行的axis列 - value 表示axis列对应的value值 + dataSet 数据集 待划分的数据集 + axis 表示每一行的axis列 划分数据集的特征 + value 表示axis列对应的value值 需要返回的特征的值。 Returns: axis列为value的数据集【该数据集需要排除axis列】 """ retDataSet = [] - for featVec in dataSet: + for featVec in dataSet: # axis列为value的数据集【该数据集需要排除axis列】 + # 判断axis列的值是否为value if featVec[axis] == value: # chop out axis used for splitting + # [:axis]表示前axis行,即若 axis 为2,就是取 featVec 的前 axis 行 reducedFeatVec = featVec[:axis] ''' 请百度查询一下: extend和append的区别 + list.append(object) 向列表中添加一个对象object + list.extend(sequence) 把一个序列seq的内容添加到列表中 + 1、使用append的时候,是将new_media看作一个对象,整体打包添加到music_media对象中。 + 2、使用extend的时候,是将new_media看作一个序列,将这个序列和music_media序列合并,并放在其后面。 + result = [] + result.extend([1,2,3]) + print result + result.append([4,5,6]) + print result + result.extend([7,8,9]) + print result + 结果: + [1, 2, 3] + [1, 2, 3, [4, 5, 6]] + [1, 2, 3, [4, 5, 6], 7, 8, 9 ''' reducedFeatVec.extend(featVec[axis+1:]) + # [axis+1:]表示从跳过 axis 的 axis+1行,取接下来的数据 # 收集结果值 axis列为value的行【该行需要排除axis列】 retDataSet.append(reducedFeatVec) return retDataSet @@ -111,19 +135,21 @@ def chooseBestFeatureToSplit(dataSet): # iterate over all the features for i in range(numFeatures): # create a list of all the examples of this feature - # 获取每一个feature的list集合 + # 获取每一个实例的第i+1个feature,组成list集合 featList = [example[i] for example in dataSet] # get a set of unique values - # 获取剔重后的集合 + # 获取剔重后的集合,使用set对list数据进行去重 uniqueVals = set(featList) # 创建一个临时的信息熵 newEntropy = 0.0 - # 遍历某一列的value集合,计算该列的信息熵 + # 遍历某一列的value集合,计算该列的信息熵 + # 遍历当前特征中的所有唯一属性值,对每个唯一属性值划分一次数据集,计算数据集的新熵值,并对所有唯一特征值得到的熵求和。 for value in uniqueVals: subDataSet = splitDataSet(dataSet, i, value) prob = len(subDataSet)/float(len(dataSet)) newEntropy += prob * calcShannonEnt(subDataSet) # gain[信息增益]: 划分数据集前后的信息变化, 获取信息熵最大的值 + # 信息增益是熵的减少或者是数据无序度的减少。最后,比较所有特征中的信息增益,返回最好特征划分的索引值。 infoGain = baseEntropy - newEntropy print 'infoGain=', infoGain, 'bestFeature=', i, baseEntropy, newEntropy if (infoGain > bestInfoGain): @@ -145,7 +171,7 @@ def majorityCnt(classList): if vote not in classCount.keys(): classCount[vote] = 0 classCount[vote] += 1 - # 倒叙排列classCount得到一个字典集合,然后取出第一个就是结果(yes/no) + # 倒叙排列classCount得到一个字典集合,然后取出第一个就是结果(yes/no),即出现次数最多的结果 sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True) # print 'sortedClassCount:', sortedClassCount return sortedClassCount[0][0] @@ -154,13 +180,16 @@ def majorityCnt(classList): def createTree(dataSet, labels): classList = [example[-1] for example in dataSet] # 如果数据集的最后一列的第一个值出现的次数=整个集合的数量,也就说只有一个类别,就只直接返回结果就行 + # 第一个停止条件:所有的类标签完全相同,则直接返回该类标签。 + # count() 函数是统计括号中的值在list中出现的次数 if classList.count(classList[0]) == len(classList): return classList[0] # 如果数据集只有1列,那么最初出现label次数最多的一类,作为结果 + # 第二个停止条件:使用完了所有特征,仍然不能将数据集划分成仅包含唯一类别的分组。 if len(dataSet[0]) == 1: return majorityCnt(classList) - # 选择最优的列,得到最有列对应的label含义 + # 选择最优的列,得到最优列对应的label含义 bestFeat = chooseBestFeatureToSplit(dataSet) # 获取label的名称 bestFeatLabel = labels[bestFeat] @@ -175,6 +204,7 @@ def createTree(dataSet, labels): for value in uniqueVals: # 求出剩余的标签label subLabels = labels[:] + # 遍历当前选择特征包含的所有属性值,在每个数据集划分上递归调用函数createTree() myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels) # print 'myTree', value, myTree return myTree diff --git a/src/python/3.DecisionTree/decisionTreePlot.pyc b/src/python/3.DecisionTree/decisionTreePlot.pyc index 826e38d7..ccd079b1 100644 Binary files a/src/python/3.DecisionTree/decisionTreePlot.pyc and b/src/python/3.DecisionTree/decisionTreePlot.pyc differ diff --git a/src/python/3.DecisionTree/skelearn_dts_regressor_demo.py b/src/python/3.DecisionTree/skelearn_dts_regressor_demo.py new file mode 100644 index 00000000..4aaa2cc0 --- /dev/null +++ b/src/python/3.DecisionTree/skelearn_dts_regressor_demo.py @@ -0,0 +1,56 @@ +#!/usr/bin/python +# coding:utf8 + +""" +Created on 2017-06-29 +Updated on 2017-06-29 +DecisionTree:决策树 +@author: 小瑶 +《机器学习实战》更新地址:https://github.com/apachecn/MachineLearning +""" + +print(__doc__) + +# 引入必要的模型和库 +import numpy as np +from sklearn.tree import DecisionTreeRegressor +import matplotlib.pyplot as plt + +# 创建一个随机的数据集 +# 参考 https://docs.scipy.org/doc/numpy-1.6.0/reference/generated/numpy.random.mtrand.RandomState.html +rng = np.random.RandomState(1) +print 'lalalalala===', rng +# rand() 是给定形状的随机值,rng.rand(80, 1)即矩阵的形状是 80行,1列 +# sort() +X = np.sort(5 * rng.rand(80, 1), axis=0) +print 'X=', X +y = np.sin(X).ravel() +print 'y=', y +y[::5] += 3 * (0.5 - rng.rand(16)) +print 'yyy=', y + +# 拟合回归模型 +regr_1 = DecisionTreeRegressor(max_depth=2) +regr_2 = DecisionTreeRegressor(max_depth=5) +regr_3 = DecisionTreeRegressor(max_depth=3) +regr_1.fit(X, y) +regr_2.fit(X, y) +regr_3.fit(X, y) + +# 预测 +X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis] +y_1 = regr_1.predict(X_test) +y_2 = regr_2.predict(X_test) +y_3 = regr_3.predict(X_test) + +# 绘制结果 +plt.figure() +plt.scatter(X, y, c="darkorange", label="data") +plt.plot(X_test, y_1, color="cornflowerblue", label="max_depth=2", linewidth=2) +plt.plot(X_test, y_2, color="yellowgreen", label="max_depth=5", linewidth=2) +plt.plot(X_test, y_3, color="red", label="max_depth=3", linewidth=2) +plt.xlabel("data") +plt.ylabel("target") +plt.title("Decision Tree Regression") +plt.legend() +plt.show() \ No newline at end of file diff --git a/src/python/3.DecisionTree/sklearn_dts_classify_demo.py b/src/python/3.DecisionTree/sklearn_dts_classify_demo.py new file mode 100644 index 00000000..15f5131e --- /dev/null +++ b/src/python/3.DecisionTree/sklearn_dts_classify_demo.py @@ -0,0 +1,61 @@ +#!/usr/bin/python +# coding:utf8 + +""" +Created on 2017-06-29 +Updated on 2017-06-29 +DecisionTree:决策树 +@author: 小瑶 +《机器学习实战》更新地址:https://github.com/apachecn/MachineLearning +""" +print(__doc__) + +import numpy as np +import matplotlib.pyplot as plt + +from sklearn.datasets import load_iris +from sklearn.tree import DecisionTreeClassifier + +# 参数 +n_classes = 3 +plot_colors = "bry" +plot_step = 0.02 + +# 加载数据 +iris = load_iris() + +for pairidx, pair in enumerate([[0, 1], [0, 2], [0, 3], [1, 2], [1, 3], [2, 3]]): + # 我们只用两个相应的features + X = iris.data[:, pair] + y = iris.target + + # 训练 + clf = DecisionTreeClassifier().fit(X, y) + + # 绘制决策边界 + plt.subplot(2, 3, pairidx + 1) + + x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 + y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 + xx, yy = np.meshgrid(np.arange(x_min, x_max, plot_step), + np.arange(y_min, y_max, plot_step)) + + Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) + Z = Z.reshape(xx.shape) + cs = plt.contourf(xx, yy, Z, cmap=plt.cm.Paired) + + plt.xlabel(iris.feature_names[pair[0]]) + plt.ylabel(iris.feature_names[pair[1]]) + plt.axis("tight") + + # 绘制训练点 + for i, color in zip(range(n_classes), plot_colors): + idx = np.where(y == i) + plt.scatter(X[idx, 0], X[idx, 1], c=color, label=iris.target_names[i], + cmap=plt.cm.Paired) + + plt.axis("tight") + +plt.suptitle("Decision surface of a decision tree using paired features") +plt.legend() +plt.show() diff --git a/src/python/4.NaiveBayes/bayes.py b/src/python/4.NaiveBayes/bayes.py index eb4f47f3..5ace46fd 100755 --- a/src/python/4.NaiveBayes/bayes.py +++ b/src/python/4.NaiveBayes/bayes.py @@ -3,7 +3,7 @@ ''' Created on Oct 19, 2010 Update on 2017-05-18 -@author: Peter Harrington/羊山 +@author: Peter Harrington/羊三/小瑶 《机器学习实战》更新地址:https://github.com/apachecn/MachineLearning ''' from numpy import * @@ -36,18 +36,21 @@ def createVocabList(dataSet): """ vocabSet = set([]) # create empty set for document in dataSet: + # 操作符 | 用于求两个集合的并集 vocabSet = vocabSet | set(document) # union of the two sets return list(vocabSet) def setOfWords2Vec(vocabList, inputSet): """ - 遍历查看该单词属否出现,出现该单词则将该单词置1 + 遍历查看该单词是否出现,出现该单词则将该单词置1 :param vocabList: 所有单词集合列表 :param inputSet: 输入数据集 - :return: 匹配列表[0,1,0,1...] + :return: 匹配列表[0,1,0,1...],其中 1与0 表示词汇表中的单词是否出现在输入的数据集中 """ + # 创建一个和词汇表等长的向量,并将其元素都设置为0 returnVec = [0] * len(vocabList)# [0,0......] + # 遍历文档中的所有单词,如果出现了词汇表中的单词,则将输出的文档向量中的对应值设为1 for word in inputSet: if word in vocabList: returnVec[vocabList.index(word)] = 1 @@ -60,14 +63,15 @@ def _trainNB0(trainMatrix, trainCategory): """ 训练数据原版 :param trainMatrix: 文件单词矩阵 [[1,0,1,1,1....],[],[]...] - :param trainCategory: 文件对应的类别[0,1,1,0....] + :param trainCategory: 文件对应的类别[0,1,1,0....],列表长度等于单词矩阵数,其中的1代表对应的文件是侮辱性文件,0代表不是侮辱性矩阵 :return: """ # 文件数 numTrainDocs = len(trainMatrix) # 单词数 numWords = len(trainMatrix[0]) - # 侮辱性文件的出现概率 + # 侮辱性文件的出现概率,即trainCategory中所有的1的个数, + # 代表的就是多少个侮辱性文件,与文件的总数相除就得到了侮辱性文件的出现概率 pAbusive = sum(trainCategory) / float(numTrainDocs) # 构造单词出现次数列表 p0Num = zeros(numWords) # [0,0,0,.....] @@ -77,10 +81,12 @@ def _trainNB0(trainMatrix, trainCategory): p0Denom = 0.0 p1Denom = 0.0 for i in range(numTrainDocs): + # 遍历所有的文件,如果是侮辱性文件,就计算此侮辱性文件中出现的侮辱性单词的个数 if trainCategory[i] == 1: p1Num += trainMatrix[i] #[0,1,1,....]->[0,1,1,...] p1Denom += sum(trainMatrix[i]) else: + # 如果不是侮辱性文件,则计算非侮辱性文件中出现的侮辱性单词的个数 p0Num += trainMatrix[i] p0Denom += sum(trainMatrix[i]) # 类别1,即侮辱性文档的[P(F1|C1),P(F2|C1),P(F3|C1),P(F4|C1),P(F5|C1)....]列表 @@ -133,16 +139,18 @@ def trainNB0(trainMatrix, trainCategory): def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1): """ 使用算法: - # 将乘法转坏为加法 + # 将乘法转换为加法 乘法:P(C|F1F2...Fn) = P(F1F2...Fn|C)P(C)/P(F1F2...Fn) 加法:P(F1|C)*P(F2|C)....P(Fn|C)P(C) -> log(P(F1|C))+log(P(F2|C))+....+log(P(Fn|C))+log(P(C)) - :param vec2Classify: 待测数据[0,1,1,1,1...] - :param p0Vec: 类别1,即侮辱性文档的[log(P(F1|C1)),log(P(F2|C1)),log(P(F3|C1)),log(P(F4|C1)),log(P(F5|C1))....]列表 - :param p1Vec: 类别0,即正常文档的[log(P(F1|C0)),log(P(F2|C0)),log(P(F3|C0)),log(P(F4|C0)),log(P(F5|C0))....]列表 + :param vec2Classify: 待测数据[0,1,1,1,1...],即要分类的向量 + :param p0Vec: 类别0,即正常文档的[log(P(F1|C0)),log(P(F2|C0)),log(P(F3|C0)),log(P(F4|C0)),log(P(F5|C0))....]列表 + :param p1Vec: 类别1,即侮辱性文档的[log(P(F1|C1)),log(P(F2|C1)),log(P(F3|C1)),log(P(F4|C1)),log(P(F5|C1))....]列表 :param pClass1: 类别1,侮辱性文件的出现概率 :return: 类别1 or 0 """ # 计算公式 log(P(F1|C))+log(P(F2|C))+....+log(P(Fn|C))+log(P(C)) + # 使用 NumPy 数组来计算两个向量相乘的结果,这里的相乘是指对应元素相乘,即先将两个向量中的第一个元素相乘,然后将第2个元素相乘,以此类推。 + # 我的理解是:这里的 vec2Classify * p1Vec 的意思就是将每个词与其对应的概率相关联起来 p1 = sum(vec2Classify * p1Vec) + log(pClass1) p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1) if p1 > p0: diff --git a/src/python/4.NaiveBayes/sklearn-nb-demo.py b/src/python/4.NaiveBayes/sklearn-nb-demo.py new file mode 100644 index 00000000..36e758cf --- /dev/null +++ b/src/python/4.NaiveBayes/sklearn-nb-demo.py @@ -0,0 +1,80 @@ +#!/usr/bin/python +# coding:utf8 + +""" +Created on 2017-06-28 +Updated on 2017-06-28 +NaiveBayes:朴素贝叶斯 +@author: 小瑶 +《机器学习实战》更新地址:https://github.com/apachecn/MachineLearning +""" +import numpy as np +import matplotlib.pyplot as plt +from sklearn import svm +print(__doc__) + + +# 创建40个分离点 +np.random.seed(0) +# X = np.r_[np.random.randn(20, 2) - [2, 2], np.random.randn(20, 2) + [2, 2]] +# Y = [0] * 20 + [1] * 20 + + +def loadDataSet(fileName): + """ + 对文件进行逐行解析,从而得到第行的类标签和整个数据矩阵 + Args: + fileName 文件名 + Returns: + dataMat 数据矩阵 + labelMat 类标签 + """ + dataMat = [] + labelMat = [] + fr = open(fileName) + for line in fr.readlines(): + lineArr = line.strip().split('\t') + dataMat.append([float(lineArr[0]), float(lineArr[1])]) + labelMat.append(float(lineArr[2])) + return dataMat, labelMat + + +X, Y = loadDataSet('input/6.SVM/testSet.txt') +X = np.mat(X) + +print("X=", X) +print("Y=", Y) + +# 拟合一个SVM模型 +clf = svm.SVC(kernel='linear') +clf.fit(X, Y) + +# 获取分割超平面 +w = clf.coef_[0] +# 斜率 +a = -w[0] / w[1] +# 从-5到5,顺序间隔采样50个样本,默认是num=50 +# xx = np.linspace(-5, 5) # , num=50) +xx = np.linspace(-2, 10) # , num=50) +# 二维的直线方程 +yy = a * xx - (clf.intercept_[0]) / w[1] +print("yy=", yy) + +# plot the parallels to the separating hyperplane that pass through the support vectors +# 通过支持向量绘制分割超平面 +print("support_vectors_=", clf.support_vectors_) +b = clf.support_vectors_[0] +yy_down = a * xx + (b[1] - a * b[0]) +b = clf.support_vectors_[-1] +yy_up = a * xx + (b[1] - a * b[0]) + +# plot the line, the points, and the nearest vectors to the plane +plt.plot(xx, yy, 'k-') +plt.plot(xx, yy_down, 'k--') +plt.plot(xx, yy_up, 'k--') + +plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=80, facecolors='none') +plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=plt.cm.Paired) + +plt.axis('tight') +plt.show() diff --git a/src/python/5.Logistic/logistic.py b/src/python/5.Logistic/logistic.py index c312f890..af834873 100644 --- a/src/python/5.Logistic/logistic.py +++ b/src/python/5.Logistic/logistic.py @@ -5,7 +5,7 @@ Created on Oct 27, 2010 Update on 2017-05-18 Logistic Regression Working Module -@author: Peter Harrington/羊山 +@author: Peter Harrington/羊三/小瑶 《机器学习实战》更新地址:https://github.com/apachecn/MachineLearning ''' from numpy import * @@ -19,6 +19,7 @@ def loadDataSet(file_name): fr = open(file_name) for line in fr.readlines(): lineArr = line.strip().split() + # 将 X0 的值设为 1.0 dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) labelMat.append(int(lineArr[2])) return dataMat,labelMat @@ -29,33 +30,37 @@ def sigmoid(inX): # 正常的处理方案 +# 两个参数:第一个参数==> dataMatIn 是一个2维NumPy数组,每列分别代表每个不同的特征,每行则代表每个训练样本。 +# 第二个参数==> classLabels 是类别标签,它是一个 1*100 的行向量。为了便于矩阵计算,需要将该行向量转换为列向量,做法是将原向量转置,再将它赋值给labelMat。 def gradAscent(dataMatIn, classLabels): # 转化为矩阵[[1,1,2],[1,1,2]....] - dataMatrix = mat(dataMatIn) #convert to NumPy matrix + dataMatrix = mat(dataMatIn) # 转换为 NumPy 矩阵 # 转化为矩阵[[0,1,0,1,0,1.....]],并转制[[0],[1],[0].....] - # transpose() 行列转制函数 - # 将行矩阵转化为列矩阵 => 矩阵的转置 - labelMat = mat(classLabels).transpose() #convert to NumPy matrix - # m->数据量 n->特征数 + # transpose() 行列转置函数 + # 将行向量转化为列向量 => 矩阵的转置 + labelMat = mat(classLabels).transpose() # 首先将数组转换为 NumPy 矩阵,然后再将行向量转置为列向量 + # m->数据量,样本数 n->特征数 m,n = shape(dataMatrix) # print m, n, '__'*10, shape(dataMatrix.transpose()), '__'*100 - # 步长 + # alpha代表向目标移动的步长 alpha = 0.001 # 迭代次数 maxCycles = 500 # 生成一个长度和特征数相同的矩阵,此处n为3 -> [[1],[1],[1]] - # 回归系数 + # weights 代表回归系数, 此处的 ones((n,1)) 创建一个长度和特征数相同的矩阵,其中的数全部都是 1 weights = ones((n,1)) for k in range(maxCycles): #heavy on matrix operations - # m*3的矩阵 * 3*1的单位矩阵 = m*1的矩阵 + # m*3 的矩阵 * 3*1 的单位矩阵 = m*1的矩阵 # 那么乘上单位矩阵的意义,就代表:通过公式得到的理论值 # 参考地址: 矩阵乘法的本质是什么? https://www.zhihu.com/question/21351965/answer/31050145 + # print 'dataMatrix====', dataMatrix + # print 'weights====', weights # n*3 * 3*1 = n*1 - h = sigmoid(dataMatrix*weights) #matrix mult + h = sigmoid(dataMatrix*weights) # 矩阵乘法 # labelMat是实际值 - error = (labelMat - h) #vector subtraction + error = (labelMat - h) # 向量相减 # 0.001* (3*m)*(m*1) 表示在每一个列上的一个误差情况,最后得出 x1,x2,xn的系数的偏移量 - weights = weights + alpha * dataMatrix.transpose() * error #matrix mult + weights = weights + alpha * dataMatrix.transpose() * error # 矩阵乘法,最后得到回归系数 return array(weights) @@ -67,10 +72,12 @@ def stocGradAscent0(dataMatrix, classLabels): alpha = 0.01 # n*1的矩阵 # 函数ones创建一个全1的数组 - weights = ones(n) #initialize to all ones + weights = ones(n) # 初始化长度为n的数组,元素全部为 1 for i in range(m): - # sum(dataMatrix[i]*weights)为了求 f(x)的值, f(x)=a1*x1+b2*x2+..+nn*xn + # sum(dataMatrix[i]*weights)为了求 f(x)的值, f(x)=a1*x1+b2*x2+..+nn*xn,此处求出的 h 是一个具体的数值,而不是一个矩阵 h = sigmoid(sum(dataMatrix[i]*weights)) + # print 'dataMatrix[i]===', dataMatrix[i] + # 计算真实类别与预测类别之间的差值,然后按照该差值调整回归系数 error = classLabels[i] - h # 0.01*(1*1)*(1*n) print weights, "*"*10 , dataMatrix[i], "*"*10 , error @@ -81,16 +88,17 @@ def stocGradAscent0(dataMatrix, classLabels): # 随机梯度上升算法(随机化) def stocGradAscent1(dataMatrix, classLabels, numIter=150): m,n = shape(dataMatrix) - weights = ones(n) #initialize to all ones - # 随机剃度, 循环150,观察是否收敛 + weights = ones(n) # 创建与列数相同的矩阵的系数矩阵,所有的元素都是1 + # 随机梯度, 循环150,观察是否收敛 for j in range(numIter): # [0, 1, 2 .. m-1] dataIndex = range(m) for i in range(m): # i和j的不断增大,导致alpha的值不断减少,但是不为0 - alpha = 4/(1.0+j+i)+0.0001 #apha decreases with iteration, does not + alpha = 4/(1.0+j+i)+0.0001 # alpha 会随着迭代不断减小,但永远不会减小到0,因为后边还有一个常数项0.0001 # 随机产生一个 0~len()之间的一个值 - randIndex = int(random.uniform(0,len(dataIndex)))#go to 0 because of the constant + # random.uniform(x, y) 方法将随机生成下一个实数,它在[x,y]范围内,x是这个范围内的最小值,y是这个范围内的最大值。 + randIndex = int(random.uniform(0,len(dataIndex))) # sum(dataMatrix[i]*weights)为了求 f(x)的值, f(x)=a1*x1+b2*x2+..+nn*xn h = sigmoid(sum(dataMatrix[randIndex]*weights)) error = classLabels[randIndex] - h @@ -139,8 +147,8 @@ def main(): dataArr = array(dataMat) # print dataArr # weights = gradAscent(dataArr, labelMat) - # weights = stocGradAscent0(dataArr, labelMat) - weights = stocGradAscent1(dataArr, labelMat) + weights = stocGradAscent0(dataArr, labelMat) + # weights = stocGradAscent1(dataArr, labelMat) # print '*'*30, weights # 数据可视化 diff --git a/src/python/8.Predictive numerical data regression/regression.py b/src/python/8.Predictive numerical data regression/regression.py index a1e72f42..4e6e0884 100644 --- a/src/python/8.Predictive numerical data regression/regression.py +++ b/src/python/8.Predictive numerical data regression/regression.py @@ -12,52 +12,58 @@ Update on 2017-05-18 from numpy import * import matplotlib.pylab as plt -def loadDataSet(fileName): #解析以tab键分隔的文件中的浮点数 - numFeat = len(open(fileName).readline().split('\t')) - 1 #获得每一行的输入数据,最后一个代表真实值 +def loadDataSet(fileName): # 解析以tab键分隔的文件中的浮点数 + """ 加载数据 + Returns: + dataMat feature 对应的数据集 + labelMat feature 对应的分类标签,即类别标签 + + """ + numFeat = len(open(fileName).readline().split('\t')) - 1 # 获得每一行的输入数据,最后一个代表真实值 dataMat = []; labelMat = [] fr = open(fileName) - for line in fr.readlines(): #读取每一行 + for line in fr.readlines(): # 读取每一行 lineArr =[] - curLine = line.strip().split('\t') #删除一行中以tab分隔的数据前后的空白符号 - for i in range(numFeat): #从0到2,不包括2 - lineArr.append(float(curLine[i]))#将数据添加到lineArr List中,每一行数据测试数据组成一个行向量 - dataMat.append(lineArr) #将测试数据的输入数据部分存储到dataMat矩阵中 - labelMat.append(float(curLine[-1]))#将每一行的最后一个数据,即真实的目标变量存储到labelMat矩阵中 + curLine = line.strip().split('\t') # 删除一行中以tab分隔的数据前后的空白符号 + for i in range(numFeat): # 从0到2,不包括2 + lineArr.append(float(curLine[i]))# 将数据添加到lineArr List中,每一行数据测试数据组成一个行向量 + dataMat.append(lineArr) # 将测试数据的输入数据部分存储到dataMat矩阵中 + labelMat.append(float(curLine[-1]))# 将每一行的最后一个数据,即真实的目标变量存储到labelMat矩阵中 return dataMat,labelMat -def standRegres(xArr,yArr): #线性回归 - xMat = mat(xArr); yMat = mat(yArr).T #mat()函数将xArr,yArr转换为矩阵 - xTx = xMat.T*xMat #矩阵乘法的条件是左矩阵的列数等于右矩阵的行数 - if linalg.det(xTx) == 0.0: #因为要用到xTx的逆矩阵,所以事先需要确定计算得到的xTx是否可逆,条件是矩阵的行列式不为0 +def standRegres(xArr,yArr): # 线性回归 + xMat = mat(xArr); yMat = mat(yArr).T # mat()函数将xArr,yArr转换为矩阵 + xTx = xMat.T*xMat # 矩阵乘法的条件是左矩阵的列数等于右矩阵的行数 + if linalg.det(xTx) == 0.0: # 因为要用到xTx的逆矩阵,所以事先需要确定计算得到的xTx是否可逆,条件是矩阵的行列式不为0 print ("This matrix is singular, cannot do inverse") return # 最小二乘法 # http://www.apache.wiki/pages/viewpage.action?pageId=5505133 - ws = xTx.I * (xMat.T*yMat) #书中的公式,求得w的最优解 + ws = xTx.I * (xMat.T*yMat) # 书中的公式,求得w的最优解 return ws -def lwlr(testPoint,xArr,yArr,k=1.0): #局部加权线性回归 +def lwlr(testPoint,xArr,yArr,k=1.0): # 局部加权线性回归 xMat = mat(xArr); yMat = mat(yArr).T - m = shape(xMat)[0] #获得xMat矩阵的行数 - weights = mat(eye((m))) #eye()返回一个对角线元素为1,其他元素为0的二维数组,创建权重矩阵 - for j in range(m): #下面两行创建权重矩阵 - diffMat = testPoint - xMat[j,:] #遍历数据集,计算每个样本点对应的权重值 + m = shape(xMat)[0] # 获得xMat矩阵的行数 + weights = mat(eye((m))) # eye()返回一个对角线元素为1,其他元素为0的二维数组,创建权重矩阵 + for j in range(m): # 下面两行创建权重矩阵 + diffMat = testPoint - xMat[j,:] # 遍历数据集,计算每个样本点对应的权重值 weights[j,j] = exp(diffMat*diffMat.T/(-2.0*k**2))#k控制衰减的速度 xTx = xMat.T * (weights * xMat) if linalg.det(xTx) == 0.0: print ("This matrix is singular, cannot do inverse") return - ws = xTx.I * (xMat.T * (weights * yMat)) #计算出回归系数的一个估计 + ws = xTx.I * (xMat.T * (weights * yMat)) # 计算出回归系数的一个估计 return testPoint * ws -def lwlrTest(testArr,xArr,yArr,k=1.0): #循环所有的数据点,并将lwlr运用于所有的数据点 +def lwlrTest(testArr,xArr,yArr,k=1.0): # 循环所有的数据点,并将lwlr运用于所有的数据点 m = shape(testArr)[0] yHat = zeros(m) for i in range(m): yHat[i] = lwlr(testArr[i],xArr,yArr,k) return yHat -def lwlrTestPlot(xArr,yArr,k=1.0): #首先将 X 排序,其余的都与lwlrTest相同,这样更容易绘图 +def lwlrTestPlot(xArr,yArr,k=1.0): # 首先将 X 排序,其余的都与lwlrTest相同,这样更容易绘图 yHat = zeros(shape(yArr)) xCopy = mat(xArr) xCopy.sort(0) @@ -65,13 +71,13 @@ def lwlrTestPlot(xArr,yArr,k=1.0): #首先将 X 排序,其余的都与lwlrTes yHat[i] = lwlr(xCopy[i],xArr,yArr,k) return yHat,xCopy -def rssError(yArr,yHatArr): #yArr 和 yHatArr 两者都需要是数组 +def rssError(yArr,yHatArr): # yArr 和 yHatArr 两者都需要是数组 return ((yArr-yHatArr)**2).sum() -def ridgeRegres(xMat,yMat,lam=0.2): #岭回归 +def ridgeRegres(xMat,yMat,lam=0.2): # 岭回归 xTx = xMat.T*xMat - denom = xTx + eye(shape(xMat)[1])*lam #按照书上的公式计算计算回归系数 - if linalg.det(denom) == 0.0: #检查行列式是否为零,即矩阵是否可逆 + denom = xTx + eye(shape(xMat)[1])*lam # 按照书上的公式计算计算回归系数 + if linalg.det(denom) == 0.0: # 检查行列式是否为零,即矩阵是否可逆 print ("This matrix is singular, cannot do inverse") return ws = denom.I * (xMat.T*yMat) @@ -79,34 +85,34 @@ def ridgeRegres(xMat,yMat,lam=0.2): #岭回归 def ridgeTest(xArr,yArr): xMat = mat(xArr); yMat=mat(yArr).T - yMean = mean(yMat,0) #计算Y均值 - yMat = yMat - yMean #Y的所有的特征减去均值 - #标准化 x - xMeans = mean(xMat,0) #X计算平均值 - xVar = var(xMat,0) #然后计算 X的方差 + yMean = mean(yMat,0) # 计算Y均值 + yMat = yMat - yMean # Y的所有的特征减去均值 + # 标准化 x + xMeans = mean(xMat,0) # X计算平均值 + xVar = var(xMat,0) # 然后计算 X的方差 xMat = (xMat - xMeans)/xVar numTestPts = 30 - wMat = zeros((numTestPts,shape(xMat)[1]))#创建30 * m 的全部数据为0 的矩阵 + wMat = zeros((numTestPts,shape(xMat)[1]))# 创建30 * m 的全部数据为0 的矩阵 for i in range(numTestPts): - ws = ridgeRegres(xMat,yMat,exp(i-10))#exp返回e^x + ws = ridgeRegres(xMat,yMat,exp(i-10))# exp返回e^x wMat[i,:]=ws.T return wMat -def regularize(xMat):#按列进行规范化 +def regularize(xMat):# 按列进行规范化 inMat = xMat.copy() - inMeans = mean(inMat,0) #计算平均值然后减去它 - inVar = var(inMat,0) #计算除以Xi的方差 + inMeans = mean(inMat,0) # 计算平均值然后减去它 + inVar = var(inMat,0) # 计算除以Xi的方差 inMat = (inMat - inMeans)/inVar return inMat def stageWise(xArr,yArr,eps=0.01,numIt=100): xMat = mat(xArr); yMat=mat(yArr).T yMean = mean(yMat,0) - yMat = yMat - yMean #也可以规则化ys但会得到更小的coef + yMat = yMat - yMean # 也可以规则化ys但会得到更小的coef xMat = regularize(xMat) m,n=shape(xMat) - #returnMat = zeros((numIt,n)) #测试代码删除 + #returnMat = zeros((numIt,n)) # 测试代码删除 ws = zeros((n,1)); wsTest = ws.copy(); wsMax = ws.copy() for i in range(numIt): print (ws.T)