From 27d810c64decdbb543e742f2d6f56729244162c2 Mon Sep 17 00:00:00 2001 From: zeek <984294471@qq.com> Date: Sun, 23 Feb 2020 22:14:06 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=81=E7=A7=BB=E4=BB=93=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 6 + LICENSE | 8 + README.md | 45 + SUMMARY.md | 32 + basic/README.md | 13 + basic/deep_basic.md | 34 + basic/deep_learn.md | 45 + basic/evaluation.md | 90 + basic/math_basis.md | 43 + basic/pic/README.md | 12 + bayes/README.md | 81 + bayes/bayes.py | 83 + book.json | 75 + decisionTree/AllElectronics.py | 3 + decisionTree/README.md | 97 + decisionTree/pics/20170121190335074.png | Bin 0 -> 5851 bytes decisionTree/pics/812093045.png | Bin 0 -> 1934 bytes decisionTree/trees.py | 78 + index.html | 9 + knn/KNN.py | 13 + knn/README.md | 18 + knn/SklearnExample.py | 17 + knn/knn_test.py | 30 + logistic/LogRegres-gj.py | 231 ++ logistic/colicLogRegres.py | 193 ++ logistic/horseColicTest.txt | 67 + logistic/horseColicTraining.txt | 299 ++ logistic/log_regres.py | 189 + logistic/testSet.txt | 100 + ml.xml | 249 ++ nlp/README.md | 1 + nlp/word2vec.md | 2 + nn/README.md | 128 + nn/ResNet.md | 68 + nn/cnn.md | 64 + nn/handWrittenDigitsRecoginition.py | 30 + nn/multi_task.md | 4 + nn/neuralNetwork.py | 80 + nn/rnn.md | 37 + nn/testnn.py | 12 + nn/visualizeDigits.py | 13 + nn/残差resnet网络原理详解.docx | Bin 0 -> 280244 bytes regression/MultipleRegDelvery.py | 28 + regression/MultipleRegDelveryExample.py | 28 + regression/README.md | 62 + regression/SimpleLinearRegression.py | 37 + regression/abalone.py | 139 + regression/abalone.txt | 4177 +++++++++++++++++++++++ regression/ex0.txt | 200 ++ regression/lego.py | 282 ++ regression/lego/lego10030.html | 55 + regression/lego/lego10179.html | 55 + regression/lego/lego10181.html | 55 + regression/lego/lego10189.html | 55 + regression/lego/lego10196.html | 55 + regression/lego/lego8288.html | 43 + regression/log_regres.py | 107 + regression/multiple.csv | 10 + regression/multipleDummy.csv | 13 + regression/regression.py | 204 ++ regression/regression_old.py | 198 ++ regression/testSet.txt | 100 + regression/线性模型.md | 96 + rl/README.md | 57 + sitmap-generator.py | 71 + svm/README.md | 13 + svm/svm-digits.py | 329 ++ svm/svm-simple.py | 270 ++ svm/svm-smo.py | 291 ++ svm/svm-svc.py | 91 + svm/svmMLiA.py | 313 ++ svm/testSet.txt | 100 + svm/testSetRBF.txt | 100 + svm/testSetRBF2.txt | 100 + targetDetection/README.md | 38 + 75 files changed, 10371 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 SUMMARY.md create mode 100644 basic/README.md create mode 100644 basic/deep_basic.md create mode 100644 basic/deep_learn.md create mode 100644 basic/evaluation.md create mode 100644 basic/math_basis.md create mode 100644 basic/pic/README.md create mode 100644 bayes/README.md create mode 100755 bayes/bayes.py create mode 100644 book.json create mode 100755 decisionTree/AllElectronics.py create mode 100644 decisionTree/README.md create mode 100644 decisionTree/pics/20170121190335074.png create mode 100644 decisionTree/pics/812093045.png create mode 100755 decisionTree/trees.py create mode 100644 index.html create mode 100755 knn/KNN.py create mode 100644 knn/README.md create mode 100755 knn/SklearnExample.py create mode 100755 knn/knn_test.py create mode 100755 logistic/LogRegres-gj.py create mode 100755 logistic/colicLogRegres.py create mode 100644 logistic/horseColicTest.txt create mode 100644 logistic/horseColicTraining.txt create mode 100755 logistic/log_regres.py create mode 100644 logistic/testSet.txt create mode 100644 ml.xml create mode 100644 nlp/README.md create mode 100644 nlp/word2vec.md create mode 100644 nn/README.md create mode 100644 nn/ResNet.md create mode 100644 nn/cnn.md create mode 100755 nn/handWrittenDigitsRecoginition.py create mode 100644 nn/multi_task.md create mode 100755 nn/neuralNetwork.py create mode 100644 nn/rnn.md create mode 100755 nn/testnn.py create mode 100755 nn/visualizeDigits.py create mode 100644 nn/残差resnet网络原理详解.docx create mode 100755 regression/MultipleRegDelvery.py create mode 100755 regression/MultipleRegDelveryExample.py create mode 100644 regression/README.md create mode 100755 regression/SimpleLinearRegression.py create mode 100755 regression/abalone.py create mode 100644 regression/abalone.txt create mode 100644 regression/ex0.txt create mode 100755 regression/lego.py create mode 100644 regression/lego/lego10030.html create mode 100644 regression/lego/lego10179.html create mode 100644 regression/lego/lego10181.html create mode 100644 regression/lego/lego10189.html create mode 100644 regression/lego/lego10196.html create mode 100644 regression/lego/lego8288.html create mode 100755 regression/log_regres.py create mode 100644 regression/multiple.csv create mode 100644 regression/multipleDummy.csv create mode 100755 regression/regression.py create mode 100755 regression/regression_old.py create mode 100644 regression/testSet.txt create mode 100644 regression/线性模型.md create mode 100644 rl/README.md create mode 100755 sitmap-generator.py create mode 100644 svm/README.md create mode 100755 svm/svm-digits.py create mode 100755 svm/svm-simple.py create mode 100755 svm/svm-smo.py create mode 100755 svm/svm-svc.py create mode 100755 svm/svmMLiA.py create mode 100644 svm/testSet.txt create mode 100644 svm/testSetRBF.txt create mode 100644 svm/testSetRBF2.txt create mode 100644 targetDetection/README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..11e27ef --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +_book +node_modules +.idea +.ropeproject +__pycache__ +env diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..472ac23 --- /dev/null +++ b/LICENSE @@ -0,0 +1,8 @@ +MIT License +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..00eb88c --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +## 机器学习 + +主要用来记录机器学习中遇到的问题及其解决方案 + +### 环境搭建 +执行下面命令 +```sh +pip install numpy scipy statsmodels matplotlib +pip install -U scikit-learn nltk +apt install python-pandas # pythons使用的是python3-pandas +apt install python-matplotlib +pip install nltk tornado +``` +docker tensorflow环境搭建 +```sh +docker pull dash00/tensorflow-python3-jupyter +# 限制使用内存的大小,防止影响到本机 +docker run -d --name "tensorflow" -m 4000M --cpus=2 -p 8888:8888 dash00/tensorflow-python3-jupyter +``` + +docker资源清理 +```sh +docker container prune # 删除所有退出状态的容器 +docker volume prune # 删除未被使用的数据卷 +docker image prune # 删除 dangling 或所有未被使用的镜像 +``` + +virtualenv使用 +```sh +sudo apt install virtualenv +virtualenv env +source ./env/bin/activate +``` + +### 监督学习 +#### 分类 +- 决策树 +- 临近取样 +- 支持向量机 +- 神经网络算法 +#### 回归 + +### 非监督学习 + + diff --git a/SUMMARY.md b/SUMMARY.md new file mode 100644 index 0000000..049edea --- /dev/null +++ b/SUMMARY.md @@ -0,0 +1,32 @@ +# 目录 + +* [简介](README.md) +* [基础知识](basic/README.md) + * [模型评估](basic/evaluation.md) + * [深度学习基础](basic/deep_basic.md) + * [深度学习简述](basic/deep_learn.md) + * [数学基础](basic/math_basis.md) + * [图像相关](basic/pic/README.md) + +* [决策树](decisionTree/README.md) + +* [回归问题](regression/README.md) + * [线性模型](regression/线性模型.md) + +* [k-近邻算法](knn/README.md) + +* [支持向量机](svm/README.md) + +* [贝叶斯分类器](bayes/README.md) + +* [神经网络](nn/README.md) + * [RNN详解](nn/rnn.md) + * [CNN详解](nn/cnn.md) + * [多任务学习](nn/multi_task.md) + * [ResNet详解](nn/ResNet.md) + +* [目标检测](targetDetection/README.md) + +* [自然语言理解与交互](nlp/README.md) + +* [强化学习](rl/README.md) diff --git a/basic/README.md b/basic/README.md new file mode 100644 index 0000000..9fef1a0 --- /dev/null +++ b/basic/README.md @@ -0,0 +1,13 @@ +# 基础知识详解 + +## 机器学习数学基础相关的好文章合集 +1. [机器学习500问之数学基础](https://github.com/deel-learn/DeepLearning-500-questions/blob/master/ch1_%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80/%E7%AC%AC%E4%B8%80%E7%AB%A0_%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80.md) +2. [深度学习基础](https://github.com/deel-learn/DeepLearning-500-questions/blob/master/ch3_%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9F%BA%E7%A1%80/%E7%AC%AC%E4%B8%89%E7%AB%A0_%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9F%BA%E7%A1%80.pdf) + + +## 常见概念理解 + +1. [目标函数和损失函数的差别](https://blog.csdn.net/u011500062/article/details/55522609) +2. [目标函数、损失函数、代价函数](https://www.davex.pw/2017/12/16/understand-loss-and-object-function/) + + diff --git a/basic/deep_basic.md b/basic/deep_basic.md new file mode 100644 index 0000000..a2f6c4b --- /dev/null +++ b/basic/deep_basic.md @@ -0,0 +1,34 @@ +# 深度学习基础 + +## 激活函数 + +### 常见的激活函数 + +#### 1. sigmoid函数 +函数的定义$$ f(x) = \frac{1}{1 + e^{-x}} $$,其值域为 $$ (0,1) $$。 函数图像 + +![图像](https://raw.githubusercontent.com/deel-learn/DeepLearning-500-questions/master/ch3_%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9F%BA%E7%A1%80/img/ch3/3-26.png) + +#### 2. tanh激活函数 +函数的定义为:$$ f(x) = tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} $$,值域为 $$ (-1,1) $$。函数图像 + +![pic](https://raw.githubusercontent.com/deel-learn/DeepLearning-500-questions/master/ch3_%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9F%BA%E7%A1%80/img/ch3/3-27.png) + +#### 3. Relu激活函数 +函数的定义为:$$ f(x) = max(0, x) $$ ,值域为 $$ [0,+∞) $$;函数图像 + +![pic](https://raw.githubusercontent.com/deel-learn/DeepLearning-500-questions/master/ch3_%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9F%BA%E7%A1%80/img/ch3/3-28.png) + +#### 4. Leak Relu激活函数 +函数定义为: $$ f(x) = \left{ \begin{aligned} ax, \quad x<0 \ x, \quad x>0 \end{aligned} \right. $$,值域为 $$ (-∞,+∞) $$。图像如下($$ a = 0.5 $$): + +![pic](https://raw.githubusercontent.com/deel-learn/DeepLearning-500-questions/master/ch3_%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9F%BA%E7%A1%80/img/ch3/3-29.png) + +#### 5. SolftPlus 激活函数 +函数的定义为:$$ f(x) = ln( 1 + e^x) $$,值域为 $$ (0,+∞) $$。图像如下 + +![pic](https://raw.githubusercontent.com/deel-learn/DeepLearning-500-questions/master/ch3_%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9F%BA%E7%A1%80/img/ch3/3-30.png) + +#### 6. softmax激活函数 +函数定义为: $$ \sigma(z)j = \frac{e^{z_j}}{\sum{k=1}^K e^{z_k}} $$。 +Softmax 多用于多分类神经网络输出。 diff --git a/basic/deep_learn.md b/basic/deep_learn.md new file mode 100644 index 0000000..b9ef949 --- /dev/null +++ b/basic/deep_learn.md @@ -0,0 +1,45 @@ +## 深度模型的局限性 +随着深度学习的不断进步以及数据处理能力的不断提升,各大研究机构及科技巨头相继对深度学习领域投入了大量的资金和精力,并取得 +了惊人的成就。然而,我们不能忽略的一个重要问题是,深度学习实际上仍然存在着局限性: + +### 深度学习需要大量的训练数据 +度学习的性能,能否提升取决于数据集的大小,因此深度学习通常需要大量的数据作为支撑,如果不能进行大量有效的训练,往往会导致 +过拟合(过拟合是指深度学习时选择的模型所包含的参数过多,以至于出现这一模型对已知数据预测得很好,但对未知数据预测得很差的 +现象)现象的产生。 + + +### 缺乏推理能力 +深度学习能够发现事件之间的关联性,建立事件之间的映射关系,但是深度学习不能解释因果关系。简单来说,深度学习学到的是输入与 +输出特征间的复杂关系,而非因果性的表征。深度学习可以把人类当作整体,并学习到身高与词汇量的相关性,但并不能了解到长大与发 +展间的关系。也就是说,孩子随着长大会学到更多单词,但这并不代表学习更多单词会让孩子长大。 + +### 深度网络对图像的改变过于敏感 + +在人类看来,对图片进行局部调整可能并会不影响对图的判断。然而,深度网络不仅对标准对抗攻击敏感,而且对环境的变化也会敏感。 +下图显示了在一张丛林猴子的照片中PS上一把吉他的效果。这导致深度网络将猴子误认为人类,同时将吉他误认为鸟,大概是因为它认为 +人类比猴子更可能携带吉他,而鸟类比吉他更可能出现在附近的丛林中。 +![pic](http://dynamic-image.yesky.com/1200x-/uploadImages/2019/051/59/GVLL362E78A2.png) + +图:添加遮蔽体会导致深度网络失效。左:用摩托车进行遮挡后,猴子被识别为人类。中:用自行车进行遮挡后,猴子被识别为人类,同 +时丛林背景导致自行车把手被误认为是鸟。右:用吉他进行遮挡后,猴子被识别为人类,而丛林把吉他变成了鸟. + +类似地,通过梯度上升,可以稍微修改图像,以便最大化给定类的类预测。通过拍摄一只熊猫,并添加一个“长臂猿”梯度,我们可以得到 +一个神经网络将这只熊猫分类为长臂猿。这证明了这些模型的脆弱性,以及它们运行的输入到输出映射与我们自己的人类感知之间的深刻 +差异。 + +![pic](https://www.mayi888.com/wp-content/uploads/2017/10/p20170722094310570.wm.png) + + +### 无法判断数据的正确性 + +深度学习可以在不理解数据的情况下模仿数据中的内容,它不会否定任何数据,不会发现数据中隐藏的偏见,这就可能会造成最终生成 +结果的不客观。 + +人工智能目前具有的一个非常真实的风险——人们误解了深度学习模型,并高估了它们的能力。人类思想的一个根本特征是我们的“思想理 +论”,我们倾向于对我们周围的事物设计意向、信仰和知识。在岩石上画一个笑脸,突然让我们“开心”。应用于深度学习,这意味着,例 +如,当我们能够成功地训练一个模型以生成描述图片的说明时,我们误认为该模型“理解”了图片的内容以及图片所生成的内容。但是,当 +训练数据中的图像存在轻微的偏离,使得模型开始生成完全荒谬的说明时,我们又非常惊讶。 + +![pic](https://www.mayi888.com/wp-content/uploads/2017/10/p20170722094255127.wm.png) + +案例:这个“男孩”正拿着一个“棒球棒”(正确说明应该是“这个女孩正拿着牙刷”) diff --git a/basic/evaluation.md b/basic/evaluation.md new file mode 100644 index 0000000..d354979 --- /dev/null +++ b/basic/evaluation.md @@ -0,0 +1,90 @@ +# 评估方法 +## 留出法 +留出法(hold-out)直接将数据集D划分为两个互斥的集合,其中一个集合作为训练集S,另一个作为测试集T,即有$$D=S∪T,S∩T=∅ $$ +建议:
+训练集/测试集:2/3~4/5 + +## 交叉验证法 +交叉验证法(cross validation)先将数据集D划分为k个大小相似的互斥子集。即有:$$D=D1∪D2∪...∪Dk,Di∩Dj=∅$$ +每个子集Di都尽可能保持数据分布的一致性,即从D中通过分层采样得到。然后,每次用k-1个子集的并集作为训练集,余下的那个子集 +作为测试集,这样就可以获得k组训练/测试集。从而可以进行k次训练与测试,最终返回的是这k个测试结果的均值。
+![交叉验证法](http://index.zeekling.cn/gogsPics/ml/basic/20161109110731469.png)
+缺陷:数据集较大时,计算开销。同时留一法的估计结果也未必比其他评估方法准确。 + +## 自助法 +简单的说,它从数据集D中每次随机取出一个样本,将其拷贝一份放入新的采样数据集D′,样本放回原数据集中,重复这个过程m次,就得 +到了同样包含m个样本的数据集D′,显然D中会有一部分数据会在D′中重复出现。样本在m次采样中始终不被采样到的概率是 +![概率](http://index.zeekling.cn/gogsPics/ml/basic/2018-12-08_23-13.png),取极限得到:
+![自助法](http://index.zeekling.cn/gogsPics/ml/basic/2018-12-08_23-02.png)
+即通过自助法,初始数据集中约有36.8%样本未出现在采样数据集D′中。可将D′作为训练集,D\D′作为测试集,(\表示集合的减法)。保 +证了实际评估的模型与期望评估的模型都是用m个训练样本,而有数据总量约1/3的、没在训练集中出过的样本用于测试,这样的测试结 +果,也叫做”包外估计”(out-of-bagestimate). + +### 适用场景 +自助法在数据集较小、难以有效划分训练/测试集很有用;此外自助法可以从初始数据集中产生多个不同的训练集,这对集成学习等方法 +有很大好处。 + +### 缺点 +自助法产生的数据集改变了初始数据集的分布,引入估计偏差。故在数据量足够时,留出法与交叉验证更为常用。 + +# 性能度量 +在预测任务中,给定样本集 +![样本集](http://index.zeekling.cn/gogsPics/ml/basic/v2-ec2cf40da68b421eaa9fd3161c3c6aae_hd.jpg) +其中,yi是示例xi的真实标记。回归任务中最常用的性能度量是均方误差(mean squeared error),f(x)是机器学习预测结果
+![均方误差](http://index.zeekling.cn/gogsPics/ml/basic/20170728160012970.png)
+更一般的形式(数据分布D,概率密度函数p(x))
+![均方误差](http://index.zeekling.cn/gogsPics/ml/basic/20170728160030374.png) + +## 错误率和精度 +错误率的定义:
+![错误率](http://index.zeekling.cn/gogsPics/ml/basic/20170728160111980.png)
+更一般的定义:
+![错误率](http://index.zeekling.cn/gogsPics/ml/basic/20170728160154325.png)
+精度的定义:
+![精度](http://index.zeekling.cn/gogsPics/ml/basic/20170728160235638.png)
+更一般的定义:
+![精度](http://index.zeekling.cn/gogsPics/ml/basic/20170728160341707.png) + +## 查准率、查全率与F1 +下表是二分类结果混淆矩阵,将判断结果分为四个类别,真正例(TP)、假正例(FP)、假反例(FN)、真反例(TN)。
+![二分类问题](http://index.zeekling.cn/gogsPics/ml/basic/v2-d86bd2ab359674615166d641c0a290b3_hd.jpg)
+查准率:【真正例样本数】与【预测结果是正例的样本数】的比值。
+查全率:【真正例样本数】与【真实情况是正例的样本数】的比值。
+![P-R曲线](http://index.zeekling.cn/gogsPics/ml/basic/v2-c2eb73c67a9c3ced1cb0167363ab8971_hd.png)
+- 当曲线没有交叉的时候:外侧曲线的学习器性能优于内侧; +- 当曲线有交叉的时候: + - 第一种方法是比较曲线下面积,但值不太容易估算; + - 第二种方法是比较两条曲线的平衡点,平衡点是“查准率=查全率”时的取值,在图中表示为曲线和对角线的交点。平衡点在外侧的 + 曲线的学习器性能优于内侧。 + - 第三种方法是F1度量和Fβ度量。F1是基于查准率与查全率的调和平均定义的,Fβ则是加权调和平均。
+ ![F1](http://index.zeekling.cn/gogsPics/ml/basic/v2-8767d0e40027a80c9dfbb4e67c415562_hd.png)
+ ![Fb](http://index.zeekling.cn/gogsPics/ml/basic/v2-b1957f27cd827f658c44e09f25950676_hd.png)
+ + +## ROC与AUC +ROC曲线便是从这个角度出发来研究学习器泛化性能的有力工具。
+与P-R曲线使用查准率、查全率为横纵轴不同,ROC的纵轴是”真正样例(True Positive Rate,简称TPR)”,横轴是“假正例率(False +Positive Rate,简称FPR),两者分别定义为
+![ROC](http://index.zeekling.cn/gogsPics/ml/basic/v2-4c7d54020323bbf3b04e57be62bb29dc_hd.jpg)
+显示ROC的曲线图称为“ROC图”
+![pic](http://index.zeekling.cn/gogsPics/ml/basic/v2-688e036b40e5fae2ffa0fa54b77cb5a4_hd.jpg)
+进行学习器比较时,与P-R如相似,若一个学习器的ROC曲线被另一个学习器的曲线“包住”,则可断言后者的性能优于前者;若两个学习 +器的ROC曲线发生交叉,则难以一般性的断言两者孰优孰劣。此时如果一定要进行比较,则较为合理的判断是比较ROC曲线下的面积, +即AUC(Area Under ROC Curve)。 + +注意:AUC计算公式没看懂 + +## 代价敏感错误率与代价曲线 +在现实任务中会遇到这样的情况:不同类型错误所造成的后果不同。以二分类任务为例,我们可根据任务领域知识设定一个“代价矩阵”, +如下图所示,
+![代价矩阵](http://index.zeekling.cn/gogsPics/ml/basic/v2-85d636c2cc2078f7a38134f4dceb2019_hd.jpg)
+在非均等代价下,ROC曲线不能直接反映出学习器的期望总体代价,而“代价曲线(cost curve)”则可达到目的。代价曲线图的横轴是取 +值为[0,1]的正例概率代价,
+![正概率代价](http://index.zeekling.cn/gogsPics/ml/basic/v2-33493342b0a90d67276250573aea107e_hd.jpg)
+纵轴是取值为[0,1]的归一化代价
+![归一化代价](http://index.zeekling.cn/gogsPics/ml/basic/v2-e02dbd62fa02979d958291d56fbaae0b_hd.jpg)
+画图表示如下图所示
+![图](http://index.zeekling.cn/gogsPics/ml/basic/v2-3d72a25b2a326afa1ccebed64f41f2ce_hd.jpg)
+ +# 比较检验 + diff --git a/basic/math_basis.md b/basic/math_basis.md new file mode 100644 index 0000000..1303b66 --- /dev/null +++ b/basic/math_basis.md @@ -0,0 +1,43 @@ +# 数学基础 + +## 标量、向量、矩阵、张量之间的联系 +### 标量(scalar) +一个标量表示一个单独的数,它不同于线性代数中研究的其他大部分对象(通常是多个数的数组)。我们用斜体表示标量。标量通常被 +赋予小写的变量名称。 +### 向量(vector) +一个向量表示组有序排列的数。通过次序中的索引,我们可以确定每个单独的数。通常我们赋予向量粗体的小写变量名称,比如xx。向量 +中的元素可以通过带脚标的斜体表示。向量x的第一个元素是x1,第二个元素是x2,以此类推。我们也会注明存储在向量中的元素的类型 +(实数、虚数等)。 +### 矩阵(matrix) +矩阵是具有相同特征和纬度的对象的集合,表现为一张二维数据表。其意义是一个对象表示为矩阵中的一行,一个特征表示为矩阵中的一 +列,每个特征都有数值型的取值。通常会赋予矩阵粗体的大写变量名称,比如A。 +### 张量(tensor) +在某些情况下,我们会讨论坐标超过两维的数组。一般地,一个数组中的元素分布在若干维坐标的规则网格中,我们将其称之为张量。 + +### 奇异值分解 +[https://zhuanlan.zhihu.com/p/26306568 ](https://zhuanlan.zhihu.com/p/26306568) + +## 常见概率分布 +![常见概率分布](http://index.zeekling.cn/gogsPics/ml/basic/20170728160341708.png) +![常见概率分布](http://index.zeekling.cn/gogsPics/ml/basic/20170728160341709.png) +![常见概率分布](http://index.zeekling.cn/gogsPics/ml/basic/20170728160341710.png) +![常见概率分布](http://index.zeekling.cn/gogsPics/ml/basic/20170728160341711.png) +![常见概率分布](http://index.zeekling.cn/gogsPics/ml/basic/20170728160341712.png) +![常见概率分布](http://index.zeekling.cn/gogsPics/ml/basic/20170728160341713.png) +![常见概率分布](http://index.zeekling.cn/gogsPics/ml/basic/20170728160341714.png) + +## 数值计算 + +[Jacobian矩阵和Hessian矩阵](https://www.cnblogs.com/wangyarui/p/6407604.html) + +## 估计、偏差、方差 +[偏差和方差](http://liuchengxu.org/blog-cn/posts/bias-variance/) + +## 极大似然估计 +[相对熵(KL散度)](https://blog.csdn.net/ACdreamers/article/details/44657745) + +极大似然相关理解 +1. [https://www.jiqizhixin.com/articles/2018-01-09-6 ](https://www.jiqizhixin.com/articles/2018-01-09-6) + + + diff --git a/basic/pic/README.md b/basic/pic/README.md new file mode 100644 index 0000000..e0975d5 --- /dev/null +++ b/basic/pic/README.md @@ -0,0 +1,12 @@ +# 图片相关基础知识 + +## 上采样和下采样 + +### 上采样 + + + +### 下采样 + + + diff --git a/bayes/README.md b/bayes/README.md new file mode 100644 index 0000000..effa14a --- /dev/null +++ b/bayes/README.md @@ -0,0 +1,81 @@ +# 朴素贝叶斯 + +叶斯分类器是一种概率框架下的统计学习分类器,对分类任务而言,假设在相关概率都已知的情况下,贝叶斯分类器考虑如何基于这些概 +率为样本判定最优的类标。在开始介绍贝叶斯决策论之前,我们首先来回顾下概率论委员会常委--贝叶斯公式。 + +![条件概率](http://index.zeekling.cn/data/Pictures/gogs/ml/bayes/1.png)
+ +### 条件概率 +朴素贝叶斯最核心的部分是贝叶斯法则,而贝叶斯法则的基石是条件概率。贝叶斯法则如下: + +![条件概率](http://index.zeekling.cn/data/Pictures/gogs/ml/bayes/0.png)
+ +对于给定的样本x,P(x)与类标无关,P(c)称为类先验概率,p(x | c )称为类条件概率。这时估计后验概率P(c | x)就变成为 +估计类先验概率和类条件概率的问题。对于先验概率和后验概率,在看这章之前也是模糊了我好久,这里普及一下它们的基本概念。 + +> 先验概率: 根据以往经验和分析得到的概率。
+> 后验概率:后验概率是基于新的信息,修正原来的先验概率后所获得的更接近实际情况的概率估计。 + +实际上先验概率就是在没有任何结果出来的情况下估计的概率,而后验概率则是在有一定依据后的重新估计,直观意义上后验概率就是条 +件概率。 + +![pic](http://index.zeekling.cn/data/Pictures/gogs/ml/bayes/2.png)
+ +回归正题,对于类先验概率P(c),p(c)就是样本空间中各类样本所占的比例,根据大数定理(当样本足够多时,频率趋于稳定等于其 +概率),这样当训练样本充足时,p(c)可以使用各类出现的频率来代替。因此只剩下类条件概率p(x | c ),它表达的意思是在类别c中 +出现x的概率,它涉及到属性的联合概率问题,若只有一个离散属性还好,当属性多时采用频率估计起来就十分困难,因此这里一般采用 +极大似然法进行估计。 + +### 极大似然法 +极大似然估计(Maximum Likelihood Estimation,简称MLE),是一种根据数据采样来估计概率分布的经典方法。常用的策略是先假定总 +体具有某种确定的概率分布,再基于训练样本对概率分布的参数进行估计。运用到类条件概率p(x | c )中,假设p(x | c )服从一个 +参数为θ的分布,问题就变为根据已知的训练样本来估计θ。极大似然法的核心思想就是:估计出的参数使得已知样本出现的概率最大,即 +使得训练数据的似然最大。 + +![pic](http://index.zeekling.cn/data/Pictures/gogs/ml/bayes/3.png)
+ +所以,贝叶斯分类器的训练过程就是参数估计。总结最大似然法估计参数的过程,一般分为以下四个步骤: + +> 1. 写出似然函数;
+> 2. 对似然函数取对数,并整理;
+> 3. 求导数,令偏导数为0,得到似然方程组;
+> 4. 解似然方程组,得到所有参数即为所求。 + +例如:假设样本属性都是连续值,p(x | c )服从一个多维高斯分布,则通过MLE计算出的参数刚好分别为: + +![pic](http://index.zeekling.cn/data/Pictures/gogs/ml/bayes/4.png)
+ +上述结果看起来十分合乎实际,但是采用最大似然法估计参数的效果很大程度上依赖于作出的假设是否合理,是否符合潜在的真实数据分 +布。这就需要大量的经验知识,搞统计越来越值钱也是这个道理,大牛们掐指一算比我们搬砖几天更有效果。 + +### 朴素贝叶斯分类器 +不难看出:原始的贝叶斯分类器最大的问题在于联合概率密度函数的估计,首先需要根据经验来假设联合概率分布,其次当属性很多时, +训练样本往往覆盖不够,参数的估计会出现很大的偏差。为了避免这个问题,朴素贝叶斯分类器(naive Bayes classifier)采用了“属 +性条件独立性假设”,即样本数据的所有属性之间相互独立。这样类条件概率p(x | c )可以改写为: + +![pic](http://index.zeekling.cn/data/Pictures/gogs/ml/bayes/5.png)
+ +这样,为每个样本估计类条件概率变成为每个样本的每个属性估计类条件概率。 + +![pic](http://index.zeekling.cn/data/Pictures/gogs/ml/bayes/6.png)
+ +相比原始贝叶斯分类器,朴素贝叶斯分类器基于单个的属性计算类条件概率更加容易操作,需要注意的是:若某个属性值在训练集中和某 +个类别没有一起出现过,这样会抹掉其它的属性信息,因为该样本的类条件概率被计算为0。因此在估计概率值时,常常用进行平滑( +smoothing)处理,拉普拉斯修正(Laplacian correction)就是其中的一种经典方法,具体计算方法如下: + +![pic](http://index.zeekling.cn/data/Pictures/gogs/ml/bayes/7.png)
+ +当训练集越大时,拉普拉斯修正引入的影响越来越小。对于贝叶斯分类器,模型的训练就是参数估计,因此可以事先将所有的概率储存好 +,当有新样本需要判定时,直接查表计算即可。 + +### 词集模型 +对于给定文档,只统计某个侮辱性词汇(准确说是词条)是否在本文档出现 + +### 词袋模型 +对于给定文档,统计某个侮辱性词汇在本文当中出现的频率,除此之外,往往还需要剔除重要性极低的高频词和停用词。因此, +词袋模型更精炼,也更有效。 + +## 数据预处理 + +### 向量化 +向量化、矩阵化操作是机器学习的追求。从数学表达式上看,向量化、矩阵化表示更加简洁;在实际操作中,矩阵化(向量是特殊的矩阵)更高效。 diff --git a/bayes/bayes.py b/bayes/bayes.py new file mode 100755 index 0000000..9150500 --- /dev/null +++ b/bayes/bayes.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +# coding:utf-8 +import numpy as np + + +def load_data_set(): + posting_list = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'], + ['maybe', 'not', 'take', 'him', 'dog', 'park', 'stupid'], + ['my', 'dalmation', 'is', 'so', 'cute', '_i', 'love', 'him'], + ['stop', 'posting', 'stupid', 'worthless', 'garbage'], + ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'], + ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']] + + class_vec = [0, 1, 0, 1, 0, 1] + return posting_list, class_vec + + +def create_vocab_list(data_set): + vocab_set = set([]) + for document in data_set: + vocab_set = vocab_set | set(document) + + return list(vocab_set) + + +def set_of_words2_vec(vocab_list, input_set): + return_vec = [0] * len(vocab_list) + for word in input_set: + if word in vocab_list: + return_vec[vocab_list.index(word)] = 1 + else: + print("the word:%s is not in my vocabulary!", word) + + return return_vec + + +# 贝叶斯分类器训练函数 +def train_nb0(train_matrix, train_category): + num_train_docs = len(train_matrix) + num_words = len(train_matrix[0]) + p_abusive = sum(train_category)/float(num_train_docs) + p0_num = np.zeros(num_words) + p1_num = np.zeros(num_words) + p0_denom = 0.0 + p1_denom = 0.0 + for i in range(num_train_docs): + if train_category[i] == 1: + p1_num += train_matrix[i] + p1_denom += sum(train_matrix[i]) + else: + p0_num += train_matrix[i] + p0_denom += sum(train_matrix[i]) + + p1_vect = p1_num/p1_denom + p0_vect = p0_num/p0_denom + return p0_vect, p1_vect, p_abusive + + +def classify_nb(vec2_classify, p0_vec, p1_vec, p_class1): + p1 = sum(vec2_classify * p1_vec) + np.log(p_class1) + p0 = sum(vec2_classify * p0_vec) + np.log(1.0 - p_class1) + if p1 > p0: + return 1 + else: + return 0 + + +def testing_nb(): + list0_posts, list_classes = load_data_set() + my_vocab_list = create_vocab_list(list0_posts) + train_mat = [] + for postin_doc in list0_posts: + train_mat.append(set_of_words2_vec(my_vocab_list, postin_doc)) + p0_v, p1_v, p_ab = train_nb0(np.array(train_mat), np.array(list_classes)) + test_entry = ['love', 'my', 'dalmation'] + this_doc = np.array(set_of_words2_vec(my_vocab_list, test_entry)) + print(test_entry, 'classsified as:', classify_nb(this_doc, p0_v, p1_v, p_ab)) + test_entry = ['stupid', 'garbage'] + this_doc = np.array(set_of_words2_vec(my_vocab_list, test_entry)) + print(test_entry, 'classsified as:', classify_nb(this_doc, p0_v, p1_v, p_ab)) + + +testing_nb() diff --git a/book.json b/book.json new file mode 100644 index 0000000..332cda5 --- /dev/null +++ b/book.json @@ -0,0 +1,75 @@ +{ + "root":"./", + "author":"小令童鞋", + "description":"没有到不了的明天,只有回不了的昨天", + "plugins":["github", + "-sharing", + "-search", + "sharing-plus", + "-highlight", + "expandable-chapters-small", + "mathjax", + "splitter", + "disqus", + "3-ba", + "theme-comscore", + "search-plus", + "prism", + "prism-themes", + "github-buttons", + "ad", + "tbfed-pagefooter", + "ga", + "alerts", + "anchors", + "include-codeblock", + "ace" + ], + "links":{ + "sidebar":{ + "主页":"http://www.zeekling.cn" + } + }, + "pluginsConfig":{ + "sharing":{ + "douban":false, + "facebook":false, + "qq":false, + "qzone":false, + "google":false, + "all": [ + "weibo","qq","qzone","google","douban" + ] + }, + "disqus":{ + "shortName":"zeekling" + }, + "ad":{ + + }, + "include-codeblock":{ + "template":"ace", + "unindent":true, + "theme":"monokai" + }, + "tbfed-pagefooter":{ + "Copyright":"© zeekling.cn", + "modify_label":"文件修改时间", + "modify_format":"YYYY-MM-DD HH:mm:ss" + }, + "3-ba":{ + "token":"zeekling" + }, + "ga":{ + "token":"zeekling", + "configuration":{ + "cookieName":"zeekling", + "cookieDomain":"book.zeekling.cn" + } + }, + "github":{"url":"http://www.zeekling.cn/gogs/zeek"}, + "theme-default": { + "showLevel": true + } + } +} diff --git a/decisionTree/AllElectronics.py b/decisionTree/AllElectronics.py new file mode 100755 index 0000000..378661d --- /dev/null +++ b/decisionTree/AllElectronics.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + diff --git a/decisionTree/README.md b/decisionTree/README.md new file mode 100644 index 0000000..0de373b --- /dev/null +++ b/decisionTree/README.md @@ -0,0 +1,97 @@ +# 决策树 + + +# 决策树的构造 +决策树的构造是一个递归的过程,有三种情形会导致递归返回:(1) 当前结点包含的样本全属于同一类别,这时直接将该节点标记为叶节 +点,并设为相应的类别;(2) 当前属性集为空,或是所有样本在所有属性上取值相同,无法划分,这时将该节点标记为叶节点,并将其类 +别设为该节点所含样本最多的类别;(3) 当前结点包含的样本集合为空,不能划分,这时也将该节点标记为叶节点,并将其类别设为父节 +点中所含样本最多的类别。算法的基本流程如下图所示: + +![pic](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335075.png)
+ +可以看出:决策树学习的关键在于如何选择划分属性,不同的划分属性得出不同的分支结构,从而影响整颗决策树的性能。属性划分的目 +标是让各个划分出来的子节点尽可能地“纯”,即属于同一类别。 + +## 数学归纳算法(ID3) +### 信息增益 + +相关概念 +1. 熵:表示随机变量的不确定性。 +2. 条件熵:在一个条件下,随机变量的不确定性。 +3. 信息增益:熵 - 条件熵,在一个条件下,信息不确定性减少的程度! + +### 信息熵 +ID3算法使用信息增益为准则来选择划分属性,“信息熵”(information entropy)是度量样本结合纯度的常用指标,假定当前样本集合D中 +第k类样本所占比例为pk,则样本集合D的信息熵定义为: +![信息熵](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335076.png) + +信息熵特点 +> 1. 不同类别的概率分布越均匀,信息熵越大; +> 2. 类别个数越多,信息熵越大; +> 3. 信息熵越大,越不容易被预测;(变化个数多,变化之间区分小,则越不容易被预测)(对于确定性问题,信息熵为0;p=1; E=p*logp=0)
+> 相关理解:[通俗理解信息熵](https://zhuanlan.zhihu.com/p/26486223)、[条件熵](https://zhuanlan.zhihu.com/p/26551798) + +假定通过属性划分样本集D,产生了V个分支节点,v表示其中第v个分支节点,易知:分支节点包含的样本数越多,表示该分支节点的影响 +力越大。故可以计算出划分后相比原始数据集D获得的“信息增益”(information gain)。 + +![信息增益](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335077.png)
+信息增益越大,表示使用该属性划分样本集D的效果越好,因此ID3算法在递归过程中,每次选择最大信息增益的属性作为当前的划分属性。 + +### C4.5算法 +ID3算法存在一个问题,就是偏向于取值数目较多的属性,例如:如果存在一个唯一标识,这样样本集D将会被划分为|D|个分支,每个分 +支只有一个样本,这样划分后的信息熵为零,十分纯净,但是对分类毫无用处。因此C4.5算法使用了“增益率”(gain ratio)来选择划分 +属性,来避免这个问题带来的困扰。首先使用ID3算法计算出信息增益高于平均水平的候选属性,接着C4.5计算这些候选属性的增益率, +增益率定义为: +
![pic](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335078.png)
+ +### cart算法 +CART决策树使用“基尼指数”(Gini index)来选择划分属性,基尼指数反映的是从样本集D中随机抽取两个样本,其类别标记不一致的概 +率,因此Gini(D)越小越好,基尼指数定义如下: +
![pic](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335079.png)
+进而,使用属性α划分后的基尼指数为: +
![pic](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335080.png)
+ +## 剪枝处理 +从决策树的构造流程中我们可以直观地看出:不管怎么样的训练集,决策树总是能很好地将各个类别分离开来,这时就会遇到之前提到过 +的问题:过拟合(overfitting),即太依赖于训练样本。剪枝(pruning)则是决策树算法对付过拟合的主要手段,剪枝的策略有两种如 +下: +> * 预剪枝(prepruning):在构造的过程中先评估,再考虑是否分支。 +> * 后剪枝(post-pruning):在构造好一颗完整的决策树后,自底向上,评估分支的必要性。 + +评估指的是性能度量,即决策树的泛化性能。之前提到:可以使用测试集作为学习器泛化性能的近似,因此可以将数据集划分为训练集和 +测试集。预剪枝表示在构造数的过程中,对一个节点考虑是否分支时,首先计算决策树不分支时在测试集上的性能,再计算分支之后的性 +能,若分支对性能没有提升,则选择不分支(即剪枝)。后剪枝则表示在构造好一颗完整的决策树后,从最下面的节点开始,考虑该节点 +分支对模型的性能是否有提升,若无则剪枝,即将该节点标记为叶子节点,类别标记为其包含样本最多的类别。 +
![pic](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335081.png)
+
![pic](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335082.png)
+
![pic](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335083.png)
+上图分别表示不剪枝处理的决策树、预剪枝决策树和后剪枝决策树。预剪枝处理使得决策树的很多分支被剪掉,因此大大降低了训练时间 +开销,同时降低了过拟合的风险,但另一方面由于剪枝同时剪掉了当前节点后续子节点的分支,因此预剪枝“贪心”的本质阻止了分支的展 +开,在一定程度上带来了欠拟合的风险。而后剪枝则通常保留了更多的分支,因此采用后剪枝策略的决策树性能往往优于预剪枝,但其自 +底向上遍历了所有节点,并计算性能,训练时间开销相比预剪枝大大提升。 + + +## 连续值与缺失值处理 +对于连续值的属性,若每个取值作为一个分支则显得不可行,因此需要进行离散化处理,常用的方法为二分法,基本思想为:给定样本集 +D与连续属性α,二分法试图找到一个划分点t将样本集D在属性α上分为≤t与>t。 +> * 首先将α的所有取值按升序排列,所有相邻属性的均值作为候选划分点(n-1个,n为α所有的取值数目)。 +> * 计算每一个划分点划分集合D(即划分为两个分支)后的信息增益。 +> * 选择最大信息增益的划分点作为最优划分点。 + +
![pic](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335084.png)
+现实中常会遇到不完整的样本,即某些属性值缺失。有时若简单采取剔除,则会造成大量的信息浪费,因此在属性值缺失的情况下需要解 +决两个问题:(1)如何选择划分属性。(2)给定划分属性,若某样本在该属性上缺失值,如何划分到具体的分支上。假定为样本集中的 +每一个样本都赋予一个权重,根节点中的权重初始化为1,则定义: +
![pic](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335085.png)
+对于(1):通过在样本集D中选取在属性α上没有缺失值的样本子集,计算在该样本子集上的信息增益,最终的信息增益等于该样本子集 +划分后信息增益乘以样本子集占样本集的比重。即: +
![pic](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335086.png)
+对于(2):若该样本子集在属性α上的值缺失,则将该样本以不同的权重(即每个分支所含样本比例)划入到所有分支节点中。该样本在 +分支节点中的权重变为: +
![pic](http://index.zeekling.cn/gogsPics/ml/decisionTree/20170121190335087.png)
+ + +## 优缺点 +- 处理连续变量不好 +- 类型比较多的时候错误增加的比较快 +- 可规模性一般 diff --git a/decisionTree/pics/20170121190335074.png b/decisionTree/pics/20170121190335074.png new file mode 100644 index 0000000000000000000000000000000000000000..965727335aae8792b12589123caf5b289e854b0c GIT binary patch literal 5851 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 SOU5!(0MJy^Q>|6DkNqz=P4!^_ literal 0 HcmV?d00001 diff --git a/decisionTree/pics/812093045.png b/decisionTree/pics/812093045.png new file mode 100644 index 0000000000000000000000000000000000000000..cfaa451fd52c968b2ce6b8d0278344bb133cbf5e GIT binary patch literal 1934 zcmV;92XXj`P)69{VrV9`RNS8(~qb|iXuF}L_!Dt0Rib#9m13!`} zij-uD(!kF*fDwu!FL@5{x%`L$V~m0Rhyh|?6bAko#VQ#k28aQ{011p7ffyK(0TS4V z+C?KmsElAO=QcfCM%oxn!CcAc2t&5CbDJKmr?)Try1z zkif_Xh=CCq7)4GF*aD&Q%e_L3mE5 za&@RA-r-!TUKWQ8l{Q@l{pO2yVHqejfL14Hn7azB z=%>{;JO?IE0#gI+l)idzadttT%zk_fjCH&}&0y8Uz?Xv}z-6x+`!k34dGN-}DD(ER5M zK#0qEv1?HOJMx!(r$Bg#YV{dzI1%{5j|p>9{Kw+Xv3W_j)6{s<**O}sUfGh~-(Lf} zH{9@d={GVVY-D6w`mm^7uR(XVaFJs?U2QMFu_+jV1FJk;}6+4Qk&ygI$z70 zU0}g8zkb|8(JJMe7bId(lw&zal2vB7Sa2R~G-^h@CNoGKRAm4t2MkxZ5u|C2cH)l* z79d>RNY1tDGMSMY7xX2#-G3;v?mp#R6>?h;gnV6K75vANq~ z^{yrb@!m4)i+q29sYPJ5UX~f5w$71Dp9P#_U)CC!;871+1QL;ExY)(fwwj^&EbadN z!Gp`c6*S4kVa6|QWqc`YUq*M~FaO*kMFiU_Tr8u|kAGjmr4Q~lZ}5tF|BCJEy&S(8 zU)r?&X@RNhjAfc^5tvjml9xl|R*_1Nq_VTFXka#JKFg(rnQMC%gr{rF%b7*Z3dzS` z`KWE{qkYc+NN2InGF|v{*#+b>s%nqRm6)3962h=jay|*X~?eV$>;>?&~c4EQWyi9Ca zmida}#lYLJNN2I^zY2Jb|J736f{9W!HT(o(N{=Oy9ZE4gsD2bF=CHC&vduQ;o& zOoZRq_N`h)0Kc`p78hFadwP1R7IZxQ>&P#&`4{$=OWwJLwbA?%AriUCZYWk7)e`&H zwKyP&Yde3f5Kr=%Gh87v?JsW;ArX7Rx236iIY{BkJaDMm7E%1In%C>exo0S58OQ#s zjlbeR;L*UBZ*a#qcF_*@fY%LwFRXf{zPNQ8X1X_K!;s);fk)GS1?NUt^Ko&3r>CV5 z6@S%LRJxg#8BCpg={0QW*1eEz87Qv>@tHc>>3bWQU%gMLj&!Y&SRInsmWg7JLaf@v zYs1tdPX-H1MYXKf_pOyuZTwjd1jN;%`5I}o1GB4(uS>B_$H(6bw{Y-=8Kf`f3bFiP zgL7p06d>&L!)x2Al?qJioS~1f%5FHmkCoZwS8wf_kGQg8el2x=G%P*}n%AV@xMiWr zmmm77SB$D(-;H<1$5x*o3`;^Bi7HRphtcBphT_kptu*K2Pko#|ToWpI)Ngc@Rw{`p z@b|~9#@R+lPt4U1%~jv1G-KGWyyFad{6ODwlS6jW-U0I}kR+_>+Dm2hoez#So#h=b zJd)&S!E?4R{#3V40lzD#^klXwu%1SQzWiOWYZRD_PFgfB`z%FJ7t>HDk@ahWF5B&x zP_xEhI~|+zS8OPMswXFd-xFR1+l#=+<{o!yWV;3*j(flbLawRLt3kigDv$O-V243NO4WSiPL zI|fK#XE)>ocuEFHU{kV9ZJiwhB(Sp^asoUh10=91*`~J6jsX(b*$p`Xo|1w80M_3A Udd8;AO#lD@07*qoM6N<$f@>q8_y7O^ literal 0 HcmV?d00001 diff --git a/decisionTree/trees.py b/decisionTree/trees.py new file mode 100755 index 0000000..9a6fd52 --- /dev/null +++ b/decisionTree/trees.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# coding: utf-8 + +from math import log + + +# 计算香农熵 +def calcShannonEnt(dataSet): + numEntries = len(dataSet) + labelCounts = {} + for featVec in dataSet: + currentLabel = featVec[-1] + if currentLabel not in labelCounts: + labelCounts[currentLabel] = 0 + labelCounts[currentLabel] += 1 + shannonEnt = 0.0 + for key in labelCounts: + prob = float(labelCounts[key]) / numEntries + shannonEnt -= prob * log(prob, 2) + return shannonEnt + + +# 初始值 +def createDataSet(): + dataSet = [[1, 1, 'yes'], + [1, 0, 'yes'], + [1, 0, 'no'], + [0, 1, 'no'], + [0, 1, 'no']] + label = ['no surfaceing', 'flippers'] + return dataSet, label + + +# 按照给定特征划分数据集 +def splitDataSet(dataSet, axis, value): + retDataSet = [] + for featVec in dataSet: + if featVec[axis] == value: + reducedFeatVec = featVec[:axis] + reducedFeatVec.extend(featVec[axis + 1:]) + retDataSet.append(reducedFeatVec) + return retDataSet + + +# 选择最好数据集的划分方式 +def choooseBestFeatureToSplit(dataSet): + numFeatures = len(dataSet) + baseEntropy = calcShannonEnt(dataSet) + bestInfoGain = 0.0 + bestFeature = -1 + for i in range(numFeatures): + featList = [example[i] for example in dataSet] + uniqyeVals = set(featList) + newEntropy = 0.0 + for value in uniqyeVals: + subDataSet = splitDataSet(dataSet, i, value) + prob = len(subDataSet)/float(len(dataSet)) + newEntropy += prob * calcShannonEnt(subDataSet) + infoGain = baseEntropy - newEntropy + if (infoGain > bestInfoGain): + bestInfoGain = infoGain + bestFeature = i + return bestFeature + +""" +myData, labels = createDataSet() +print(myData) +calcShannonEnt(myData) +myData[0][-1] = 'maybe' +print(myData) +shannonEnt = calcShannonEnt(myData) +print(shannonEnt) +myData[0][-1] = 'yes' +data = splitDataSet(myData, 0, 1) +print(data) +data = splitDataSet(myData, 0, 0) +print(data) +""" diff --git a/index.html b/index.html new file mode 100644 index 0000000..563583f --- /dev/null +++ b/index.html @@ -0,0 +1,9 @@ + + 机器学习 + + + + + diff --git a/knn/KNN.py b/knn/KNN.py new file mode 100755 index 0000000..2502aaa --- /dev/null +++ b/knn/KNN.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- +import math + + +def computeEuclideanDistance(x1, y1, x2, y2): + d = math.sqrt(math.pow((x1 - x2), 2) + math.pow((y1 - y2), 2)) + return d + + +d_ag = computeEuclideanDistance(3, 104, 18, 90) + +print(d_ag) diff --git a/knn/README.md b/knn/README.md new file mode 100644 index 0000000..46d8918 --- /dev/null +++ b/knn/README.md @@ -0,0 +1,18 @@ +# k-近邻算法 + +K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较不成熟的方法,也是最简单的机器学习算法之一。 +该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则 +该样本也属于这个类别。 + +[详解](https://blog.csdn.net/taoyanqi8932/article/details/53727841) + + +## 综述 +- 分类算法 +- 基于实例的学习,懒惰学习 + +## 算法详述 + +### 算法步骤 +为了判断实例的类别,以所有已知实例作为参照 + diff --git a/knn/SklearnExample.py b/knn/SklearnExample.py new file mode 100755 index 0000000..3c2bf45 --- /dev/null +++ b/knn/SklearnExample.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +from sklearn import neighbors +from sklearn import datasets + +knn = neighbors.KNeighborsClassifier() + +iris = datasets.load_iris() + +print iris + +knn.fit(iris.data, iris.target) + +predictedLabel = knn.predict([[0.1, 0.2, 0.3, 0.4]]) + +print predictedLabel diff --git a/knn/knn_test.py b/knn/knn_test.py new file mode 100755 index 0000000..021a6e4 --- /dev/null +++ b/knn/knn_test.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +import numpy as np +import operator + + +def createDataSet(): + group = np.array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]]) + labels = ['A', 'A', 'B', 'B'] + return group, labels + + +# K-近邻算法 +def classify0(inX, dataSet, labels, k): + dataSetSize = np.shape(dataSet)[0] + diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet + sqDiffMat = diffMat ** 2 + sqDistances = np.sum(sqDiffMat, axis=1) + distances = sqDistances ** 0.5 + sortedDistIndicies = np.argsort(distances) + classCount = {} + for i in range(k): + voteLabel = labels[sortedDistIndicies[i]] + classCount[voteLabel] = classCount.get(voteLabel, 0) + 1 + + sortedClassCount = np.sort(classCount.iteritems(), + key=operator.itemgetter(0), + reversed=True) + + return sortedClassCount diff --git a/logistic/LogRegres-gj.py b/logistic/LogRegres-gj.py new file mode 100755 index 0000000..007b7fa --- /dev/null +++ b/logistic/LogRegres-gj.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python3 +# -*- coding:UTF-8 -*- +from matplotlib.font_manager import FontProperties +import matplotlib.pyplot as plt +import numpy as np +import random + + +""" +函数说明:加载数据 + +Parameters: + 无 +Returns: + dataMat - 数据列表 + labelMat - 标签列表 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-28 +""" +def loadDataSet(): + dataMat = [] #创建数据列表 + labelMat = [] #创建标签列表 + fr = open('testSet.txt') #打开文件 + for line in fr.readlines(): #逐行读取 + lineArr = line.strip().split() #去回车,放入列表 + dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) #添加数据 + labelMat.append(int(lineArr[2])) #添加标签 + fr.close() #关闭文件 + return dataMat, labelMat #返回 + +""" +函数说明:sigmoid函数 + +Parameters: + inX - 数据 +Returns: + sigmoid函数 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-28 +""" +def sigmoid(inX): + return 1.0 / (1 + np.exp(-inX)) + +""" +函数说明:梯度上升算法 + +Parameters: + dataMatIn - 数据集 + classLabels - 数据标签 +Returns: + weights.getA() - 求得的权重数组(最优参数) + weights_array - 每次更新的回归系数 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-28 +""" +def gradAscent(dataMatIn, classLabels): + dataMatrix = np.mat(dataMatIn) #转换成numpy的mat + labelMat = np.mat(classLabels).transpose() #转换成numpy的mat,并进行转置 + m, n = np.shape(dataMatrix) #返回dataMatrix的大小。m为行数,n为列数。 + alpha = 0.01 #移动步长,也就是学习速率,控制更新的幅度。 + maxCycles = 500 #最大迭代次数 + weights = np.ones((n,1)) + weights_array = np.array([]) + for k in range(maxCycles): + h = sigmoid(dataMatrix * weights) #梯度上升矢量化公式 + error = labelMat - h + weights = weights + alpha * dataMatrix.transpose() * error + weights_array = np.append(weights_array,weights) + weights_array = weights_array.reshape(maxCycles,n) + return weights.getA(),weights_array #将矩阵转换为数组,并返回 + +""" +函数说明:改进的随机梯度上升算法 + +Parameters: + dataMatrix - 数据数组 + classLabels - 数据标签 + numIter - 迭代次数 +Returns: + weights - 求得的回归系数数组(最优参数) + weights_array - 每次更新的回归系数 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-31 +""" +def stocGradAscent1(dataMatrix, classLabels, numIter=150): + m,n = np.shape(dataMatrix) #返回dataMatrix的大小。m为行数,n为列数。 + weights = np.ones(n) #参数初始化 + weights_array = np.array([]) #存储每次更新的回归系数 + for j in range(numIter): + dataIndex = list(range(m)) + for i in range(m): + alpha = 4/(1.0+j+i)+0.01 #降低alpha的大小,每次减小1/(j+i)。 + randIndex = int(random.uniform(0,len(dataIndex))) #随机选取样本 + h = sigmoid(sum(dataMatrix[randIndex]*weights)) #选择随机选取的一个样本,计算h + error = classLabels[randIndex] - h #计算误差 + weights = weights + alpha * error * dataMatrix[randIndex] #更新回归系数 + weights_array = np.append(weights_array,weights,axis=0) #添加回归系数到数组中 + del(dataIndex[randIndex]) #删除已经使用的样本 + weights_array = weights_array.reshape(numIter*m,n) #改变维度 + return weights,weights_array #返回 + +""" +函数说明:绘制数据集 + +Parameters: + weights - 权重参数数组 +Returns: + 无 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-30 +""" +def plotBestFit(weights): + dataMat, labelMat = loadDataSet() #加载数据集 + dataArr = np.array(dataMat) #转换成numpy的array数组 + n = np.shape(dataMat)[0] #数据个数 + xcord1 = []; ycord1 = [] #正样本 + xcord2 = []; ycord2 = [] #负样本 + for i in range(n): #根据数据集标签进行分类 + if int(labelMat[i]) == 1: + xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2]) #1为正样本 + else: + xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2]) #0为负样本 + fig = plt.figure() + ax = fig.add_subplot(111) #添加subplot + ax.scatter(xcord1, ycord1, s = 20, c = 'red', marker = 's',alpha=.5)#绘制正样本 + ax.scatter(xcord2, ycord2, s = 20, c = 'green',alpha=.5) #绘制负样本 + x = np.arange(-3.0, 3.0, 0.1) + y = (-weights[0] - weights[1] * x) / weights[2] + ax.plot(x, y) + plt.title('BestFit') #绘制title + plt.xlabel('X1'); plt.ylabel('X2') #绘制label + plt.show() + +""" +函数说明:绘制回归系数与迭代次数的关系 + +Parameters: + weights_array1 - 回归系数数组1 + weights_array2 - 回归系数数组2 +Returns: + 无 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-30 +""" +def plotWeights(weights_array1,weights_array2): + #设置汉字格式 + #font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14) + #将fig画布分隔成1行1列,不共享x轴和y轴,fig画布的大小为(13,8) + #当nrow=3,nclos=2时,代表fig画布被分为六个区域,axs[0][0]表示第一行第一列 + fig, axs = plt.subplots(nrows=3, ncols=2,sharex=False, sharey=False, figsize=(20,10)) + x1 = np.arange(0, len(weights_array1), 1) + #绘制w0与迭代次数的关系 + axs[0][0].plot(x1,weights_array1[:,0]) + axs0_title_text = axs[0][0].set_title(u'Improved Random Gradient Rising') + axs0_ylabel_text = axs[0][0].set_ylabel(u'W0') + plt.setp(axs0_title_text, size=20, weight='bold', color='black') + plt.setp(axs0_ylabel_text, size=20, weight='bold', color='black') + #绘制w1与迭代次数的关系 + axs[1][0].plot(x1,weights_array1[:,1]) + axs1_ylabel_text = axs[1][0].set_ylabel(u'W1') + plt.setp(axs1_ylabel_text, size=20, weight='bold', color='black') + #绘制w2与迭代次数的关系 + axs[2][0].plot(x1,weights_array1[:,2]) + axs2_xlabel_text = axs[2][0].set_xlabel(u'Iteration times') + axs2_ylabel_text = axs[2][0].set_ylabel(u'W1') + plt.setp(axs2_xlabel_text, size=20, weight='bold', color='black') + plt.setp(axs2_ylabel_text, size=20, weight='bold', color='black') + + + x2 = np.arange(0, len(weights_array2), 1) + #绘制w0与迭代次数的关系 + axs[0][1].plot(x2,weights_array2[:,0]) + axs0_title_text = axs[0][1].set_title(u'Random Gradient Rising') + axs0_ylabel_text = axs[0][1].set_ylabel(u'W0') + plt.setp(axs0_title_text, size=20, weight='bold', color='black') + plt.setp(axs0_ylabel_text, size=20, weight='bold', color='black') + #绘制w1与迭代次数的关系 + axs[1][1].plot(x2,weights_array2[:,1]) + axs1_ylabel_text = axs[1][1].set_ylabel(u'W1') + plt.setp(axs1_ylabel_text, size=20, weight='bold', color='black') + #绘制w2与迭代次数的关系 + axs[2][1].plot(x2,weights_array2[:,2]) + axs2_xlabel_text = axs[2][1].set_xlabel(u'Iteration times') + axs2_ylabel_text = axs[2][1].set_ylabel(u'W1') + plt.setp(axs2_xlabel_text, size=20, weight='bold', color='black') + plt.setp(axs2_ylabel_text, size=20, weight='bold', color='black') + + plt.show() + +if __name__ == '__main__': + dataMat, labelMat = loadDataSet() + weights1,weights_array1 = stocGradAscent1(np.array(dataMat), labelMat) + + weights2,weights_array2 = gradAscent(dataMat, labelMat) + plotWeights(weights_array1, weights_array2) diff --git a/logistic/colicLogRegres.py b/logistic/colicLogRegres.py new file mode 100755 index 0000000..a0d5d70 --- /dev/null +++ b/logistic/colicLogRegres.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 +# -*- coding:UTF-8 -*- +from sklearn.linear_model import LogisticRegression +import numpy as np +import random + +""" +函数说明:sigmoid函数 + +Parameters: + inX - 数据 +Returns: + sigmoid函数 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-09-05 +""" +def sigmoid(inX): + return 1.0 / (1 + np.exp(-inX)) + +""" +函数说明:改进的随机梯度上升算法 + +Parameters: + dataMatrix - 数据数组 + classLabels - 数据标签 + numIter - 迭代次数 +Returns: + weights - 求得的回归系数数组(最优参数) +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-09-05 +""" +def stocGradAscent1(dataMatrix, classLabels, numIter=150): + m,n = np.shape(dataMatrix) #返回dataMatrix的大小。m为行数,n为列数。 + weights = np.ones(n) #参数初始化 #存储每次更新的回归系数 + for j in range(numIter): + dataIndex = list(range(m)) + for i in range(m): + alpha = 4/(1.0+j+i)+0.01 #降低alpha的大小,每次减小1/(j+i)。 + randIndex = int(random.uniform(0,len(dataIndex))) #随机选取样本 + h = sigmoid(sum(dataMatrix[randIndex]*weights)) #选择随机选取的一个样本,计算h + error = classLabels[randIndex] - h #计算误差 + weights = weights + alpha * error * dataMatrix[randIndex] #更新回归系数 + del(dataIndex[randIndex]) #删除已经使用的样本 + return weights #返回 + + +""" +函数说明:梯度上升算法 + +Parameters: + dataMatIn - 数据集 + classLabels - 数据标签 +Returns: + weights.getA() - 求得的权重数组(最优参数) +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-28 +""" +def gradAscent(dataMatIn, classLabels): + dataMatrix = np.mat(dataMatIn) #转换成numpy的mat + labelMat = np.mat(classLabels).transpose() #转换成numpy的mat,并进行转置 + m, n = np.shape(dataMatrix) #返回dataMatrix的大小。m为行数,n为列数。 + alpha = 0.01 #移动步长,也就是学习速率,控制更新的幅度。 + maxCycles = 500 #最大迭代次数 + weights = np.ones((n,1)) + for k in range(maxCycles): + h = sigmoid(dataMatrix * weights) #梯度上升矢量化公式 + error = labelMat - h + weights = weights + alpha * dataMatrix.transpose() * error + return weights.getA() #将矩阵转换为数组,并返回 + + + +""" +函数说明:使用Python写的Logistic分类器做预测 + +Parameters: + 无 +Returns: + 无 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-09-05 +""" +def colicTest(): + frTrain = open('horseColicTraining.txt') #打开训练集 + frTest = open('horseColicTest.txt') #打开测试集 + trainingSet = []; trainingLabels = [] + for line in frTrain.readlines(): + currLine = line.strip().split('\t') + lineArr = [] + for i in range(len(currLine)-1): + lineArr.append(float(currLine[i])) + trainingSet.append(lineArr) + trainingLabels.append(float(currLine[-1])) + trainWeights = stocGradAscent1(np.array(trainingSet), trainingLabels,500) #使用改进的随即上升梯度训练 + errorCount = 0; numTestVec = 0.0 + for line in frTest.readlines(): + numTestVec += 1.0 + currLine = line.strip().split('\t') + lineArr =[] + for i in range(len(currLine)-1): + lineArr.append(float(currLine[i])) + if int(classifyVector(np.array(lineArr), trainWeights))!= int(currLine[-1]): + errorCount += 1 + errorRate = (float(errorCount)/numTestVec) * 100 #错误率计算 + print("测试集错误率为: %.2f%%" % errorRate) + +""" +函数说明:分类函数 + +Parameters: + inX - 特征向量 + weights - 回归系数 +Returns: + 分类结果 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-09-05 +""" +def classifyVector(inX, weights): + prob = sigmoid(sum(inX*weights)) + if prob > 0.5: return 1.0 + else: return 0.0 + +""" +函数说明:使用Sklearn构建Logistic回归分类器 + +Parameters: + 无 +Returns: + 无 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-09-05 +""" +def colicSklearn(): + frTrain = open('horseColicTraining.txt') #打开训练集 + frTest = open('horseColicTest.txt') #打开测试集 + trainingSet = []; trainingLabels = [] + testSet = []; testLabels = [] + for line in frTrain.readlines(): + currLine = line.strip().split('\t') + lineArr = [] + for i in range(len(currLine)-1): + lineArr.append(float(currLine[i])) + trainingSet.append(lineArr) + trainingLabels.append(float(currLine[-1])) + for line in frTest.readlines(): + currLine = line.strip().split('\t') + lineArr =[] + for i in range(len(currLine)-1): + lineArr.append(float(currLine[i])) + testSet.append(lineArr) + testLabels.append(float(currLine[-1])) + classifier = LogisticRegression(solver = 'sag',max_iter = 5000).fit(trainingSet, trainingLabels) + test_accurcy = classifier.score(testSet, testLabels) * 100 + print('正确率:%f%%' % test_accurcy) + +if __name__ == '__main__': + colicSklearn() diff --git a/logistic/horseColicTest.txt b/logistic/horseColicTest.txt new file mode 100644 index 0000000..ce89e0f --- /dev/null +++ b/logistic/horseColicTest.txt @@ -0,0 +1,67 @@ +2 1 38.50 54 20 0 1 2 2 3 4 1 2 2 5.90 0 2 42.00 6.30 0 0 1 +2 1 37.60 48 36 0 0 1 1 0 3 0 0 0 0 0 0 44.00 6.30 1 5.00 1 +1 1 37.7 44 28 0 4 3 2 5 4 4 1 1 0 3 5 45 70 3 2 1 +1 1 37 56 24 3 1 4 2 4 4 3 1 1 0 0 0 35 61 3 2 0 +2 1 38.00 42 12 3 0 3 1 1 0 1 0 0 0 0 2 37.00 5.80 0 0 1 +1 1 0 60 40 3 0 1 1 0 4 0 3 2 0 0 5 42 72 0 0 1 +2 1 38.40 80 60 3 2 2 1 3 2 1 2 2 0 1 1 54.00 6.90 0 0 1 +2 1 37.80 48 12 2 1 2 1 3 0 1 2 0 0 2 0 48.00 7.30 1 0 1 +2 1 37.90 45 36 3 3 3 2 2 3 1 2 1 0 3 0 33.00 5.70 3 0 1 +2 1 39.00 84 12 3 1 5 1 2 4 2 1 2 7.00 0 4 62.00 5.90 2 2.20 0 +2 1 38.20 60 24 3 1 3 2 3 3 2 3 3 0 4 4 53.00 7.50 2 1.40 1 +1 1 0 140 0 0 0 4 2 5 4 4 1 1 0 0 5 30 69 0 0 0 +1 1 37.90 120 60 3 3 3 1 5 4 4 2 2 7.50 4 5 52.00 6.60 3 1.80 0 +2 1 38.00 72 36 1 1 3 1 3 0 2 2 1 0 3 5 38.00 6.80 2 2.00 1 +2 9 38.00 92 28 1 1 2 1 1 3 2 3 0 7.20 0 0 37.00 6.10 1 1.10 1 +1 1 38.30 66 30 2 3 1 1 2 4 3 3 2 8.50 4 5 37.00 6.00 0 0 1 +2 1 37.50 48 24 3 1 1 1 2 1 0 1 1 0 3 2 43.00 6.00 1 2.80 1 +1 1 37.50 88 20 2 3 3 1 4 3 3 0 0 0 0 0 35.00 6.40 1 0 0 +2 9 0 150 60 4 4 4 2 5 4 4 0 0 0 0 0 0 0 0 0 0 +1 1 39.7 100 30 0 0 6 2 4 4 3 1 0 0 4 5 65 75 0 0 0 +1 1 38.30 80 0 3 3 4 2 5 4 3 2 1 0 4 4 45.00 7.50 2 4.60 1 +2 1 37.50 40 32 3 1 3 1 3 2 3 2 1 0 0 5 32.00 6.40 1 1.10 1 +1 1 38.40 84 30 3 1 5 2 4 3 3 2 3 6.50 4 4 47.00 7.50 3 0 0 +1 1 38.10 84 44 4 0 4 2 5 3 1 1 3 5.00 0 4 60.00 6.80 0 5.70 0 +2 1 38.70 52 0 1 1 1 1 1 3 1 0 0 0 1 3 4.00 74.00 0 0 1 +2 1 38.10 44 40 2 1 3 1 3 3 1 0 0 0 1 3 35.00 6.80 0 0 1 +2 1 38.4 52 20 2 1 3 1 1 3 2 2 1 0 3 5 41 63 1 1 1 +1 1 38.20 60 0 1 0 3 1 2 1 1 1 1 0 4 4 43.00 6.20 2 3.90 1 +2 1 37.70 40 18 1 1 1 0 3 2 1 1 1 0 3 3 36.00 3.50 0 0 1 +1 1 39.1 60 10 0 1 1 0 2 3 0 0 0 0 4 4 0 0 0 0 1 +2 1 37.80 48 16 1 1 1 1 0 1 1 2 1 0 4 3 43.00 7.50 0 0 1 +1 1 39.00 120 0 4 3 5 2 2 4 3 2 3 8.00 0 0 65.00 8.20 3 4.60 1 +1 1 38.20 76 0 2 3 2 1 5 3 3 1 2 6.00 1 5 35.00 6.50 2 0.90 1 +2 1 38.30 88 0 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +1 1 38.00 80 30 3 3 3 1 0 0 0 0 0 6.00 0 0 48.00 8.30 0 4.30 1 +1 1 0 0 0 3 1 1 1 2 3 3 1 3 6.00 4 4 0 0 2 0 0 +1 1 37.60 40 0 1 1 1 1 1 1 1 0 0 0 1 1 0 0 2 2.10 1 +2 1 37.50 44 0 1 1 1 1 3 3 2 0 0 0 0 0 45.00 5.80 2 1.40 1 +2 1 38.2 42 16 1 1 3 1 1 3 1 0 0 0 1 0 35 60 1 1 1 +2 1 38 56 44 3 3 3 0 0 1 1 2 1 0 4 0 47 70 2 1 1 +2 1 38.30 45 20 3 3 2 2 2 4 1 2 0 0 4 0 0 0 0 0 1 +1 1 0 48 96 1 1 3 1 0 4 1 2 1 0 1 4 42.00 8.00 1 0 1 +1 1 37.70 55 28 2 1 2 1 2 3 3 0 3 5.00 4 5 0 0 0 0 1 +2 1 36.00 100 20 4 3 6 2 2 4 3 1 1 0 4 5 74.00 5.70 2 2.50 0 +1 1 37.10 60 20 2 0 4 1 3 0 3 0 2 5.00 3 4 64.00 8.50 2 0 1 +2 1 37.10 114 40 3 0 3 2 2 2 1 0 0 0 0 3 32.00 0 3 6.50 1 +1 1 38.1 72 30 3 3 3 1 4 4 3 2 1 0 3 5 37 56 3 1 1 +1 1 37.00 44 12 3 1 1 2 1 1 1 0 0 0 4 2 40.00 6.70 3 8.00 1 +1 1 38.6 48 20 3 1 1 1 4 3 1 0 0 0 3 0 37 75 0 0 1 +1 1 0 82 72 3 1 4 1 2 3 3 0 3 0 4 4 53 65 3 2 0 +1 9 38.20 78 60 4 4 6 0 3 3 3 0 0 0 1 0 59.00 5.80 3 3.10 0 +2 1 37.8 60 16 1 1 3 1 2 3 2 1 2 0 3 0 41 73 0 0 0 +1 1 38.7 34 30 2 0 3 1 2 3 0 0 0 0 0 0 33 69 0 2 0 +1 1 0 36 12 1 1 1 1 1 2 1 1 1 0 1 5 44.00 0 0 0 1 +2 1 38.30 44 60 0 0 1 1 0 0 0 0 0 0 0 0 6.40 36.00 0 0 1 +2 1 37.40 54 18 3 0 1 1 3 4 3 2 2 0 4 5 30.00 7.10 2 0 1 +1 1 0 0 0 4 3 0 2 2 4 1 0 0 0 0 0 54 76 3 2 1 +1 1 36.6 48 16 3 1 3 1 4 1 1 1 1 0 0 0 27 56 0 0 0 +1 1 38.5 90 0 1 1 3 1 3 3 3 2 3 2 4 5 47 79 0 0 1 +1 1 0 75 12 1 1 4 1 5 3 3 0 3 5.80 0 0 58.00 8.50 1 0 1 +2 1 38.20 42 0 3 1 1 1 1 1 2 2 1 0 3 2 35.00 5.90 2 0 1 +1 9 38.20 78 60 4 4 6 0 3 3 3 0 0 0 1 0 59.00 5.80 3 3.10 0 +2 1 38.60 60 30 1 1 3 1 4 2 2 1 1 0 0 0 40.00 6.00 1 0 1 +2 1 37.80 42 40 1 1 1 1 1 3 1 0 0 0 3 3 36.00 6.20 0 0 1 +1 1 38 60 12 1 1 2 1 2 1 1 1 1 0 1 4 44 65 3 2 0 +2 1 38.00 42 12 3 0 3 1 1 1 1 0 0 0 0 1 37.00 5.80 0 0 1 +2 1 37.60 88 36 3 1 1 1 3 3 2 1 3 1.50 0 0 44.00 6.00 0 0 0 \ No newline at end of file diff --git a/logistic/horseColicTraining.txt b/logistic/horseColicTraining.txt new file mode 100644 index 0000000..def190a --- /dev/null +++ b/logistic/horseColicTraining.txt @@ -0,0 +1,299 @@ +2.000000 1.000000 38.500000 66.000000 28.000000 3.000000 3.000000 0.000000 2.000000 5.000000 4.000000 4.000000 0.000000 0.000000 0.000000 3.000000 5.000000 45.000000 8.400000 0.000000 0.000000 0.000000 +1.000000 1.000000 39.200000 88.000000 20.000000 0.000000 0.000000 4.000000 1.000000 3.000000 4.000000 2.000000 0.000000 0.000000 0.000000 4.000000 2.000000 50.000000 85.000000 2.000000 2.000000 0.000000 +2.000000 1.000000 38.300000 40.000000 24.000000 1.000000 1.000000 3.000000 1.000000 3.000000 3.000000 1.000000 0.000000 0.000000 0.000000 1.000000 1.000000 33.000000 6.700000 0.000000 0.000000 1.000000 +1.000000 9.000000 39.100000 164.000000 84.000000 4.000000 1.000000 6.000000 2.000000 2.000000 4.000000 4.000000 1.000000 2.000000 5.000000 3.000000 0.000000 48.000000 7.200000 3.000000 5.300000 0.000000 +2.000000 1.000000 37.300000 104.000000 35.000000 0.000000 0.000000 6.000000 2.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 74.000000 7.400000 0.000000 0.000000 0.000000 +2.000000 1.000000 0.000000 0.000000 0.000000 2.000000 1.000000 3.000000 1.000000 2.000000 3.000000 2.000000 2.000000 1.000000 0.000000 3.000000 3.000000 0.000000 0.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 37.900000 48.000000 16.000000 1.000000 1.000000 1.000000 1.000000 3.000000 3.000000 3.000000 1.000000 1.000000 0.000000 3.000000 5.000000 37.000000 7.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 60.000000 0.000000 3.000000 0.000000 0.000000 1.000000 0.000000 4.000000 2.000000 2.000000 1.000000 0.000000 3.000000 4.000000 44.000000 8.300000 0.000000 0.000000 0.000000 +2.000000 1.000000 0.000000 80.000000 36.000000 3.000000 4.000000 3.000000 1.000000 4.000000 4.000000 4.000000 2.000000 1.000000 0.000000 3.000000 5.000000 38.000000 6.200000 0.000000 0.000000 0.000000 +2.000000 9.000000 38.300000 90.000000 0.000000 1.000000 0.000000 1.000000 1.000000 5.000000 3.000000 1.000000 2.000000 1.000000 0.000000 3.000000 0.000000 40.000000 6.200000 1.000000 2.200000 1.000000 +1.000000 1.000000 38.100000 66.000000 12.000000 3.000000 3.000000 5.000000 1.000000 3.000000 3.000000 1.000000 2.000000 1.000000 3.000000 2.000000 5.000000 44.000000 6.000000 2.000000 3.600000 1.000000 +2.000000 1.000000 39.100000 72.000000 52.000000 2.000000 0.000000 2.000000 1.000000 2.000000 1.000000 2.000000 1.000000 1.000000 0.000000 4.000000 4.000000 50.000000 7.800000 0.000000 0.000000 1.000000 +1.000000 1.000000 37.200000 42.000000 12.000000 2.000000 1.000000 1.000000 1.000000 3.000000 3.000000 3.000000 3.000000 1.000000 0.000000 4.000000 5.000000 0.000000 7.000000 0.000000 0.000000 1.000000 +2.000000 9.000000 38.000000 92.000000 28.000000 1.000000 1.000000 2.000000 1.000000 1.000000 3.000000 2.000000 3.000000 0.000000 7.200000 1.000000 1.000000 37.000000 6.100000 1.000000 0.000000 0.000000 +1.000000 1.000000 38.200000 76.000000 28.000000 3.000000 1.000000 1.000000 1.000000 3.000000 4.000000 1.000000 2.000000 2.000000 0.000000 4.000000 4.000000 46.000000 81.000000 1.000000 2.000000 1.000000 +1.000000 1.000000 37.600000 96.000000 48.000000 3.000000 1.000000 4.000000 1.000000 5.000000 3.000000 3.000000 2.000000 3.000000 4.500000 4.000000 0.000000 45.000000 6.800000 0.000000 0.000000 0.000000 +1.000000 9.000000 0.000000 128.000000 36.000000 3.000000 3.000000 4.000000 2.000000 4.000000 4.000000 3.000000 3.000000 0.000000 0.000000 4.000000 5.000000 53.000000 7.800000 3.000000 4.700000 0.000000 +2.000000 1.000000 37.500000 48.000000 24.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 37.600000 64.000000 21.000000 1.000000 1.000000 2.000000 1.000000 2.000000 3.000000 1.000000 1.000000 1.000000 0.000000 2.000000 5.000000 40.000000 7.000000 1.000000 0.000000 1.000000 +2.000000 1.000000 39.400000 110.000000 35.000000 4.000000 3.000000 6.000000 0.000000 0.000000 3.000000 3.000000 0.000000 0.000000 0.000000 0.000000 0.000000 55.000000 8.700000 0.000000 0.000000 1.000000 +1.000000 1.000000 39.900000 72.000000 60.000000 1.000000 1.000000 5.000000 2.000000 5.000000 4.000000 4.000000 3.000000 1.000000 0.000000 4.000000 4.000000 46.000000 6.100000 2.000000 0.000000 1.000000 +2.000000 1.000000 38.400000 48.000000 16.000000 1.000000 0.000000 1.000000 1.000000 1.000000 3.000000 1.000000 2.000000 3.000000 5.500000 4.000000 3.000000 49.000000 6.800000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.600000 42.000000 34.000000 2.000000 1.000000 4.000000 0.000000 2.000000 3.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 48.000000 7.200000 0.000000 0.000000 1.000000 +1.000000 9.000000 38.300000 130.000000 60.000000 0.000000 3.000000 0.000000 1.000000 2.000000 4.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 50.000000 70.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.100000 60.000000 12.000000 3.000000 3.000000 3.000000 1.000000 0.000000 4.000000 3.000000 3.000000 2.000000 2.000000 0.000000 0.000000 51.000000 65.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 37.800000 60.000000 42.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.300000 72.000000 30.000000 4.000000 3.000000 3.000000 2.000000 3.000000 3.000000 3.000000 2.000000 1.000000 0.000000 3.000000 5.000000 43.000000 7.000000 2.000000 3.900000 1.000000 +1.000000 1.000000 37.800000 48.000000 12.000000 3.000000 1.000000 1.000000 1.000000 0.000000 3.000000 2.000000 1.000000 1.000000 0.000000 1.000000 3.000000 37.000000 5.500000 2.000000 1.300000 1.000000 +1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.700000 48.000000 0.000000 2.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 45.000000 76.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 37.700000 96.000000 30.000000 3.000000 3.000000 4.000000 2.000000 5.000000 4.000000 4.000000 3.000000 2.000000 4.000000 4.000000 5.000000 66.000000 7.500000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.200000 108.000000 12.000000 3.000000 3.000000 4.000000 2.000000 2.000000 4.000000 2.000000 0.000000 3.000000 6.000000 3.000000 3.000000 52.000000 8.200000 3.000000 7.400000 0.000000 +1.000000 1.000000 37.200000 60.000000 0.000000 2.000000 1.000000 1.000000 1.000000 3.000000 3.000000 3.000000 2.000000 1.000000 0.000000 4.000000 5.000000 43.000000 6.600000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.200000 64.000000 28.000000 1.000000 1.000000 1.000000 1.000000 3.000000 1.000000 0.000000 0.000000 0.000000 0.000000 4.000000 4.000000 49.000000 8.600000 2.000000 6.600000 1.000000 +1.000000 1.000000 0.000000 100.000000 30.000000 3.000000 3.000000 4.000000 2.000000 5.000000 4.000000 4.000000 3.000000 3.000000 0.000000 4.000000 4.000000 52.000000 6.600000 0.000000 0.000000 1.000000 +2.000000 1.000000 0.000000 104.000000 24.000000 4.000000 3.000000 3.000000 2.000000 4.000000 4.000000 3.000000 0.000000 3.000000 0.000000 0.000000 2.000000 73.000000 8.400000 0.000000 0.000000 0.000000 +2.000000 1.000000 38.300000 112.000000 16.000000 0.000000 3.000000 5.000000 2.000000 0.000000 0.000000 1.000000 1.000000 2.000000 0.000000 0.000000 5.000000 51.000000 6.000000 2.000000 1.000000 0.000000 +1.000000 1.000000 37.800000 72.000000 0.000000 0.000000 3.000000 0.000000 1.000000 5.000000 3.000000 1.000000 0.000000 1.000000 0.000000 1.000000 1.000000 56.000000 80.000000 1.000000 2.000000 1.000000 +2.000000 1.000000 38.600000 52.000000 0.000000 1.000000 1.000000 1.000000 1.000000 3.000000 3.000000 2.000000 1.000000 1.000000 0.000000 1.000000 3.000000 32.000000 6.600000 1.000000 5.000000 1.000000 +1.000000 9.000000 39.200000 146.000000 96.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 +1.000000 1.000000 0.000000 88.000000 0.000000 3.000000 3.000000 6.000000 2.000000 5.000000 3.000000 3.000000 1.000000 3.000000 0.000000 4.000000 5.000000 63.000000 6.500000 3.000000 0.000000 0.000000 +2.000000 9.000000 39.000000 150.000000 72.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 47.000000 8.500000 0.000000 0.100000 1.000000 +2.000000 1.000000 38.000000 60.000000 12.000000 3.000000 1.000000 3.000000 1.000000 3.000000 3.000000 1.000000 1.000000 1.000000 0.000000 2.000000 2.000000 47.000000 7.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 120.000000 0.000000 3.000000 4.000000 4.000000 1.000000 4.000000 4.000000 4.000000 1.000000 1.000000 0.000000 0.000000 5.000000 52.000000 67.000000 2.000000 2.000000 0.000000 +1.000000 1.000000 35.400000 140.000000 24.000000 3.000000 3.000000 4.000000 2.000000 4.000000 4.000000 0.000000 2.000000 1.000000 0.000000 0.000000 5.000000 57.000000 69.000000 3.000000 2.000000 0.000000 +2.000000 1.000000 0.000000 120.000000 0.000000 4.000000 3.000000 4.000000 2.000000 5.000000 4.000000 4.000000 1.000000 1.000000 0.000000 4.000000 5.000000 60.000000 6.500000 3.000000 0.000000 0.000000 +1.000000 1.000000 37.900000 60.000000 15.000000 3.000000 0.000000 4.000000 2.000000 5.000000 4.000000 4.000000 2.000000 2.000000 0.000000 4.000000 5.000000 65.000000 7.500000 0.000000 0.000000 1.000000 +2.000000 1.000000 37.500000 48.000000 16.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 1.000000 0.000000 37.000000 6.500000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.900000 80.000000 44.000000 3.000000 3.000000 3.000000 2.000000 2.000000 3.000000 3.000000 2.000000 2.000000 7.000000 3.000000 1.000000 54.000000 6.500000 3.000000 0.000000 0.000000 +2.000000 1.000000 37.200000 84.000000 48.000000 3.000000 3.000000 5.000000 2.000000 4.000000 1.000000 2.000000 1.000000 2.000000 0.000000 2.000000 1.000000 73.000000 5.500000 2.000000 4.100000 0.000000 +2.000000 1.000000 38.600000 46.000000 0.000000 1.000000 1.000000 2.000000 1.000000 1.000000 3.000000 2.000000 1.000000 1.000000 0.000000 0.000000 2.000000 49.000000 9.100000 1.000000 1.600000 1.000000 +1.000000 1.000000 37.400000 84.000000 36.000000 1.000000 0.000000 3.000000 2.000000 3.000000 3.000000 2.000000 0.000000 0.000000 0.000000 4.000000 5.000000 0.000000 0.000000 3.000000 0.000000 0.000000 +2.000000 1.000000 0.000000 0.000000 0.000000 1.000000 1.000000 3.000000 1.000000 1.000000 3.000000 1.000000 0.000000 0.000000 0.000000 2.000000 2.000000 43.000000 7.700000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.600000 40.000000 20.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 41.000000 6.400000 0.000000 0.000000 1.000000 +2.000000 1.000000 40.300000 114.000000 36.000000 3.000000 3.000000 1.000000 2.000000 2.000000 3.000000 3.000000 2.000000 1.000000 7.000000 1.000000 5.000000 57.000000 8.100000 3.000000 4.500000 0.000000 +1.000000 9.000000 38.600000 160.000000 20.000000 3.000000 0.000000 5.000000 1.000000 3.000000 3.000000 4.000000 3.000000 0.000000 0.000000 4.000000 0.000000 38.000000 0.000000 2.000000 0.000000 0.000000 +1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 24.000000 6.700000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 64.000000 36.000000 2.000000 0.000000 2.000000 1.000000 5.000000 3.000000 3.000000 2.000000 2.000000 0.000000 0.000000 0.000000 42.000000 7.700000 0.000000 0.000000 0.000000 +1.000000 1.000000 0.000000 0.000000 20.000000 4.000000 3.000000 3.000000 0.000000 5.000000 4.000000 3.000000 2.000000 0.000000 0.000000 4.000000 4.000000 53.000000 5.900000 3.000000 0.000000 0.000000 +2.000000 1.000000 0.000000 96.000000 0.000000 3.000000 3.000000 3.000000 2.000000 5.000000 4.000000 4.000000 1.000000 2.000000 0.000000 4.000000 5.000000 60.000000 0.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.800000 48.000000 32.000000 1.000000 1.000000 3.000000 1.000000 2.000000 1.000000 0.000000 1.000000 1.000000 0.000000 4.000000 5.000000 37.000000 6.700000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.500000 60.000000 0.000000 2.000000 2.000000 1.000000 1.000000 1.000000 2.000000 2.000000 2.000000 1.000000 0.000000 1.000000 1.000000 44.000000 7.700000 0.000000 0.000000 1.000000 +1.000000 1.000000 37.800000 88.000000 22.000000 2.000000 1.000000 2.000000 1.000000 3.000000 0.000000 0.000000 2.000000 0.000000 0.000000 4.000000 0.000000 64.000000 8.000000 1.000000 6.000000 0.000000 +2.000000 1.000000 38.200000 130.000000 16.000000 4.000000 3.000000 4.000000 2.000000 2.000000 4.000000 4.000000 1.000000 1.000000 0.000000 0.000000 0.000000 65.000000 82.000000 2.000000 2.000000 0.000000 +1.000000 1.000000 39.000000 64.000000 36.000000 3.000000 1.000000 4.000000 2.000000 3.000000 3.000000 2.000000 1.000000 2.000000 7.000000 4.000000 5.000000 44.000000 7.500000 3.000000 5.000000 1.000000 +1.000000 1.000000 0.000000 60.000000 36.000000 3.000000 1.000000 3.000000 1.000000 3.000000 3.000000 2.000000 1.000000 1.000000 0.000000 3.000000 4.000000 26.000000 72.000000 2.000000 1.000000 1.000000 +2.000000 1.000000 37.900000 72.000000 0.000000 1.000000 1.000000 5.000000 2.000000 3.000000 3.000000 1.000000 1.000000 3.000000 2.000000 3.000000 4.000000 58.000000 74.000000 1.000000 2.000000 1.000000 +2.000000 1.000000 38.400000 54.000000 24.000000 1.000000 1.000000 1.000000 1.000000 1.000000 3.000000 1.000000 2.000000 1.000000 0.000000 3.000000 2.000000 49.000000 7.200000 1.000000 0.000000 1.000000 +2.000000 1.000000 0.000000 52.000000 16.000000 1.000000 0.000000 3.000000 1.000000 0.000000 0.000000 0.000000 2.000000 3.000000 5.500000 0.000000 0.000000 55.000000 7.200000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.000000 48.000000 12.000000 1.000000 1.000000 1.000000 1.000000 1.000000 3.000000 0.000000 1.000000 1.000000 0.000000 3.000000 2.000000 42.000000 6.300000 2.000000 4.100000 1.000000 +2.000000 1.000000 37.000000 60.000000 20.000000 3.000000 0.000000 0.000000 1.000000 3.000000 0.000000 3.000000 2.000000 2.000000 4.500000 4.000000 4.000000 43.000000 7.600000 0.000000 0.000000 0.000000 +1.000000 1.000000 37.800000 48.000000 28.000000 1.000000 1.000000 1.000000 1.000000 1.000000 2.000000 1.000000 2.000000 0.000000 0.000000 1.000000 1.000000 46.000000 5.900000 2.000000 7.000000 1.000000 +1.000000 1.000000 37.700000 56.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.100000 52.000000 24.000000 1.000000 1.000000 5.000000 1.000000 4.000000 3.000000 1.000000 2.000000 3.000000 7.000000 1.000000 0.000000 54.000000 7.500000 2.000000 2.600000 0.000000 +1.000000 9.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 37.000000 4.900000 0.000000 0.000000 0.000000 +1.000000 9.000000 39.700000 100.000000 0.000000 3.000000 3.000000 5.000000 2.000000 2.000000 3.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 48.000000 57.000000 2.000000 2.000000 0.000000 +1.000000 1.000000 37.600000 38.000000 20.000000 3.000000 3.000000 1.000000 1.000000 3.000000 3.000000 2.000000 0.000000 0.000000 0.000000 3.000000 0.000000 37.000000 68.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.700000 52.000000 20.000000 2.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 1.000000 1.000000 33.000000 77.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 0.000000 0.000000 3.000000 3.000000 3.000000 3.000000 5.000000 3.000000 3.000000 3.000000 2.000000 0.000000 4.000000 5.000000 46.000000 5.900000 0.000000 0.000000 0.000000 +1.000000 1.000000 37.500000 96.000000 18.000000 1.000000 3.000000 6.000000 2.000000 3.000000 4.000000 2.000000 2.000000 3.000000 5.000000 0.000000 4.000000 69.000000 8.900000 3.000000 0.000000 1.000000 +1.000000 1.000000 36.400000 98.000000 35.000000 3.000000 3.000000 4.000000 1.000000 4.000000 3.000000 2.000000 0.000000 0.000000 0.000000 4.000000 4.000000 47.000000 6.400000 3.000000 3.600000 0.000000 +1.000000 1.000000 37.300000 40.000000 0.000000 0.000000 3.000000 1.000000 1.000000 2.000000 3.000000 2.000000 3.000000 1.000000 0.000000 3.000000 5.000000 36.000000 0.000000 3.000000 2.000000 1.000000 +1.000000 9.000000 38.100000 100.000000 80.000000 3.000000 1.000000 2.000000 1.000000 3.000000 4.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 36.000000 5.700000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.000000 0.000000 24.000000 3.000000 3.000000 6.000000 2.000000 5.000000 0.000000 4.000000 1.000000 1.000000 0.000000 0.000000 0.000000 68.000000 7.800000 0.000000 0.000000 0.000000 +1.000000 1.000000 37.800000 60.000000 80.000000 1.000000 3.000000 2.000000 2.000000 2.000000 3.000000 3.000000 0.000000 2.000000 5.500000 4.000000 0.000000 40.000000 4.500000 2.000000 0.000000 1.000000 +2.000000 1.000000 38.000000 54.000000 30.000000 2.000000 3.000000 3.000000 3.000000 3.000000 1.000000 2.000000 2.000000 2.000000 0.000000 0.000000 4.000000 45.000000 6.200000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 88.000000 40.000000 3.000000 3.000000 4.000000 2.000000 5.000000 4.000000 3.000000 3.000000 0.000000 0.000000 4.000000 5.000000 50.000000 7.700000 3.000000 1.400000 0.000000 +2.000000 1.000000 0.000000 40.000000 16.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 50.000000 7.000000 2.000000 3.900000 0.000000 +2.000000 1.000000 39.000000 64.000000 40.000000 1.000000 1.000000 5.000000 1.000000 3.000000 3.000000 2.000000 2.000000 1.000000 0.000000 3.000000 3.000000 42.000000 7.500000 2.000000 2.300000 1.000000 +2.000000 1.000000 38.300000 42.000000 10.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 38.000000 61.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.000000 52.000000 16.000000 0.000000 0.000000 0.000000 0.000000 2.000000 0.000000 0.000000 0.000000 3.000000 1.000000 1.000000 1.000000 53.000000 86.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 40.300000 114.000000 36.000000 3.000000 3.000000 1.000000 2.000000 2.000000 3.000000 3.000000 2.000000 1.000000 7.000000 1.000000 5.000000 57.000000 8.100000 3.000000 4.500000 0.000000 +2.000000 1.000000 38.800000 50.000000 20.000000 3.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 2.000000 1.000000 0.000000 3.000000 1.000000 42.000000 6.200000 0.000000 0.000000 1.000000 +2.000000 1.000000 0.000000 0.000000 0.000000 3.000000 3.000000 1.000000 1.000000 5.000000 3.000000 3.000000 1.000000 1.000000 0.000000 4.000000 5.000000 38.000000 6.500000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.500000 48.000000 30.000000 4.000000 1.000000 3.000000 1.000000 0.000000 2.000000 1.000000 1.000000 1.000000 0.000000 1.000000 1.000000 48.000000 8.600000 0.000000 0.000000 1.000000 +1.000000 1.000000 37.300000 48.000000 20.000000 0.000000 1.000000 2.000000 1.000000 3.000000 3.000000 3.000000 2.000000 1.000000 0.000000 3.000000 5.000000 41.000000 69.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 0.000000 84.000000 36.000000 0.000000 0.000000 3.000000 1.000000 0.000000 3.000000 1.000000 2.000000 1.000000 0.000000 3.000000 2.000000 44.000000 8.500000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.100000 88.000000 32.000000 3.000000 3.000000 4.000000 1.000000 2.000000 3.000000 3.000000 0.000000 3.000000 1.000000 4.000000 5.000000 55.000000 60.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.700000 44.000000 40.000000 2.000000 1.000000 3.000000 1.000000 1.000000 3.000000 2.000000 1.000000 1.000000 0.000000 1.000000 5.000000 41.000000 60.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 39.600000 108.000000 51.000000 3.000000 3.000000 6.000000 2.000000 2.000000 4.000000 3.000000 1.000000 2.000000 0.000000 3.000000 5.000000 59.000000 8.000000 2.000000 2.600000 1.000000 +1.000000 1.000000 38.200000 40.000000 16.000000 3.000000 3.000000 1.000000 1.000000 1.000000 3.000000 0.000000 0.000000 0.000000 0.000000 1.000000 1.000000 34.000000 66.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 60.000000 20.000000 4.000000 3.000000 4.000000 2.000000 5.000000 4.000000 0.000000 0.000000 1.000000 0.000000 4.000000 5.000000 0.000000 0.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 38.300000 40.000000 16.000000 3.000000 0.000000 1.000000 1.000000 2.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 37.000000 57.000000 0.000000 0.000000 1.000000 +1.000000 9.000000 38.000000 140.000000 68.000000 1.000000 1.000000 1.000000 1.000000 3.000000 3.000000 2.000000 0.000000 0.000000 0.000000 2.000000 1.000000 39.000000 5.300000 0.000000 0.000000 1.000000 +1.000000 1.000000 37.800000 52.000000 24.000000 1.000000 3.000000 3.000000 1.000000 4.000000 4.000000 1.000000 2.000000 3.000000 5.700000 2.000000 5.000000 48.000000 6.600000 1.000000 3.700000 0.000000 +1.000000 1.000000 0.000000 70.000000 36.000000 1.000000 0.000000 3.000000 2.000000 2.000000 3.000000 2.000000 2.000000 0.000000 0.000000 4.000000 5.000000 36.000000 7.300000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.300000 52.000000 96.000000 0.000000 3.000000 3.000000 1.000000 0.000000 0.000000 0.000000 1.000000 1.000000 0.000000 1.000000 0.000000 43.000000 6.100000 0.000000 0.000000 1.000000 +2.000000 1.000000 37.300000 50.000000 32.000000 1.000000 1.000000 3.000000 1.000000 1.000000 3.000000 2.000000 0.000000 0.000000 0.000000 1.000000 0.000000 44.000000 7.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.700000 60.000000 32.000000 4.000000 3.000000 2.000000 2.000000 4.000000 4.000000 4.000000 0.000000 0.000000 0.000000 4.000000 5.000000 53.000000 64.000000 3.000000 2.000000 0.000000 +1.000000 9.000000 38.400000 84.000000 40.000000 3.000000 3.000000 2.000000 1.000000 3.000000 3.000000 3.000000 1.000000 1.000000 0.000000 0.000000 0.000000 36.000000 6.600000 2.000000 2.800000 0.000000 +1.000000 1.000000 0.000000 70.000000 16.000000 3.000000 4.000000 5.000000 2.000000 2.000000 3.000000 2.000000 2.000000 1.000000 0.000000 4.000000 5.000000 60.000000 7.500000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.300000 40.000000 16.000000 3.000000 0.000000 0.000000 1.000000 1.000000 3.000000 2.000000 0.000000 0.000000 0.000000 0.000000 0.000000 38.000000 58.000000 1.000000 2.000000 1.000000 +1.000000 1.000000 0.000000 40.000000 0.000000 2.000000 1.000000 1.000000 1.000000 1.000000 3.000000 1.000000 1.000000 1.000000 0.000000 0.000000 5.000000 39.000000 56.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 36.800000 60.000000 28.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 10.000000 0.000000 +1.000000 1.000000 38.400000 44.000000 24.000000 3.000000 0.000000 4.000000 0.000000 5.000000 4.000000 3.000000 2.000000 1.000000 0.000000 4.000000 5.000000 50.000000 77.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 0.000000 0.000000 40.000000 3.000000 1.000000 1.000000 1.000000 3.000000 3.000000 2.000000 0.000000 0.000000 0.000000 0.000000 0.000000 45.000000 70.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.000000 44.000000 12.000000 1.000000 1.000000 1.000000 1.000000 3.000000 3.000000 3.000000 2.000000 1.000000 0.000000 4.000000 5.000000 42.000000 65.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 39.500000 0.000000 0.000000 3.000000 3.000000 4.000000 2.000000 3.000000 4.000000 3.000000 0.000000 3.000000 5.500000 4.000000 5.000000 0.000000 6.700000 1.000000 0.000000 0.000000 +1.000000 1.000000 36.500000 78.000000 30.000000 1.000000 0.000000 1.000000 1.000000 5.000000 3.000000 1.000000 0.000000 1.000000 0.000000 0.000000 0.000000 34.000000 75.000000 2.000000 1.000000 1.000000 +2.000000 1.000000 38.100000 56.000000 20.000000 2.000000 1.000000 2.000000 1.000000 1.000000 3.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 46.000000 70.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 39.400000 54.000000 66.000000 1.000000 1.000000 2.000000 1.000000 2.000000 3.000000 2.000000 1.000000 1.000000 0.000000 3.000000 4.000000 39.000000 6.000000 2.000000 0.000000 1.000000 +1.000000 1.000000 38.300000 80.000000 40.000000 0.000000 0.000000 6.000000 2.000000 4.000000 3.000000 1.000000 0.000000 2.000000 0.000000 1.000000 4.000000 67.000000 10.200000 2.000000 1.000000 0.000000 +2.000000 1.000000 38.700000 40.000000 28.000000 2.000000 1.000000 1.000000 1.000000 3.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 39.000000 62.000000 1.000000 1.000000 1.000000 +1.000000 1.000000 38.200000 64.000000 24.000000 1.000000 1.000000 3.000000 1.000000 4.000000 4.000000 3.000000 2.000000 1.000000 0.000000 4.000000 4.000000 45.000000 7.500000 1.000000 2.000000 0.000000 +2.000000 1.000000 37.600000 48.000000 20.000000 3.000000 1.000000 4.000000 1.000000 1.000000 1.000000 3.000000 2.000000 1.000000 0.000000 1.000000 1.000000 37.000000 5.500000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.000000 42.000000 68.000000 4.000000 1.000000 1.000000 1.000000 3.000000 3.000000 2.000000 2.000000 2.000000 0.000000 4.000000 4.000000 41.000000 7.600000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.700000 0.000000 0.000000 3.000000 1.000000 3.000000 1.000000 5.000000 4.000000 2.000000 0.000000 0.000000 0.000000 0.000000 0.000000 33.000000 6.500000 2.000000 0.000000 1.000000 +1.000000 1.000000 37.400000 50.000000 32.000000 3.000000 3.000000 0.000000 1.000000 4.000000 4.000000 1.000000 2.000000 1.000000 0.000000 1.000000 0.000000 45.000000 7.900000 2.000000 1.000000 1.000000 +1.000000 1.000000 37.400000 84.000000 20.000000 0.000000 0.000000 3.000000 1.000000 2.000000 3.000000 3.000000 0.000000 0.000000 0.000000 0.000000 0.000000 31.000000 61.000000 0.000000 1.000000 0.000000 +1.000000 1.000000 38.400000 49.000000 0.000000 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 1.000000 2.000000 1.000000 0.000000 0.000000 0.000000 44.000000 7.600000 0.000000 0.000000 1.000000 +1.000000 1.000000 37.800000 30.000000 12.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.600000 88.000000 36.000000 3.000000 1.000000 1.000000 1.000000 3.000000 3.000000 2.000000 1.000000 3.000000 1.500000 0.000000 0.000000 44.000000 6.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.900000 40.000000 24.000000 1.000000 1.000000 1.000000 1.000000 2.000000 3.000000 1.000000 0.000000 0.000000 0.000000 0.000000 3.000000 40.000000 5.700000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 100.000000 0.000000 3.000000 0.000000 4.000000 2.000000 5.000000 4.000000 0.000000 2.000000 0.000000 0.000000 2.000000 0.000000 59.000000 6.300000 0.000000 0.000000 0.000000 +1.000000 9.000000 38.100000 136.000000 48.000000 3.000000 3.000000 3.000000 1.000000 5.000000 1.000000 3.000000 2.000000 2.000000 4.400000 2.000000 0.000000 33.000000 4.900000 2.000000 2.900000 0.000000 +1.000000 1.000000 0.000000 0.000000 0.000000 3.000000 3.000000 3.000000 2.000000 5.000000 3.000000 3.000000 3.000000 2.000000 0.000000 4.000000 5.000000 46.000000 5.900000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.000000 48.000000 0.000000 1.000000 1.000000 1.000000 1.000000 1.000000 2.000000 4.000000 2.000000 2.000000 0.000000 4.000000 5.000000 0.000000 0.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.000000 56.000000 0.000000 1.000000 2.000000 3.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 1.000000 1.000000 42.000000 71.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.000000 60.000000 32.000000 1.000000 1.000000 0.000000 1.000000 3.000000 3.000000 0.000000 1.000000 1.000000 0.000000 0.000000 0.000000 50.000000 7.000000 1.000000 1.000000 1.000000 +1.000000 1.000000 38.100000 44.000000 9.000000 3.000000 1.000000 1.000000 1.000000 2.000000 2.000000 1.000000 1.000000 1.000000 0.000000 4.000000 5.000000 31.000000 7.300000 0.000000 0.000000 1.000000 +2.000000 1.000000 36.000000 42.000000 30.000000 0.000000 0.000000 5.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 64.000000 6.800000 0.000000 0.000000 0.000000 +1.000000 1.000000 0.000000 120.000000 0.000000 4.000000 3.000000 6.000000 2.000000 5.000000 4.000000 4.000000 0.000000 0.000000 0.000000 4.000000 5.000000 57.000000 4.500000 3.000000 3.900000 0.000000 +1.000000 1.000000 37.800000 48.000000 28.000000 1.000000 1.000000 1.000000 2.000000 1.000000 2.000000 1.000000 2.000000 0.000000 0.000000 1.000000 1.000000 46.000000 5.900000 2.000000 7.000000 1.000000 +1.000000 1.000000 37.100000 84.000000 40.000000 3.000000 3.000000 6.000000 1.000000 2.000000 4.000000 4.000000 3.000000 2.000000 2.000000 4.000000 5.000000 75.000000 81.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 0.000000 80.000000 32.000000 3.000000 3.000000 2.000000 1.000000 2.000000 3.000000 3.000000 2.000000 1.000000 0.000000 3.000000 0.000000 50.000000 80.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.200000 48.000000 0.000000 1.000000 3.000000 3.000000 1.000000 3.000000 4.000000 4.000000 1.000000 3.000000 2.000000 4.000000 5.000000 42.000000 71.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.000000 44.000000 12.000000 2.000000 1.000000 3.000000 1.000000 3.000000 4.000000 3.000000 1.000000 2.000000 6.500000 1.000000 4.000000 33.000000 6.500000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.300000 132.000000 0.000000 0.000000 3.000000 6.000000 2.000000 2.000000 4.000000 2.000000 2.000000 3.000000 6.200000 4.000000 4.000000 57.000000 8.000000 0.000000 5.200000 1.000000 +2.000000 1.000000 38.700000 48.000000 24.000000 0.000000 0.000000 0.000000 0.000000 1.000000 1.000000 0.000000 1.000000 1.000000 0.000000 1.000000 0.000000 34.000000 63.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.900000 44.000000 14.000000 3.000000 1.000000 1.000000 1.000000 2.000000 3.000000 2.000000 0.000000 0.000000 0.000000 0.000000 2.000000 33.000000 64.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 39.300000 0.000000 0.000000 4.000000 3.000000 6.000000 2.000000 4.000000 4.000000 2.000000 1.000000 3.000000 4.000000 4.000000 4.000000 75.000000 0.000000 3.000000 4.300000 0.000000 +1.000000 1.000000 0.000000 100.000000 0.000000 3.000000 3.000000 4.000000 2.000000 0.000000 4.000000 4.000000 2.000000 1.000000 2.000000 0.000000 0.000000 68.000000 64.000000 3.000000 2.000000 1.000000 +2.000000 1.000000 38.600000 48.000000 20.000000 3.000000 1.000000 1.000000 1.000000 1.000000 3.000000 2.000000 2.000000 1.000000 0.000000 3.000000 2.000000 50.000000 7.300000 1.000000 0.000000 1.000000 +2.000000 1.000000 38.800000 48.000000 40.000000 1.000000 1.000000 3.000000 1.000000 3.000000 3.000000 4.000000 2.000000 0.000000 0.000000 0.000000 5.000000 41.000000 65.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.000000 48.000000 20.000000 3.000000 3.000000 4.000000 1.000000 1.000000 4.000000 2.000000 2.000000 0.000000 5.000000 0.000000 2.000000 49.000000 8.300000 1.000000 0.000000 1.000000 +2.000000 1.000000 38.600000 52.000000 20.000000 1.000000 1.000000 1.000000 1.000000 3.000000 3.000000 2.000000 1.000000 1.000000 0.000000 1.000000 3.000000 36.000000 6.600000 1.000000 5.000000 1.000000 +1.000000 1.000000 37.800000 60.000000 24.000000 1.000000 0.000000 3.000000 2.000000 0.000000 4.000000 4.000000 2.000000 3.000000 2.000000 0.000000 5.000000 52.000000 75.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 38.000000 42.000000 40.000000 3.000000 1.000000 1.000000 1.000000 3.000000 3.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 0.000000 0.000000 12.000000 1.000000 1.000000 2.000000 1.000000 2.000000 1.000000 2.000000 3.000000 1.000000 0.000000 1.000000 3.000000 44.000000 7.500000 2.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 4.000000 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 5.000000 35.000000 58.000000 2.000000 1.000000 1.000000 +1.000000 1.000000 38.300000 42.000000 24.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 40.000000 8.500000 0.000000 0.000000 0.000000 +2.000000 1.000000 39.500000 60.000000 10.000000 3.000000 0.000000 0.000000 2.000000 3.000000 3.000000 2.000000 2.000000 1.000000 0.000000 3.000000 0.000000 38.000000 56.000000 1.000000 0.000000 1.000000 +1.000000 1.000000 38.000000 66.000000 20.000000 1.000000 3.000000 3.000000 1.000000 5.000000 3.000000 1.000000 1.000000 1.000000 0.000000 3.000000 0.000000 46.000000 46.000000 3.000000 2.000000 0.000000 +1.000000 1.000000 38.700000 76.000000 0.000000 1.000000 1.000000 5.000000 2.000000 3.000000 3.000000 2.000000 2.000000 2.000000 0.000000 4.000000 4.000000 50.000000 8.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 39.400000 120.000000 48.000000 0.000000 0.000000 5.000000 1.000000 0.000000 3.000000 3.000000 1.000000 0.000000 0.000000 4.000000 0.000000 56.000000 64.000000 1.000000 2.000000 0.000000 +1.000000 1.000000 38.300000 40.000000 18.000000 1.000000 1.000000 1.000000 1.000000 3.000000 1.000000 1.000000 0.000000 0.000000 0.000000 2.000000 1.000000 43.000000 5.900000 1.000000 0.000000 1.000000 +2.000000 1.000000 0.000000 44.000000 24.000000 1.000000 1.000000 1.000000 1.000000 3.000000 3.000000 1.000000 2.000000 1.000000 0.000000 0.000000 1.000000 0.000000 6.300000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.400000 104.000000 40.000000 1.000000 1.000000 3.000000 1.000000 2.000000 4.000000 2.000000 2.000000 3.000000 6.500000 0.000000 4.000000 55.000000 8.500000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 65.000000 24.000000 0.000000 0.000000 0.000000 2.000000 5.000000 0.000000 4.000000 3.000000 1.000000 0.000000 0.000000 5.000000 0.000000 0.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.500000 44.000000 20.000000 1.000000 1.000000 3.000000 1.000000 0.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 35.000000 7.200000 0.000000 0.000000 1.000000 +2.000000 1.000000 39.000000 86.000000 16.000000 3.000000 3.000000 5.000000 0.000000 3.000000 3.000000 3.000000 0.000000 2.000000 0.000000 0.000000 0.000000 68.000000 5.800000 3.000000 6.000000 0.000000 +1.000000 1.000000 38.500000 129.000000 48.000000 3.000000 3.000000 3.000000 1.000000 2.000000 4.000000 3.000000 1.000000 3.000000 2.000000 0.000000 0.000000 57.000000 66.000000 3.000000 2.000000 1.000000 +1.000000 1.000000 0.000000 104.000000 0.000000 3.000000 3.000000 5.000000 2.000000 2.000000 4.000000 3.000000 0.000000 3.000000 0.000000 4.000000 4.000000 69.000000 8.600000 2.000000 3.400000 0.000000 +2.000000 1.000000 0.000000 0.000000 0.000000 3.000000 4.000000 6.000000 0.000000 4.000000 0.000000 4.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 +1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.200000 60.000000 30.000000 1.000000 1.000000 3.000000 1.000000 3.000000 3.000000 1.000000 2.000000 1.000000 0.000000 3.000000 2.000000 48.000000 66.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 68.000000 14.000000 0.000000 0.000000 4.000000 1.000000 4.000000 0.000000 0.000000 0.000000 1.000000 4.300000 0.000000 0.000000 0.000000 0.000000 2.000000 2.800000 0.000000 +1.000000 1.000000 0.000000 60.000000 30.000000 3.000000 3.000000 4.000000 2.000000 5.000000 4.000000 4.000000 1.000000 1.000000 0.000000 4.000000 0.000000 45.000000 70.000000 3.000000 2.000000 1.000000 +2.000000 1.000000 38.500000 100.000000 0.000000 3.000000 3.000000 5.000000 2.000000 4.000000 3.000000 4.000000 2.000000 1.000000 0.000000 4.000000 5.000000 0.000000 0.000000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.400000 84.000000 30.000000 3.000000 1.000000 5.000000 2.000000 4.000000 3.000000 3.000000 2.000000 3.000000 6.500000 4.000000 4.000000 47.000000 7.500000 3.000000 0.000000 0.000000 +2.000000 1.000000 37.800000 48.000000 14.000000 0.000000 0.000000 1.000000 1.000000 3.000000 0.000000 2.000000 1.000000 3.000000 5.300000 1.000000 0.000000 35.000000 7.500000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.000000 0.000000 24.000000 3.000000 3.000000 6.000000 2.000000 5.000000 0.000000 4.000000 1.000000 1.000000 0.000000 0.000000 0.000000 68.000000 7.800000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.800000 56.000000 16.000000 1.000000 1.000000 2.000000 1.000000 2.000000 1.000000 1.000000 2.000000 1.000000 0.000000 1.000000 0.000000 44.000000 68.000000 1.000000 1.000000 1.000000 +2.000000 1.000000 38.200000 68.000000 32.000000 2.000000 2.000000 2.000000 1.000000 1.000000 1.000000 1.000000 3.000000 1.000000 0.000000 1.000000 1.000000 43.000000 65.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.500000 120.000000 60.000000 4.000000 3.000000 6.000000 2.000000 0.000000 3.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 54.000000 0.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 39.300000 64.000000 90.000000 2.000000 3.000000 1.000000 1.000000 0.000000 3.000000 1.000000 1.000000 2.000000 0.000000 0.000000 0.000000 39.000000 6.700000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.400000 80.000000 30.000000 4.000000 3.000000 1.000000 1.000000 3.000000 3.000000 3.000000 3.000000 3.000000 0.000000 4.000000 5.000000 32.000000 6.100000 3.000000 4.300000 1.000000 +1.000000 1.000000 38.500000 60.000000 0.000000 1.000000 1.000000 0.000000 1.000000 0.000000 1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 33.000000 53.000000 1.000000 0.000000 1.000000 +1.000000 1.000000 38.300000 60.000000 16.000000 3.000000 1.000000 1.000000 1.000000 2.000000 1.000000 1.000000 2.000000 2.000000 3.000000 1.000000 4.000000 30.000000 6.000000 1.000000 3.000000 1.000000 +1.000000 1.000000 37.100000 40.000000 8.000000 0.000000 1.000000 4.000000 1.000000 3.000000 3.000000 1.000000 1.000000 1.000000 0.000000 3.000000 3.000000 23.000000 6.700000 3.000000 0.000000 1.000000 +2.000000 9.000000 0.000000 100.000000 44.000000 2.000000 1.000000 1.000000 1.000000 4.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 0.000000 37.000000 4.700000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.200000 48.000000 18.000000 1.000000 1.000000 1.000000 1.000000 3.000000 3.000000 3.000000 1.000000 2.000000 0.000000 4.000000 0.000000 48.000000 74.000000 1.000000 2.000000 1.000000 +1.000000 1.000000 0.000000 60.000000 48.000000 3.000000 3.000000 4.000000 2.000000 4.000000 3.000000 4.000000 0.000000 0.000000 0.000000 0.000000 0.000000 58.000000 7.600000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.900000 88.000000 24.000000 1.000000 1.000000 2.000000 1.000000 2.000000 2.000000 1.000000 0.000000 0.000000 0.000000 4.000000 1.000000 37.000000 56.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.000000 44.000000 12.000000 3.000000 1.000000 1.000000 0.000000 0.000000 1.000000 2.000000 0.000000 0.000000 0.000000 1.000000 0.000000 42.000000 64.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.500000 60.000000 20.000000 1.000000 1.000000 5.000000 2.000000 2.000000 2.000000 1.000000 2.000000 1.000000 0.000000 2.000000 3.000000 63.000000 7.500000 2.000000 2.300000 0.000000 +2.000000 1.000000 38.500000 96.000000 36.000000 3.000000 3.000000 0.000000 2.000000 2.000000 4.000000 2.000000 1.000000 2.000000 0.000000 4.000000 5.000000 70.000000 8.500000 0.000000 0.000000 0.000000 +2.000000 1.000000 38.300000 60.000000 20.000000 1.000000 1.000000 1.000000 2.000000 1.000000 3.000000 1.000000 0.000000 0.000000 0.000000 3.000000 0.000000 34.000000 66.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.500000 60.000000 40.000000 3.000000 1.000000 2.000000 1.000000 2.000000 1.000000 2.000000 0.000000 0.000000 0.000000 3.000000 2.000000 49.000000 59.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 37.300000 48.000000 12.000000 1.000000 0.000000 3.000000 1.000000 3.000000 1.000000 3.000000 2.000000 1.000000 0.000000 3.000000 3.000000 40.000000 6.600000 2.000000 0.000000 1.000000 +1.000000 1.000000 38.500000 86.000000 0.000000 1.000000 1.000000 3.000000 1.000000 4.000000 4.000000 3.000000 2.000000 1.000000 0.000000 3.000000 5.000000 45.000000 7.400000 1.000000 3.400000 0.000000 +1.000000 1.000000 37.500000 48.000000 40.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 1.000000 0.000000 0.000000 5.000000 41.000000 55.000000 3.000000 2.000000 0.000000 +2.000000 1.000000 37.200000 36.000000 9.000000 1.000000 1.000000 1.000000 1.000000 2.000000 3.000000 1.000000 2.000000 1.000000 0.000000 4.000000 1.000000 35.000000 5.700000 0.000000 0.000000 1.000000 +1.000000 1.000000 39.200000 0.000000 23.000000 3.000000 1.000000 3.000000 1.000000 4.000000 4.000000 2.000000 2.000000 0.000000 0.000000 0.000000 0.000000 36.000000 6.600000 1.000000 3.000000 1.000000 +2.000000 1.000000 38.500000 100.000000 0.000000 3.000000 3.000000 5.000000 2.000000 4.000000 3.000000 4.000000 2.000000 1.000000 0.000000 4.000000 5.000000 0.000000 0.000000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.500000 96.000000 30.000000 2.000000 3.000000 4.000000 2.000000 4.000000 4.000000 3.000000 2.000000 1.000000 0.000000 3.000000 5.000000 50.000000 65.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 45.000000 8.700000 0.000000 0.000000 0.000000 +1.000000 1.000000 37.800000 88.000000 80.000000 3.000000 3.000000 5.000000 2.000000 0.000000 3.000000 3.000000 2.000000 3.000000 0.000000 4.000000 5.000000 64.000000 89.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.500000 44.000000 10.000000 3.000000 1.000000 1.000000 1.000000 3.000000 1.000000 2.000000 2.000000 0.000000 0.000000 3.000000 3.000000 43.000000 51.000000 1.000000 1.000000 1.000000 +1.000000 1.000000 37.900000 68.000000 20.000000 0.000000 1.000000 2.000000 1.000000 2.000000 4.000000 2.000000 0.000000 0.000000 0.000000 1.000000 5.000000 45.000000 4.000000 3.000000 2.800000 0.000000 +1.000000 1.000000 38.000000 86.000000 24.000000 4.000000 3.000000 4.000000 1.000000 2.000000 4.000000 4.000000 1.000000 1.000000 0.000000 4.000000 5.000000 45.000000 5.500000 1.000000 10.100000 0.000000 +1.000000 9.000000 38.900000 120.000000 30.000000 1.000000 3.000000 2.000000 2.000000 3.000000 3.000000 3.000000 3.000000 1.000000 3.000000 0.000000 0.000000 47.000000 6.300000 1.000000 0.000000 1.000000 +1.000000 1.000000 37.600000 45.000000 12.000000 3.000000 1.000000 3.000000 1.000000 0.000000 2.000000 2.000000 2.000000 1.000000 0.000000 1.000000 4.000000 39.000000 7.000000 2.000000 1.500000 1.000000 +2.000000 1.000000 38.600000 56.000000 32.000000 2.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 2.000000 0.000000 0.000000 2.000000 0.000000 40.000000 7.000000 2.000000 2.100000 1.000000 +1.000000 1.000000 37.800000 40.000000 12.000000 1.000000 1.000000 1.000000 1.000000 1.000000 2.000000 1.000000 2.000000 1.000000 0.000000 1.000000 2.000000 38.000000 7.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.000000 76.000000 18.000000 0.000000 0.000000 0.000000 2.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 71.000000 11.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.100000 40.000000 36.000000 1.000000 2.000000 2.000000 1.000000 2.000000 2.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 +1.000000 1.000000 0.000000 52.000000 28.000000 3.000000 3.000000 4.000000 1.000000 3.000000 4.000000 3.000000 2.000000 1.000000 0.000000 4.000000 4.000000 37.000000 8.100000 0.000000 0.000000 1.000000 +1.000000 1.000000 39.200000 88.000000 58.000000 4.000000 4.000000 0.000000 2.000000 5.000000 4.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 2.000000 2.000000 0.000000 +1.000000 1.000000 38.500000 92.000000 40.000000 4.000000 3.000000 0.000000 1.000000 2.000000 4.000000 3.000000 0.000000 0.000000 0.000000 4.000000 0.000000 46.000000 67.000000 2.000000 2.000000 1.000000 +1.000000 1.000000 0.000000 112.000000 13.000000 4.000000 4.000000 4.000000 1.000000 2.000000 3.000000 1.000000 2.000000 1.000000 4.500000 4.000000 4.000000 60.000000 6.300000 3.000000 0.000000 1.000000 +1.000000 1.000000 37.700000 66.000000 12.000000 1.000000 1.000000 3.000000 1.000000 3.000000 3.000000 2.000000 2.000000 0.000000 0.000000 4.000000 4.000000 31.500000 6.200000 2.000000 1.600000 1.000000 +1.000000 1.000000 38.800000 50.000000 14.000000 1.000000 1.000000 1.000000 1.000000 3.000000 1.000000 1.000000 1.000000 1.000000 0.000000 3.000000 5.000000 38.000000 58.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.400000 54.000000 24.000000 1.000000 1.000000 1.000000 1.000000 1.000000 3.000000 1.000000 2.000000 1.000000 0.000000 3.000000 2.000000 49.000000 7.200000 1.000000 8.000000 1.000000 +1.000000 1.000000 39.200000 120.000000 20.000000 4.000000 3.000000 5.000000 2.000000 2.000000 3.000000 3.000000 1.000000 3.000000 0.000000 0.000000 4.000000 60.000000 8.800000 3.000000 0.000000 0.000000 +1.000000 9.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 45.000000 6.500000 2.000000 0.000000 1.000000 +1.000000 1.000000 37.300000 90.000000 40.000000 3.000000 0.000000 6.000000 2.000000 5.000000 4.000000 3.000000 2.000000 2.000000 0.000000 1.000000 5.000000 65.000000 50.000000 3.000000 2.000000 0.000000 +1.000000 9.000000 38.500000 120.000000 70.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 2.000000 0.000000 0.000000 1.000000 0.000000 35.000000 54.000000 1.000000 1.000000 1.000000 +1.000000 1.000000 38.500000 104.000000 40.000000 3.000000 3.000000 0.000000 1.000000 4.000000 3.000000 4.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 39.500000 92.000000 28.000000 3.000000 3.000000 6.000000 1.000000 5.000000 4.000000 1.000000 0.000000 3.000000 0.000000 4.000000 0.000000 72.000000 6.400000 0.000000 3.600000 0.000000 +1.000000 1.000000 38.500000 30.000000 18.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 40.000000 7.700000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.300000 72.000000 30.000000 4.000000 3.000000 3.000000 2.000000 3.000000 3.000000 3.000000 2.000000 1.000000 0.000000 3.000000 5.000000 43.000000 7.000000 2.000000 3.900000 1.000000 +2.000000 1.000000 37.500000 48.000000 30.000000 4.000000 1.000000 3.000000 1.000000 0.000000 2.000000 1.000000 1.000000 1.000000 0.000000 1.000000 1.000000 48.000000 8.600000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.100000 52.000000 24.000000 1.000000 1.000000 5.000000 1.000000 4.000000 3.000000 1.000000 2.000000 3.000000 7.000000 1.000000 0.000000 54.000000 7.500000 2.000000 2.600000 0.000000 +2.000000 1.000000 38.200000 42.000000 26.000000 1.000000 1.000000 1.000000 1.000000 3.000000 1.000000 2.000000 0.000000 0.000000 0.000000 1.000000 0.000000 36.000000 6.900000 0.000000 0.000000 1.000000 +2.000000 1.000000 37.900000 54.000000 42.000000 2.000000 1.000000 5.000000 1.000000 3.000000 1.000000 1.000000 0.000000 1.000000 0.000000 0.000000 2.000000 47.000000 54.000000 3.000000 1.000000 1.000000 +2.000000 1.000000 36.100000 88.000000 0.000000 3.000000 3.000000 3.000000 1.000000 3.000000 3.000000 2.000000 2.000000 3.000000 0.000000 0.000000 4.000000 45.000000 7.000000 3.000000 4.800000 0.000000 +1.000000 1.000000 38.100000 70.000000 22.000000 0.000000 1.000000 0.000000 1.000000 5.000000 3.000000 0.000000 0.000000 0.000000 0.000000 0.000000 5.000000 36.000000 65.000000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.000000 90.000000 30.000000 4.000000 3.000000 4.000000 2.000000 5.000000 4.000000 4.000000 0.000000 0.000000 0.000000 4.000000 5.000000 55.000000 6.100000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.200000 52.000000 16.000000 1.000000 1.000000 2.000000 1.000000 1.000000 2.000000 1.000000 1.000000 1.000000 0.000000 1.000000 0.000000 43.000000 8.100000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 36.000000 32.000000 1.000000 1.000000 4.000000 1.000000 5.000000 3.000000 3.000000 2.000000 3.000000 4.000000 0.000000 4.000000 41.000000 5.900000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.400000 92.000000 20.000000 1.000000 0.000000 0.000000 2.000000 0.000000 3.000000 3.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 +1.000000 9.000000 38.200000 124.000000 88.000000 1.000000 3.000000 2.000000 1.000000 2.000000 3.000000 4.000000 0.000000 0.000000 0.000000 0.000000 0.000000 47.000000 8.000000 1.000000 0.000000 1.000000 +2.000000 1.000000 0.000000 96.000000 0.000000 3.000000 3.000000 3.000000 2.000000 5.000000 4.000000 4.000000 0.000000 1.000000 0.000000 4.000000 5.000000 60.000000 0.000000 0.000000 0.000000 0.000000 +1.000000 1.000000 37.600000 68.000000 32.000000 3.000000 0.000000 3.000000 1.000000 4.000000 2.000000 4.000000 2.000000 2.000000 6.500000 1.000000 5.000000 47.000000 7.200000 1.000000 0.000000 1.000000 +1.000000 1.000000 38.100000 88.000000 24.000000 3.000000 3.000000 4.000000 1.000000 5.000000 4.000000 3.000000 2.000000 1.000000 0.000000 3.000000 4.000000 41.000000 4.600000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.000000 108.000000 60.000000 2.000000 3.000000 4.000000 1.000000 4.000000 3.000000 3.000000 2.000000 0.000000 0.000000 3.000000 4.000000 0.000000 0.000000 3.000000 0.000000 1.000000 +2.000000 1.000000 38.200000 48.000000 0.000000 2.000000 0.000000 1.000000 2.000000 3.000000 3.000000 1.000000 2.000000 1.000000 0.000000 0.000000 2.000000 34.000000 6.600000 0.000000 0.000000 1.000000 +1.000000 1.000000 39.300000 100.000000 51.000000 4.000000 4.000000 6.000000 1.000000 2.000000 4.000000 1.000000 1.000000 3.000000 2.000000 0.000000 4.000000 66.000000 13.000000 3.000000 2.000000 0.000000 +2.000000 1.000000 36.600000 42.000000 18.000000 3.000000 3.000000 2.000000 1.000000 1.000000 4.000000 1.000000 1.000000 1.000000 0.000000 0.000000 5.000000 52.000000 7.100000 0.000000 0.000000 0.000000 +1.000000 9.000000 38.800000 124.000000 36.000000 3.000000 1.000000 2.000000 1.000000 2.000000 3.000000 4.000000 1.000000 1.000000 0.000000 4.000000 4.000000 50.000000 7.600000 3.000000 0.000000 0.000000 +2.000000 1.000000 0.000000 112.000000 24.000000 3.000000 3.000000 4.000000 2.000000 5.000000 4.000000 2.000000 0.000000 0.000000 0.000000 4.000000 0.000000 40.000000 5.300000 3.000000 2.600000 1.000000 +1.000000 1.000000 0.000000 80.000000 0.000000 3.000000 3.000000 3.000000 1.000000 4.000000 4.000000 4.000000 0.000000 0.000000 0.000000 4.000000 5.000000 43.000000 70.000000 0.000000 0.000000 1.000000 +1.000000 9.000000 38.800000 184.000000 84.000000 1.000000 0.000000 1.000000 1.000000 4.000000 1.000000 3.000000 0.000000 0.000000 0.000000 2.000000 0.000000 33.000000 3.300000 0.000000 0.000000 0.000000 +1.000000 1.000000 37.500000 72.000000 0.000000 2.000000 1.000000 1.000000 1.000000 2.000000 1.000000 1.000000 1.000000 1.000000 0.000000 1.000000 0.000000 35.000000 65.000000 2.000000 2.000000 0.000000 +1.000000 1.000000 38.700000 96.000000 28.000000 3.000000 3.000000 4.000000 1.000000 0.000000 4.000000 0.000000 0.000000 3.000000 7.500000 0.000000 0.000000 64.000000 9.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.500000 52.000000 12.000000 1.000000 1.000000 1.000000 1.000000 2.000000 3.000000 2.000000 2.000000 1.000000 0.000000 3.000000 5.000000 36.000000 61.000000 1.000000 1.000000 1.000000 +1.000000 1.000000 40.800000 72.000000 42.000000 3.000000 3.000000 1.000000 1.000000 2.000000 3.000000 1.000000 2.000000 1.000000 0.000000 0.000000 0.000000 54.000000 7.400000 3.000000 0.000000 0.000000 +2.000000 1.000000 38.000000 40.000000 25.000000 0.000000 1.000000 1.000000 1.000000 4.000000 3.000000 2.000000 1.000000 1.000000 0.000000 4.000000 0.000000 37.000000 69.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.400000 48.000000 16.000000 2.000000 1.000000 1.000000 1.000000 1.000000 0.000000 2.000000 2.000000 1.000000 0.000000 0.000000 2.000000 39.000000 6.500000 0.000000 0.000000 1.000000 +2.000000 9.000000 38.600000 88.000000 28.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 35.000000 5.900000 0.000000 0.000000 1.000000 +1.000000 1.000000 37.100000 75.000000 36.000000 0.000000 0.000000 3.000000 2.000000 4.000000 4.000000 2.000000 2.000000 3.000000 5.000000 4.000000 4.000000 48.000000 7.400000 3.000000 3.200000 0.000000 +1.000000 1.000000 38.300000 44.000000 21.000000 3.000000 1.000000 2.000000 1.000000 3.000000 3.000000 3.000000 2.000000 1.000000 0.000000 1.000000 5.000000 44.000000 6.500000 2.000000 4.400000 1.000000 +2.000000 1.000000 0.000000 56.000000 68.000000 3.000000 1.000000 1.000000 1.000000 3.000000 3.000000 1.000000 2.000000 1.000000 0.000000 1.000000 0.000000 40.000000 6.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 38.600000 68.000000 20.000000 2.000000 1.000000 3.000000 1.000000 3.000000 3.000000 2.000000 1.000000 1.000000 0.000000 1.000000 5.000000 38.000000 6.500000 1.000000 0.000000 1.000000 +2.000000 1.000000 38.300000 54.000000 18.000000 3.000000 1.000000 2.000000 1.000000 2.000000 3.000000 2.000000 0.000000 3.000000 5.400000 0.000000 4.000000 44.000000 7.200000 3.000000 0.000000 1.000000 +1.000000 1.000000 38.200000 42.000000 20.000000 0.000000 0.000000 1.000000 1.000000 0.000000 3.000000 0.000000 0.000000 0.000000 0.000000 3.000000 0.000000 47.000000 60.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 39.300000 64.000000 90.000000 2.000000 3.000000 1.000000 1.000000 0.000000 3.000000 1.000000 1.000000 2.000000 6.500000 1.000000 5.000000 39.000000 6.700000 0.000000 0.000000 1.000000 +1.000000 1.000000 37.500000 60.000000 50.000000 3.000000 3.000000 1.000000 1.000000 3.000000 3.000000 2.000000 2.000000 2.000000 3.500000 3.000000 4.000000 35.000000 6.500000 0.000000 0.000000 0.000000 +1.000000 1.000000 37.700000 80.000000 0.000000 3.000000 3.000000 6.000000 1.000000 5.000000 4.000000 1.000000 2.000000 3.000000 0.000000 3.000000 1.000000 50.000000 55.000000 3.000000 2.000000 1.000000 +1.000000 1.000000 0.000000 100.000000 30.000000 3.000000 3.000000 4.000000 2.000000 5.000000 4.000000 4.000000 3.000000 3.000000 0.000000 4.000000 4.000000 52.000000 6.600000 0.000000 0.000000 1.000000 +1.000000 1.000000 37.700000 120.000000 28.000000 3.000000 3.000000 3.000000 1.000000 5.000000 3.000000 3.000000 1.000000 1.000000 0.000000 0.000000 0.000000 65.000000 7.000000 3.000000 0.000000 0.000000 +1.000000 1.000000 0.000000 76.000000 0.000000 0.000000 3.000000 0.000000 0.000000 0.000000 4.000000 4.000000 0.000000 0.000000 0.000000 0.000000 5.000000 0.000000 0.000000 0.000000 0.000000 0.000000 +1.000000 9.000000 38.800000 150.000000 50.000000 1.000000 3.000000 6.000000 2.000000 5.000000 3.000000 2.000000 1.000000 1.000000 0.000000 0.000000 0.000000 50.000000 6.200000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.000000 36.000000 16.000000 3.000000 1.000000 1.000000 1.000000 4.000000 2.000000 2.000000 3.000000 3.000000 2.000000 3.000000 0.000000 37.000000 75.000000 2.000000 1.000000 0.000000 +2.000000 1.000000 36.900000 50.000000 40.000000 2.000000 3.000000 3.000000 1.000000 1.000000 3.000000 2.000000 3.000000 1.000000 7.000000 0.000000 0.000000 37.500000 6.500000 0.000000 0.000000 1.000000 +2.000000 1.000000 37.800000 40.000000 16.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 1.000000 1.000000 37.000000 6.800000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.200000 56.000000 40.000000 4.000000 3.000000 1.000000 1.000000 2.000000 4.000000 3.000000 2.000000 2.000000 7.500000 0.000000 0.000000 47.000000 7.200000 1.000000 2.500000 1.000000 +1.000000 1.000000 38.600000 48.000000 12.000000 0.000000 0.000000 1.000000 0.000000 1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 36.000000 67.000000 0.000000 0.000000 1.000000 +2.000000 1.000000 40.000000 78.000000 0.000000 3.000000 3.000000 5.000000 1.000000 2.000000 3.000000 1.000000 1.000000 1.000000 0.000000 4.000000 1.000000 66.000000 6.500000 0.000000 0.000000 0.000000 +1.000000 1.000000 0.000000 70.000000 16.000000 3.000000 4.000000 5.000000 2.000000 2.000000 3.000000 2.000000 2.000000 1.000000 0.000000 4.000000 5.000000 60.000000 7.500000 0.000000 0.000000 0.000000 +1.000000 1.000000 38.200000 72.000000 18.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 35.000000 6.400000 0.000000 0.000000 1.000000 +2.000000 1.000000 38.500000 54.000000 0.000000 1.000000 1.000000 1.000000 1.000000 3.000000 1.000000 1.000000 2.000000 1.000000 0.000000 1.000000 0.000000 40.000000 6.800000 2.000000 7.000000 1.000000 +1.000000 1.000000 38.500000 66.000000 24.000000 1.000000 1.000000 1.000000 1.000000 3.000000 3.000000 1.000000 2.000000 1.000000 0.000000 4.000000 5.000000 40.000000 6.700000 1.000000 0.000000 1.000000 +2.000000 1.000000 37.800000 82.000000 12.000000 3.000000 1.000000 1.000000 2.000000 4.000000 0.000000 3.000000 1.000000 3.000000 0.000000 0.000000 0.000000 50.000000 7.000000 0.000000 0.000000 0.000000 +2.000000 9.000000 39.500000 84.000000 30.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 28.000000 5.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.000000 50.000000 36.000000 0.000000 1.000000 1.000000 1.000000 3.000000 2.000000 2.000000 0.000000 0.000000 0.000000 3.000000 0.000000 39.000000 6.600000 1.000000 5.300000 1.000000 +2.000000 1.000000 38.600000 45.000000 16.000000 2.000000 1.000000 2.000000 1.000000 1.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 1.000000 43.000000 58.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 38.900000 80.000000 44.000000 3.000000 3.000000 3.000000 1.000000 2.000000 3.000000 3.000000 2.000000 2.000000 7.000000 3.000000 1.000000 54.000000 6.500000 3.000000 0.000000 0.000000 +1.000000 1.000000 37.000000 66.000000 20.000000 1.000000 3.000000 2.000000 1.000000 4.000000 3.000000 3.000000 1.000000 0.000000 0.000000 1.000000 5.000000 35.000000 6.900000 2.000000 0.000000 0.000000 +1.000000 1.000000 0.000000 78.000000 24.000000 3.000000 3.000000 3.000000 1.000000 0.000000 3.000000 0.000000 2.000000 1.000000 0.000000 0.000000 4.000000 43.000000 62.000000 0.000000 2.000000 0.000000 +2.000000 1.000000 38.500000 40.000000 16.000000 1.000000 1.000000 1.000000 1.000000 2.000000 1.000000 1.000000 0.000000 0.000000 0.000000 3.000000 2.000000 37.000000 67.000000 0.000000 0.000000 1.000000 +1.000000 1.000000 0.000000 120.000000 70.000000 4.000000 0.000000 4.000000 2.000000 2.000000 4.000000 0.000000 0.000000 0.000000 0.000000 0.000000 5.000000 55.000000 65.000000 0.000000 0.000000 0.000000 +2.000000 1.000000 37.200000 72.000000 24.000000 3.000000 2.000000 4.000000 2.000000 4.000000 3.000000 3.000000 3.000000 1.000000 0.000000 4.000000 4.000000 44.000000 0.000000 3.000000 3.300000 0.000000 +1.000000 1.000000 37.500000 72.000000 30.000000 4.000000 3.000000 4.000000 1.000000 4.000000 4.000000 3.000000 2.000000 1.000000 0.000000 3.000000 5.000000 60.000000 6.800000 0.000000 0.000000 0.000000 +1.000000 1.000000 36.500000 100.000000 24.000000 3.000000 3.000000 3.000000 1.000000 3.000000 3.000000 3.000000 3.000000 1.000000 0.000000 4.000000 4.000000 50.000000 6.000000 3.000000 3.400000 1.000000 +1.000000 1.000000 37.200000 40.000000 20.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 4.000000 1.000000 36.000000 62.000000 1.000000 1.000000 0.000000 \ No newline at end of file diff --git a/logistic/log_regres.py b/logistic/log_regres.py new file mode 100755 index 0000000..20a7294 --- /dev/null +++ b/logistic/log_regres.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python3 +# -*- coding:UTF-8 -*- +import matplotlib.pyplot as plt +import numpy as np + +""" +函数说明:梯度上升算法测试函数 + +求函数f(x) = -x^2 + 4x的极大值 + +Parameters: + 无 +Returns: + 无 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-28 +""" +def Gradient_Ascent_test(): + def f_prime(x_old): #f(x)的导数 + return -2 * x_old + 4 + x_old = -1 #初始值,给一个小于x_new的值 + x_new = 0 #梯度上升算法初始值,即从(0,0)开始 + alpha = 0.01 #步长,也就是学习速率,控制更新的幅度 + presision = 0.00000001 #精度,也就是更新阈值 + while abs(x_new - x_old) > presision: + x_old = x_new + x_new = x_old + alpha * f_prime(x_old) #上面提到的公式 + print(x_new) #打印最终求解的极值近似值 + +""" +函数说明:加载数据 + +Parameters: + 无 +Returns: + dataMat - 数据列表 + labelMat - 标签列表 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-28 +""" +def loadDataSet(): + dataMat = [] #创建数据列表 + labelMat = [] #创建标签列表 + fr = open('testSet.txt') #打开文件 + for line in fr.readlines(): #逐行读取 + lineArr = line.strip().split() #去回车,放入列表 + dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) #添加数据 + labelMat.append(int(lineArr[2])) #添加标签 + fr.close() #关闭文件 + return dataMat, labelMat #返回 + +""" +函数说明:sigmoid函数 + +Parameters: + inX - 数据 +Returns: + sigmoid函数 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-28 +""" +def sigmoid(inX): + return 1.0 / (1 + np.exp(-inX)) + +""" +函数说明:梯度上升算法 + +Parameters: + dataMatIn - 数据集 + classLabels - 数据标签 +Returns: + weights.getA() - 求得的权重数组(最优参数) +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-28 +""" +def gradAscent(dataMatIn, classLabels): + dataMatrix = np.mat(dataMatIn) #转换成numpy的mat + labelMat = np.mat(classLabels).transpose() #转换成numpy的mat,并进行转置 + m, n = np.shape(dataMatrix) #返回dataMatrix的大小。m为行数,n为列数。 + alpha = 0.001 #移动步长,也就是学习速率,控制更新的幅度。 + maxCycles = 500 #最大迭代次数 + weights = np.ones((n,1)) + for k in range(maxCycles): + h = sigmoid(dataMatrix * weights) #梯度上升矢量化公式 + error = labelMat - h + weights = weights + alpha * dataMatrix.transpose() * error + return weights.getA() #将矩阵转换为数组,返回权重数组 + +""" +函数说明:绘制数据集 + +Parameters: + 无 +Returns: + 无 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-30 +""" +def plotDataSet(): + dataMat, labelMat = loadDataSet() #加载数据集 + dataArr = np.array(dataMat) #转换成numpy的array数组 + n = np.shape(dataMat)[0] #数据个数 + xcord1 = []; ycord1 = [] #正样本 + xcord2 = []; ycord2 = [] #负样本 + for i in range(n): #根据数据集标签进行分类 + if int(labelMat[i]) == 1: + xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2]) #1为正样本 + else: + xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2]) #0为负样本 + fig = plt.figure() + ax = fig.add_subplot(111) #添加subplot + ax.scatter(xcord1, ycord1, s = 20, c = 'red', marker = 's',alpha=.5)#绘制正样本 + ax.scatter(xcord2, ycord2, s = 20, c = 'green',alpha=.5) #绘制负样本 + plt.title('DataSet') #绘制title + plt.xlabel('X1'); plt.ylabel('X2') #绘制label + plt.show() #显示 + +""" +函数说明:绘制数据集 + +Parameters: + weights - 权重参数数组 +Returns: + 无 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-08-30 +""" +def plotBestFit(weights): + dataMat, labelMat = loadDataSet() #加载数据集 + dataArr = np.array(dataMat) #转换成numpy的array数组 + n = np.shape(dataMat)[0] #数据个数 + xcord1 = []; ycord1 = [] #正样本 + xcord2 = []; ycord2 = [] #负样本 + for i in range(n): #根据数据集标签进行分类 + if int(labelMat[i]) == 1: + xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2]) #1为正样本 + else: + xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2]) #0为负样本 + fig = plt.figure() + ax = fig.add_subplot(111) #添加subplot + ax.scatter(xcord1, ycord1, s = 20, c = 'red', marker = 's',alpha=.5)#绘制正样本 + ax.scatter(xcord2, ycord2, s = 20, c = 'green',alpha=.5) #绘制负样本 + x = np.arange(-3.0, 3.0, 0.1) + y = (-weights[0] - weights[1] * x) / weights[2] + ax.plot(x, y) + plt.title('BestFit') #绘制title + plt.xlabel('X1'); plt.ylabel('X2') #绘制label + plt.show() + +if __name__ == '__main__': + dataMat, labelMat = loadDataSet() + weights = gradAscent(dataMat, labelMat) + plotBestFit(weights) diff --git a/logistic/testSet.txt b/logistic/testSet.txt new file mode 100644 index 0000000..f2f9024 --- /dev/null +++ b/logistic/testSet.txt @@ -0,0 +1,100 @@ +-0.017612 14.053064 0 +-1.395634 4.662541 1 +-0.752157 6.538620 0 +-1.322371 7.152853 0 +0.423363 11.054677 0 +0.406704 7.067335 1 +0.667394 12.741452 0 +-2.460150 6.866805 1 +0.569411 9.548755 0 +-0.026632 10.427743 0 +0.850433 6.920334 1 +1.347183 13.175500 0 +1.176813 3.167020 1 +-1.781871 9.097953 0 +-0.566606 5.749003 1 +0.931635 1.589505 1 +-0.024205 6.151823 1 +-0.036453 2.690988 1 +-0.196949 0.444165 1 +1.014459 5.754399 1 +1.985298 3.230619 1 +-1.693453 -0.557540 1 +-0.576525 11.778922 0 +-0.346811 -1.678730 1 +-2.124484 2.672471 1 +1.217916 9.597015 0 +-0.733928 9.098687 0 +-3.642001 -1.618087 1 +0.315985 3.523953 1 +1.416614 9.619232 0 +-0.386323 3.989286 1 +0.556921 8.294984 1 +1.224863 11.587360 0 +-1.347803 -2.406051 1 +1.196604 4.951851 1 +0.275221 9.543647 0 +0.470575 9.332488 0 +-1.889567 9.542662 0 +-1.527893 12.150579 0 +-1.185247 11.309318 0 +-0.445678 3.297303 1 +1.042222 6.105155 1 +-0.618787 10.320986 0 +1.152083 0.548467 1 +0.828534 2.676045 1 +-1.237728 10.549033 0 +-0.683565 -2.166125 1 +0.229456 5.921938 1 +-0.959885 11.555336 0 +0.492911 10.993324 0 +0.184992 8.721488 0 +-0.355715 10.325976 0 +-0.397822 8.058397 0 +0.824839 13.730343 0 +1.507278 5.027866 1 +0.099671 6.835839 1 +-0.344008 10.717485 0 +1.785928 7.718645 1 +-0.918801 11.560217 0 +-0.364009 4.747300 1 +-0.841722 4.119083 1 +0.490426 1.960539 1 +-0.007194 9.075792 0 +0.356107 12.447863 0 +0.342578 12.281162 0 +-0.810823 -1.466018 1 +2.530777 6.476801 1 +1.296683 11.607559 0 +0.475487 12.040035 0 +-0.783277 11.009725 0 +0.074798 11.023650 0 +-1.337472 0.468339 1 +-0.102781 13.763651 0 +-0.147324 2.874846 1 +0.518389 9.887035 0 +1.015399 7.571882 0 +-1.658086 -0.027255 1 +1.319944 2.171228 1 +2.056216 5.019981 1 +-0.851633 4.375691 1 +-1.510047 6.061992 0 +-1.076637 -3.181888 1 +1.821096 10.283990 0 +3.010150 8.401766 1 +-1.099458 1.688274 1 +-0.834872 -1.733869 1 +-0.846637 3.849075 1 +1.400102 12.628781 0 +1.752842 5.468166 1 +0.078557 0.059736 1 +0.089392 -0.715300 1 +1.825662 12.693808 0 +0.197445 9.744638 0 +0.126117 0.922311 1 +-0.679797 1.220530 1 +0.677983 2.556666 1 +0.761349 10.693862 0 +-2.168791 0.143632 1 +1.388610 9.341997 0 +0.317029 14.739025 0 diff --git a/ml.xml b/ml.xml new file mode 100644 index 0000000..1cf3349 --- /dev/null +++ b/ml.xml @@ -0,0 +1,249 @@ + + + + http://www.zeekling.cn/book/ml/bayes/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/bayes/index.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/logistic/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/decisionTree/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/decisionTree/pics/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/decisionTree/index.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/basic/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/basic/deep_learn.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/basic/math_basis.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/basic/pic/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/basic/pic/index.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/basic/deep_basic.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/basic/evaluation.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/basic/index.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/svm/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/svm/index.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/knn/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/knn/index.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/nlp/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/nlp/index.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/regression/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/regression/lego/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/regression/lego/lego10196.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/regression/lego/lego8288.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/regression/lego/lego10189.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/regression/lego/lego10181.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/regression/lego/lego10030.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/regression/lego/lego10179.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/regression/线性模型.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/regression/index.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/rl/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/rl/index.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/targetDetection/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/targetDetection/index.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/nn/ + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/nn/rnn.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/nn/multi_task.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/nn/ResNet.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/nn/cnn.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/nn/index.html + weekly + 0.8 + 2019-06-17 + + + http://www.zeekling.cn/book/ml/index.html + weekly + 0.8 + 2019-06-17 + + diff --git a/nlp/README.md b/nlp/README.md new file mode 100644 index 0000000..0b207ff --- /dev/null +++ b/nlp/README.md @@ -0,0 +1 @@ +# 自然语言理解 diff --git a/nlp/word2vec.md b/nlp/word2vec.md new file mode 100644 index 0000000..c386a31 --- /dev/null +++ b/nlp/word2vec.md @@ -0,0 +1,2 @@ +# Word2vec + diff --git a/nn/README.md b/nn/README.md new file mode 100644 index 0000000..27ece64 --- /dev/null +++ b/nn/README.md @@ -0,0 +1,128 @@ +# 神经网络 +一直沿用至今的“M-P神经元模型”正是对这一结构进行了抽象,也称“阈值逻辑单元“,其中树突对应于输入部分,每个神经元收到n个其他 +神经元传递过来的输入信号,这些信号通过带权重的连接传递给细胞体,这些权重又称为连接权(connection weight)。细胞体分为两 +部分,前一部分计算总输入值(即输入信号的加权和,或者说累积电平),后一部分先计算总输入值与该神经元阈值的差值,然后通过 +激活函数(activation function)的处理,产生输出从轴突传送给其它神经元。M-P神经元模型如下图所示: + +![pic](http://index.zeekling.cn/gogsPics/ml/nn/1.png)
+ +与线性分类十分相似,神经元模型最理想的激活函数也是阶跃函数,即将神经元输入值与阈值的差值映射为输出值1或0,若差值大于零输 +出1,对应兴奋;若差值小于零则输出0,对应抑制。但阶跃函数不连续,不光滑,故在M-P神经元模型中,也采用Sigmoid函数来近似, +Sigmoid函数将较大范围内变化的输入值挤压到 (0,1) 输出值范围内,所以也称为挤压函数(squashing function)。 + +![pic](http://index.zeekling.cn/gogsPics/ml/nn/2.png)
+ +将多个神经元按一定的层次结构连接起来,就得到了神经网络。它是一种包含多个参数的模型,比方说10个神经元两两连接,则有100个 +参数需要学习(每个神经元有9个连接权以及1个阈值),若将每个神经元都看作一个函数,则整个神经网络就是由这些函数相互嵌套而成。 + +## 感知机与多层网络 +感知机(Perceptron)是由两层神经元组成的一个简单模型,但只有输出层是M-P神经元,即只有输出层神经元进行激活函数处理,也称 +为功能神经元(functional neuron);输入层只是接受外界信号(样本属性)并传递给输出层(输入层的神经元个数等于样本的属性数 +目),而没有激活函数。这样一来,感知机与之前线性模型中的对数几率回归的思想基本是一样的,都是通过对属性加权与另一个常数求 +和,再使用sigmoid函数将这个输出值压缩到0-1之间,从而解决分类问题。不同的是感知机的输出层应该可以有多个神经元,从而可以实 +现多分类问题,同时两个模型所用的参数估计方法十分不同。 + +给定训练集,则感知机的n+1个参数(n个权重+1个阈值)都可以通过学习得到。阈值Θ可以看作一个输入值固定为-1的哑结点的权重ωn+1, +即假设有一个固定输入xn+1=-1的输入层神经元,其对应的权重为ωn+1,这样就把权重和阈值统一为权重的学习了。简单感知机的结构如 +下图所示: + +![pic](http://index.zeekling.cn/gogsPics/ml/nn/3.png)
+ +感知机权重的学习规则如下:对于训练样本(x,y),当该样本进入感知机学习后,会产生一个输出值,若该输出值与样本的真实标记 +不一致,则感知机会对权重进行调整,若激活函数为阶跃函数,则调整的方法为(基于梯度下降法):(看不懂) + +![pic](http://index.zeekling.cn/gogsPics/ml/nn/4.png)
+ +其中 η∈(0,1)称为学习率,可以看出感知机是通过逐个样本输入来更新权重,首先设定好初始权重(一般为随机),逐个地输入样本 +数据,若输出值与真实标记相同则继续输入下一个样本,若不一致则更新权重,然后再重新逐个检验,直到每个样本数据的输出值都与真 +实标记相同。容易看出:感知机模型总是能将训练数据的每一个样本都预测正确,和决策树模型总是能将所有训练数据都分开一样,感 +知机模型很容易产生过拟合问题。 + +由于感知机模型只有一层功能神经元,因此其功能十分有限,只能处理线性可分的问题,对于这类问题,感知机的学习过程一定会收敛 +(converge),因此总是可以求出适当的权值。但是对于像书上提到的异或问题,只通过一层功能神经元往往不能解决,因此要解决非线 +性可分问题,需要考虑使用多层功能神经元,即神经网络。多层神经网络的拓扑结构如下图所示: + +![pic](http://index.zeekling.cn/gogsPics/ml/nn/4.png)
+ +在神经网络中,输入层与输出层之间的层称为隐含层或隐层(hidden layer),隐层和输出层的神经元都是具有激活函数的功能神经元。 +只需包含一个隐层便可以称为多层神经网络,常用的神经网络称为“多层前馈神经网络”(multi-layer feedforward neural network), +该结构满足以下几个特点: + +* 每层神经元与下一层神经元之间完全互连 +* 神经元之间不存在同层连接 +* 神经元之间不存在跨层连接 + +![pic](http://index.zeekling.cn/gogsPics/ml/nn/6.png)
+ +根据上面的特点可以得知:这里的“前馈”指的是网络拓扑结构中不存在环或回路,而不是指该网络只能向前传播而不能向后传播(下节中 +的BP神经网络正是基于前馈神经网络而增加了反馈调节机制)。神经网络的学习过程就是根据训练数据来调整神经元之间的“连接权”以及 +每个神经元的阈值,换句话说:神经网络所学习到的东西都蕴含在网络的连接权与阈值中。 + +## BP神经网络算法 + +一般而言,只需包含一个足够多神经元的隐层,就能以任意精度逼近任意复杂度的连续函数[Hornik et al.,1989],故下面以训练单隐 +层的前馈神经网络为例,介绍BP神经网络的算法思想。 + +![pic](http://index.zeekling.cn/gogsPics/ml/nn/7.png)
+ +上图为一个单隐层前馈神经网络的拓扑结构,BP神经网络算法也使用梯度下降法(gradient descent),以单个样本的均方误差的负梯度 +方向对权重进行调节。可以看出:BP算法首先将误差反向传播给隐层神经元,调节隐层到输出层的连接权重与输出层神经元的阈值;接着 +根据隐含层神经元的均方误差,来调节输入层到隐含层的连接权值与隐含层神经元的阈值。BP算法基本的推导过程与感知机的推导过程原 +理是相同的,下面给出调整隐含层到输出层的权重调整规则的推导过程: + +![pic](http://index.zeekling.cn/gogsPics/ml/nn/8.png)
+ +学习率η∈(0,1)控制着沿反梯度方向下降的步长,若步长太大则下降太快容易产生震荡,若步长太小则收敛速度太慢,一般地常把η设 +置为0.1,有时更新权重时会将输出层与隐含层设置为不同的学习率。BP算法的基本流程如下所示: + +![pic](http://index.zeekling.cn/gogsPics/ml/nn/9.png)
+ +BP算法的更新规则是基于每个样本的预测值与真实类标的均方误差来进行权值调节,即BP算法每次更新只针对于单个样例。需要注意的是 +:BP算法的最终目标是要最小化整个训练集D上的累积误差,即: + +![pic](http://index.zeekling.cn/gogsPics/ml/nn/10.png)
+ +如果基于累积误差最小化的更新规则,则得到了累积误差逆传播算法(accumulated error backpropagation),即每次读取全部的数据 +集一遍,进行一轮学习,从而基于当前的累积误差进行权值调整,因此参数更新的频率相比标准BP算法低了很多,但在很多任务中,尤其 +是在数据量很大的时候,往往标准BP算法会获得较好的结果。另外对于如何设置隐层神经元个数的问题,至今仍然没有好的解决方案, +常使用“试错法”进行调整。 + +- 早停:将数据分为训练集与测试集,训练集用于学习,测试集用于评估性能,若在训练过程中,训练集的累积误差降低,而测试集的 + 累积误差升高,则停止训练。 +- 引入正则化(regularization):基本思想是在累积误差函数中增加一个用于描述网络复杂度的部分,例如所有权值与阈值的平方和, + 其中λ∈(0,1)用于对累积经验误差与网络复杂度这两项进行折中,常通过交叉验证法来估计。 + +![pic](http://index.zeekling.cn/gogsPics/ml/nn/11.png)
+ +### 全局最小与局部最小 +模型学习的过程实质上就是一个寻找最优参数的过程,例如BP算法试图通过最速下降来寻找使得累积经验误差最小的权值与阈值,在谈到 +最优时,一般会提到局部极小(local minimum)和全局最小(global minimum)。 +> * 局部极小解:参数空间中的某个点,其邻域点的误差函数值均不小于该点的误差函数值。 +> * 全局最小解:参数空间中的某个点,所有其他点的误差函数值均不小于该点的误差函数值。 + +
![pic](http://index.zeekling.cn/gogsPics/ml/nn/12.png)
+要成为局部极小点,只要满足该点在参数空间中的梯度为零。局部极小可以有多个,而全局最小只有一个。全局最小一定是局部极小,但 +局部最小却不一定是全局最小。显然在很多机器学习算法中,都试图找到目标函数的全局最小。梯度下降法的主要思想就是沿着负梯度方 +向去搜索最优解,负梯度方向是函数值下降最快的方向,若迭代到某处的梯度为0,则表示达到一个局部最小,参数更新停止。因此在现 +实任务中,通常使用以下策略尽可能地去接近全局最小。 +> * 以多组不同参数值初始化多个神经网络,按标准方法训练,迭代停止后,取其中误差最小的解作为最终参数。 +> * 使用“模拟退火”技术,这里不做具体介绍。 +> * 使用随机梯度下降,即在计算梯度时加入了随机因素,使得在局部最小时,计算的梯度仍可能不为0,从而迭代可以继续进行。 + +不太懂 + + +## 其他神经网络 +### RBF网络 + +### ART网络 + +### SOM网络 + +### 级联相关网络 + +### Elman网络 + +### Bolttzmann网络 + + diff --git a/nn/ResNet.md b/nn/ResNet.md new file mode 100644 index 0000000..eca3cb3 --- /dev/null +++ b/nn/ResNet.md @@ -0,0 +1,68 @@ +# ResNet 详解 + +## 背景简介 + +深度网络随着层数不断加深,可能会引起梯度消失/梯度爆炸的问题: +1. “梯度消失”:指的是即当梯度(小于1.0)在被反向传播到前面的层时,重复的相乘可能会使梯度变得无限小。 +2. “梯度爆炸”:指的是即当梯度(大于1.0)在被反向传播到前面的层时,重复的相乘可能会使梯度变得非常大甚至无限大导致溢出。 + +随着网络深度的不断增加,常常会出现以下两个问题: +1. 长时间训练但是网络收敛变得非常困难甚至不收敛 +2. 网络性能会逐渐趋于饱和,甚至还会开始下降,可以观察到下图中56层的误差比20层的更多,故这种现象并不是由于过拟合造成的。 + 这种现象称为深度网络的退化问题。 + +![pic](http://www.zeekling.cn/gogsPics/ml/nn/13.png) + +ResNet深度残差网络,成功解决了此类问题,使得即使在网络层数很深(甚至在1000多层)的情况下,网络依然可以得到很好的性能与效 +率。 + +## 参差网络 + +ResNet引入残差网络结构(residual network),即在输入与输出之间(称为堆积层)引入一个前向反馈的shortcut connection,这有 +点类似与电路中的“短路”,也是文中提到identity mapping(恒等映射y=x)。原来的网络是学习输入到输出的映射H(x),而残差网络学 +习的是$$ F(x)=H(x)−x $$。残差学习的结构如下图所示: + +![pic](http://www.zeekling.cn/gogsPics/ml/nn/14.png) + +另外我们可以从数学的角度来分析这个问题,首先残差单元可以表示为: + +$$ +y_l=h(x_l) + F(x_l, W-l) \\ +x_{l+1} = f(y_l) +$$ + +其中$$ x_{l} $$ 和$$ x_{l+1} $$ 分别表示的是第 l 个残差单元的输入和输出,注意每个残差单元一般包含多层结构。 F 是残差函 +数,表示学习到的残差,而h表示恒等映射, f 是ReLU激活函数。基于上式,我们求得从浅层 l 到深层 L 的学习特征为: + +$$ x_L = x_l + \sum_{i=l}^{L-1} F(x_i, W_i) $$ + +利用链式规则,可以求得反向过程的梯度: +$$ +\frac{\alpha{loss}}{\alpha{x_l}} = \frac{\alpha{loss}}{\alpha{x_L}} * \frac{\alpha{x_L}}{\alpha{x_l}} += \frac{\alpha{loss}}{\alpha{x_L}} * (1 + \frac{\alpha}{\alpha{x_L}} \sum_{i=l}^{L-1} F(x_i, W_i) ) +$$ + +式子的第一个因子表示的损失函数到达 L 的梯度,小括号中的1表明短路机制可以无损地传播梯度,而另外一项残差梯度则需要经过带 +有weights的层,梯度不是直接传递过来的。残差梯度不会那么巧全为-1,而且就算其比较小,有1的存在也不会导致梯度消失。所以残 +差学习会更容易。 + + +实线、虚线就是为了区分这两种情况的: +1. 实线的Connection部分,表示通道相同,如上图的第一个粉色矩形和第三个粉色矩形,都是3x3x64的特征图,由于通道相同,所以采 +用计算方式为$$ H(x)=F(x)+x $$ +2. 虚线的的Connection部分,表示通道不同,如上图的第一个绿色矩形和第三个绿色矩形,分别是3x3x64和3x3x128的特征图,通道不 +同,采用的计算方式为$$ H(x)=F(x)+Wx $$,其中W是卷积操作,用来调整x维度的。 +![pic](http://www.zeekling.cn/gogsPics/ml/nn/16.png) + +## 残差学习的本质 + +![pic](http://www.zeekling.cn/gogsPics/ml/nn/15.png) + +残差网络的确解决了退化的问题,在训练集和校验集上,都证明了的更深的网络错误率越小: +![pic](http://www.zeekling.cn/gogsPics/ml/nn/17.png) + +下面是resnet的成绩单, 在imagenet2015夺得冠军: + +![pic](http://www.zeekling.cn/gogsPics/ml/nn/18.png) + + diff --git a/nn/cnn.md b/nn/cnn.md new file mode 100644 index 0000000..1aad976 --- /dev/null +++ b/nn/cnn.md @@ -0,0 +1,64 @@ +# 卷积神经网络 + +## 详解 + +卷积神经网络沿用了普通的神经元网络即多层感知器的结构,是一个前馈网络。以应用于图像领域的CNN为例,大体结构如图。 + +![卷积神经网络](http://index.zeekling.cn/gogsPics/ml/neuralNetwork/cnn2.jpg) + +### 输入层 +为了减小后续BP算法处理的复杂度,一般建议使用灰度图像。也可以使用RGB彩色图像,此时输入图像原始图像的RGB三通道。对于输入的 +图像像素分量为 [0, 255],为了计算方便一般需要归一化,如果使用sigmoid激活函数,则归一化到[0, 1],如果使用tanh激活函数, +则归一化到[-1, 1]。 + +### 卷积层 +特征提取层(C层) - 特征映射层(S层)。将上一层的输出图像与本层卷积核(权重参数w)加权值,加偏置,通过一个Sigmoid函数得到各个 +C层,然后下采样subsampling得到各个S层。C层和S层的输出称为Feature Map(特征图)。 + +### 激活层 + +将上面特征图中的得到的每个参数放入到下面的几个激活函数中进行处理 + +Sigmoid(S形函数),得到的是[0,1]区间的数值 + +Tanh(双曲正切,双S形函数),得到的是[-1,0]之间的数值 + +ReLU 当x<0 时,y=0,当x>0 时,y = x + +Leaky ReLU 当x<0 时,y = α(exp(x-1)),当x>0时,y= x + +![激活层](https://pic3.zhimg.com/80/v2-6fcb293439ca1160391b17cbc58aff87_hd.jpg) + +### 池化层 +通过上一层2*2的卷积核操作后,我们将原始图像由4*4的尺寸变为了3*3的一个新的图片。池化层的主要目的是通过降采样的方式,在不 +影响图像质量的情况下,压缩图片,减少参数。简单来说,假设现在设定池化层采用MaxPooling,大小为2*2,步长为1,取每个窗口最 +大的数值重新,那么图片的尺寸就会由3*3变为2*2:(3-2)+1=2。从上例来看,会有如下变换: + +![池化](http://index.zeekling.cn/gogsPics/ml/neuralNetwork/853467-20171104142056685-2048616836.png) + +### 全连接层 + +通 过不断的设计卷积核的尺寸,数量,提取更多的特征,最后识别不同类别的物体。做完Max Pooling后,我们就会把这些 数据“拍平”把3维的数组变成1维的数组,丢到Flatten层,然后把Flatten层的output放到full connected +Layer里,采用softmax对其进行分类。 + +## CNN三大核心思想 + +卷积神经网络CNN的出现是为了解决MLP多层感知器全连接和梯度发散的问题。其引入三个核心思想:1.局部感知(local field),2.权值 +共享(Shared Weights),3.下采样(subsampling)。极大地提升了计算速度,减少了连接数量。 + +### 局部感知 +如下图所示,左边是每个像素的全连接,右边是每行隔两个像素作为局部连接,因此在数量上,少了很多权值参数数量(每一条连接每 +一条线需要有一个权值参数,具体忘记了的可以回顾单个[神经元模型]。因此局部感知就是: +通过卷积操作,把 全连接变成局部连接 ,因为多层网络能够抽取高阶统计特性, 即使网络为局部连接,由于格外的突触连接和额外的 +神经交互作用,也可以使网络在不十分严格的意义下获得一个全局关系。 + +![局部感知](http://index.zeekling.cn/gogsPics/ml/neuralNetwork/cnn3.jpg) + +### 权值共享 +不同的图像或者同一张图像共用一个卷积核,减少重复的卷积核。同一张图像当中可能会出现相同的特征,共享卷积核能够进一步减少权 +值参数。 + +### 池化 +1. 这些统计特征能够有更低的维度,减少计算量。 +2. 不容易过拟合,当参数过多的时候很容易造成过度拟合。 +3. 缩小图像的规模,提升计算速度。 diff --git a/nn/handWrittenDigitsRecoginition.py b/nn/handWrittenDigitsRecoginition.py new file mode 100755 index 0000000..5be54c0 --- /dev/null +++ b/nn/handWrittenDigitsRecoginition.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# coding: utf-8 +import numpy as np +import sklearn.datasets as ds +import sklearn.metrics as mt +import sklearn.preprocessing as prep +import neuralNetwork as nn +import sklearn.cross_validation as cross + + +digits = ds.load_digits() +x = digits.data +y = digits.target +# 将x中的值设置到0-1之间 +x -= x.min() +x /= x.max() + +# n = nn.NeuralNetwork([64, 100, 10], 'tanh') +n = nn.NeuralNetwork([64, 100, 10], 'logistic') +x_train, x_test, y_train, y_test = cross.train_test_split(x, y) +labels_train = prep.LabelBinarizer().fit_transform(y_train) +labels_test = prep.LabelBinarizer().fit_transform(y_test) +print("start fitting") +n.fit(x_train, labels_train, epochs=10000) +preddctions = [] +for i in range(x_test.shape[0]): + o = n.predit(x_test[i]) + preddctions.append(np.argmax(o)) +print(mt.confusion_matrix(y_test, preddctions)) +print(mt.classification_report(y_test, preddctions)) diff --git a/nn/multi_task.md b/nn/multi_task.md new file mode 100644 index 0000000..0c622f5 --- /dev/null +++ b/nn/multi_task.md @@ -0,0 +1,4 @@ +# 多任务学习 + +相关学习资料 +1. [模型汇总-14 多任务学习-Multitask Learning概述](https://zhuanlan.zhihu.com/p/27421983) diff --git a/nn/neuralNetwork.py b/nn/neuralNetwork.py new file mode 100755 index 0000000..464166d --- /dev/null +++ b/nn/neuralNetwork.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# coding: utf-8 +import numpy as np + + +# 计算tanh的值,激活函数 +def tanh(x): + return np.tanh(x) + + +# 求tanh的导数 +def tanh_deriv(x): + return 1.0 - np.tanh(x)*np.tanh(x) + + +# 逻辑函数 +def logistic(x): + return 1.0/(1.0 + np.exp(-x)) + + +# 逻辑函数求导 +def logistic_deriv(x): + return logistic(x)*(1.0 - logistic(x)) + + +class NeuralNetwork: + def __init__(self, layers, activation='tanh'): + """ + :param layers: A list + """ + if activation == 'logistic': + self.activation = logistic + self.activation_deriv = logistic_deriv + elif activation == 'tanh': + self.activation = tanh + self.activation_deriv = tanh_deriv + + self.weights = [] + for i in range(1, len(layers) - 1): + # 初始化 权值范围 [-0.25,0.25) + # [0,1) * 2 - 1 => [-1,1) => * 0.25 => [-0.25,0.25) + self.weights.append((2*np.random.random((layers[i - 1] + 1, layers[i] + 1))-1)*0.25) + self.weights.append((2*np.random.random((layers[i] + 1, layers[i+1]))-1)*0.25) + + def fit(self, x, y, learning_rate=0.2, epochs=10000): + x = np.atleast_2d(x) + temp = np.ones([x.shape[0], x.shape[1] + 1]) + temp[:, 0:-1] = x + x = temp + y = np.array(y) + for k in range(epochs): + i = np.random.randint(x.shape[0]) + a = [x[i]] + + # 正向计算 + for l in range(len(self.weights)): + a.append(self.activation(np.dot(a[l], self.weights[l]))) + # 反向传播 + error = y[i] - a[-1] + deltas = [error*self.activation_deriv(a[-1])] + + # 开始反向计算,从倒数第二层开始计算 + for j in range(len(a)-2, 0, -1): + deltas.append(deltas[-1].dot(self.weights[j].T)*self.activation_deriv(a[j])) + deltas.reverse() + + # 更新权值 + for i in range(len(self.weights)): + layer = np.atleast_2d(a[i]) + delta = np.atleast_2d(deltas[i]) + self.weights[i] += learning_rate * layer.T.dot(delta) + + def predit(self, x): + x = np.array(x) + temp = np.ones(x.shape[0] + 1) + temp[0:-1] = x + a = temp + for l in range(0, len(self.weights)): + a = self.activation(np.dot(a, self.weights[l])) + return a diff --git a/nn/rnn.md b/nn/rnn.md new file mode 100644 index 0000000..dc1391b --- /dev/null +++ b/nn/rnn.md @@ -0,0 +1,37 @@ +# 循环神经网络 + +## RNN结构 +RNN结构如下: + +![rnn](http://index.zeekling.cn/gogsPics/ml/neuralNetwork/rnn1.png) + +- 左侧是RNN的原始结构, 右侧是RNN在时间上展开的结果 +- RNN的结构,本质上和全连接网络相同 + +![rnn](http://index.zeekling.cn/gogsPics/ml/neuralNetwork/rnn2.gif) + + +## LSTM 网络 +LSTM 同样是这样的结构,但是重复的模块拥有一个不同的结构。不同于单一神经网络层,这里是有四个,以一种非常特殊的方式进行交互。 + +![SLTM](http://index.zeekling.cn/gogsPics/ml/neuralNetwork/005BVyzmly1fotnatxsm7j30jg07bjsi.jpg) + + +### 遗忘门 +在我们 LSTM 中的第一步是决定我们会从细胞状态中丢弃什么信息。这个决定通过一个称为忘记门层完成。该门会读取ht−1和xt,输出一个在 +0到 1之间的数值给每个在细胞状态 Ct−1 中的数字。1 表示“完全保留”,0 表示“完全舍弃”。 + +![遗忘门](http://index.zeekling.cn/gogsPics/ml/neuralNetwork/005BVyzmly1fotoa9sgm5j30jg06074q.jpg) + +### 输入门 +我们把旧状态与ft相乘,丢弃掉我们确定需要丢弃的信息。接着加上it∗C~t。这就是新的候选值,根据我们决定更新每个状态的程度进行变化。 + +![输入门](http://index.zeekling.cn/gogsPics/ml/neuralNetwork/005BVyzmly1fotoftw50ij31eq0fomz4.jpg) + +### 输出门 +在语言模型的例子中,因为他就看到了一个 代词,可能需要输出与一个 动词 相关的信息。例如,可能输出是否代词是单数还是负数,这样如 +果是动词的话,我们也知道动词需要进行的词形变化。 + +![输出门](http://index.zeekling.cn/gogsPics/ml/neuralNetwork/005BVyzmly1fotoky28zbj30jg06074w.jpg) + + diff --git a/nn/testnn.py b/nn/testnn.py new file mode 100755 index 0000000..06561a2 --- /dev/null +++ b/nn/testnn.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 +# coding: utf-8 +import neuralNetwork as nn +import numpy as np + +n = nn.NeuralNetwork([2, 2, 1], 'tanh') + +x = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]) +y = np.array([0, 1, 1, 0]) +n.fit(x, y) +for i in [[0, 0], [0, 1], [1, 0], [1, 1]]: + print(i, n.predit(i)) diff --git a/nn/visualizeDigits.py b/nn/visualizeDigits.py new file mode 100755 index 0000000..b85fa88 --- /dev/null +++ b/nn/visualizeDigits.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# coding:utf-8 + +import sklearn.datasets as ds +import pylab as pl + + +digits = ds.load_digits() +print(digits.data.shape) + +pl.gray() +pl.matshow(digits.images[0]) +pl.show() diff --git a/nn/残差resnet网络原理详解.docx b/nn/残差resnet网络原理详解.docx new file mode 100644 index 0000000000000000000000000000000000000000..19bcaf03795cdf4f2be55d164a80441eb5ccb303 GIT binary patch literal 280244 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
  • &L)mZeiHIGcxYnC;axc%OnPftu0kt2#v4Gp5j?MF{bWE^w^l`*){tdB`FG7( zhJM-r*g6i!ixt%Tw1THq7d9?(KKkOT#J=Jb)Ff3^6BmAl$1-7rAYRQmy!>0e>{QQ= zLl)c1`n)`Gx1HQV9|3oONV{FO8AF#Zi_gWP^ul;^`QST2l{B}Usg82kN!mx)?=ZB5 z0!T!{lV~qM&GXIv7;(NP$7nhtqAQ`?-R zJM!v7HR-jsxvfPpL2!U7i%;sjYd2-;X7bkOuKsq5}f%hg@RsztBSx{tQ= z`}_OSwj|&8+O7v~X^z)rahFin9!Q3}hsP>W?X3k5A&n;6jgcu|b#?Vs$ErHu#_&Z| zY!SYdI{G-BSLE~Jphr7@Mj;*$qattA#61 zaFkg%KR-7@strz4PL3_)_2ToFZX zYj|qq_jGsHpdrk@BlAsh{`&jycNGJ`0~t7KZxA(o%QwXg^!2+{^=*4QeTF5Q%Jz6yrZ~K_!Ziqf^{((fSPhFzrF?^!kAS=>IrV9 z7PktDMDiN&qXLT+eE#gw5)w+GgI7ya5H!42s@(2XpFIujkFT#6gf|@k^-iAtc*nkY z0k^p2al}{mwWWrzD|7x}=4V+HjBJYyu4`&u=@#)?FW%feu7gee@H-`hPA*(gZ7?(o z*4f>~Z|Qsbw3G^4ON4EN#vWQeXX5g{(2iU9LC$YtP;|Y%-A}SMQ{fH{{zHEcqwav8AV2Cs8NEx&IW7Jc_9fA`(fUrol`{~%dYv6X`8w{klDIev z5BG!@o%~r27^I(?;v^nV<>1q4GDxpx>@Cjwl_i&RRbvzz1pp$3tdQeA@HV)~2%J$=47)A{ZH!u8Ugmqhlalg1mW-}rQ)Q(zEOV4-)s4mb zh#4-u5|0v69|0tWUS^u?fDn=O9i7O)56hD4vQ`V_o60JNIpEt# z^7C@^?DOX_w#@{SMhdp7wBpLz;bul&>!sqtk47Qz%*4XN*QIH(i(7 zG~FGa(S5x#VdNXzxO&EpL4^ec#t;qH1Z?|%hgP3X@h3l?ZZ->c6Q8q)xaEn<+o23@ zU9i#M;OxS*Kb-*Y2g@C6_!?&ky{N<{HE^`FfDxL8n1_uzife)q{<7f z&3{W2qXdsP>;VPG<38ZpfBr&?{CJCOUs>@Sgv*x9%6?xJ;`rg)ZsYB_D z$rT+MLf58y$q+%_lx{P7RKtulkaTVy4(vTUqFxe|me}m_t+KYx;1lJ}wyX1XIlDEo zhY=^BgE*%SoHr9HO;{JH5Z5=jvVQ?JX{8dL!PY*{&M{P;Dzi+X?dPhQ?jfCm1 z`7`5?@c8JYGGAZz#p{ycC;VPND_R{kkDQ{`rq14t*3(-c>|(*b+ec~FW3rWj;tUUr z<%HjZ{Q#l$LSmwT2YC~MIjK(8udE2{&}CGg=UGcmi49-k+<|c+s$PncHCMy|M z7)%(eb_B=dytA>b;ahCan_gZEbiIz>_X&LVcqXcwo0}K>T3()%9p*|yDh23^<+AQ9 zgo?OrdMgrlw{;AD?1IR@Ouy6OV>3GDA}$ zmRh)R37fdRQnrM!utv6CbKWJzg|GZV?+2@Lincs6i^;>=PRQobc&;RO#CAkYne~0$ z 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
  • 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 -1) or (lwrTitle.find('nisb') > -1): + newFlag = 1.0 + else: + newFlag = 0.0 + + # 查找是否已经标志出售,我们只收集已出售的数据 + soldUnicde = currentRow[0].find_all('td')[3].find_all('span') + if len(soldUnicde) == 0: + print("商品 #%d 没有出售" % i) + else: + # 解析页面获取当前价格 + soldPrice = currentRow[0].find_all('td')[4] + priceStr = soldPrice.text + priceStr = priceStr.replace('$','') + priceStr = priceStr.replace(',','') + if len(soldPrice) > 1: + priceStr = priceStr.replace('Free shipping', '') + sellingPrice = float(priceStr) + + # 去掉不完整的套装价格 + if sellingPrice > origPrc * 0.5: + print("%d\t%d\t%d\t%f\t%f" % (yr, numPce, newFlag, origPrc, sellingPrice)) + retX.append([yr, numPce, newFlag, origPrc]) + retY.append(sellingPrice) + i += 1 + currentRow = soup.find_all('table', r = "%d" % i) + +def ridgeRegres(xMat, yMat, lam = 0.2): + """ + 函数说明:岭回归 + Parameters: + xMat - x数据集 + yMat - y数据集 + lam - 缩减系数 + Returns: + ws - 回归系数 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-20 + """ + xTx = xMat.T * xMat + denom = xTx + np.eye(np.shape(xMat)[1]) * lam + if np.linalg.det(denom) == 0.0: + print("矩阵为奇异矩阵,不能求逆") + return + ws = denom.I * (xMat.T * yMat) + return ws + +def setDataCollect(retX, retY): + """ + 函数说明:依次读取六种乐高套装的数据,并生成数据矩阵 + Parameters: + 无 + Returns: + 无 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-12-03 + """ + scrapePage(retX, retY, './lego/lego8288.html', 2006, 800, 49.99) #2006年的乐高8288,部件数目800,原价49.99 + scrapePage(retX, retY, './lego/lego10030.html', 2002, 3096, 269.99) #2002年的乐高10030,部件数目3096,原价269.99 + scrapePage(retX, retY, './lego/lego10179.html', 2007, 5195, 499.99) #2007年的乐高10179,部件数目5195,原价499.99 + scrapePage(retX, retY, './lego/lego10181.html', 2007, 3428, 199.99) #2007年的乐高10181,部件数目3428,原价199.99 + scrapePage(retX, retY, './lego/lego10189.html', 2008, 5922, 299.99) #2008年的乐高10189,部件数目5922,原价299.99 + scrapePage(retX, retY, './lego/lego10196.html', 2009, 3263, 249.99) #2009年的乐高10196,部件数目3263,原价249.99 + +def regularize(xMat, yMat): + """ + 函数说明:数据标准化 + Parameters: + xMat - x数据集 + yMat - y数据集 + Returns: + inxMat - 标准化后的x数据集 + inyMat - 标准化后的y数据集 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-12-03 + """ + inxMat = xMat.copy() #数据拷贝 + inyMat = yMat.copy() + yMean = np.mean(yMat, 0) #行与行操作,求均值 + inyMat = yMat - yMean #数据减去均值 + inMeans = np.mean(inxMat, 0) #行与行操作,求均值 + inVar = np.var(inxMat, 0) #行与行操作,求方差 + # print(inxMat) + print(inMeans) + # print(inVar) + inxMat = (inxMat - inMeans) / inVar #数据减去均值除以方差实现标准化 + return inxMat, inyMat + +def rssError(yArr,yHatArr): + """ + 函数说明:计算平方误差 + Parameters: + yArr - 预测值 + yHatArr - 真实值 + Returns: + + Website: + http://www.cuijiahua.com/ + Modify: + 2017-12-03 + """ + return ((yArr-yHatArr)**2).sum() + +def standRegres(xArr,yArr): + """ + 函数说明:计算回归系数w + Parameters: + xArr - x数据集 + yArr - y数据集 + Returns: + ws - 回归系数 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-12 + """ + xMat = np.mat(xArr); yMat = np.mat(yArr).T + xTx = xMat.T * xMat #根据文中推导的公示计算回归系数 + if np.linalg.det(xTx) == 0.0: + print("矩阵为奇异矩阵,不能求逆") + return + ws = xTx.I * (xMat.T*yMat) + return ws + +def crossValidation(xArr, yArr, numVal = 10): + """ + 函数说明:交叉验证岭回归 + Parameters: + xArr - x数据集 + yArr - y数据集 + numVal - 交叉验证次数 + Returns: + wMat - 回归系数矩阵 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-20 + """ + m = len(yArr) #统计样本个数 + indexList = list(range(m)) #生成索引值列表 + errorMat = np.zeros((numVal,30)) #create error mat 30columns numVal rows + for i in range(numVal): #交叉验证numVal次 + trainX = []; trainY = [] #训练集 + testX = []; testY = [] #测试集 + random.shuffle(indexList) #打乱次序 + for j in range(m): #划分数据集:90%训练集,10%测试集 + if j < m * 0.9: + trainX.append(xArr[indexList[j]]) + trainY.append(yArr[indexList[j]]) + else: + testX.append(xArr[indexList[j]]) + testY.append(yArr[indexList[j]]) + wMat = ridgeTest(trainX, trainY) #获得30个不同lambda下的岭回归系数 + for k in range(30): #遍历所有的岭回归系数 + matTestX = np.mat(testX); matTrainX = np.mat(trainX) #测试集 + meanTrain = np.mean(matTrainX,0) #测试集均值 + varTrain = np.var(matTrainX,0) #测试集方差 + matTestX = (matTestX - meanTrain) / varTrain #测试集标准化 + yEst = matTestX * np.mat(wMat[k,:]).T + np.mean(trainY) #根据ws预测y值 + errorMat[i, k] = rssError(yEst.T.A, np.array(testY)) #统计误差 + meanErrors = np.mean(errorMat,0) #计算每次交叉验证的平均误差 + minMean = float(min(meanErrors)) #找到最小误差 + bestWeights = wMat[np.nonzero(meanErrors == minMean)] #找到最佳回归系数 + + xMat = np.mat(xArr); yMat = np.mat(yArr).T + meanX = np.mean(xMat,0); varX = np.var(xMat,0) + unReg = bestWeights / varX #数据经过标准化,因此需要还原 + print('%f%+f*年份%+f*部件数量%+f*是否为全新%+f*原价' % ((-1 * np.sum(np.multiply(meanX,unReg)) + np.mean(yMat)), unReg[0,0], unReg[0,1], unReg[0,2], unReg[0,3])) + +def ridgeTest(xArr, yArr): + """ + 函数说明:岭回归测试 + Parameters: + xMat - x数据集 + yMat - y数据集 + Returns: + wMat - 回归系数矩阵 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-20 + """ + xMat = np.mat(xArr); yMat = np.mat(yArr).T + #数据标准化 + yMean = np.mean(yMat, axis = 0) #行与行操作,求均值 + yMat = yMat - yMean #数据减去均值 + xMeans = np.mean(xMat, axis = 0) #行与行操作,求均值 + xVar = np.var(xMat, axis = 0) #行与行操作,求方差 + xMat = (xMat - xMeans) / xVar #数据减去均值除以方差实现标准化 + numTestPts = 30 #30个不同的lambda测试 + wMat = np.zeros((numTestPts, np.shape(xMat)[1])) #初始回归系数矩阵 + for i in range(numTestPts): #改变lambda计算回归系数 + ws = ridgeRegres(xMat, yMat, np.exp(i - 10)) #lambda以e的指数变化,最初是一个非常小的数, + wMat[i, :] = ws.T #计算回归系数矩阵 + return wMat + +def useStandRegres(): + """ + 函数说明:使用简单的线性回归 + Parameters: + 无 + Returns: + 无 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-12 + """ + lgX = [] + lgY = [] + setDataCollect(lgX, lgY) + data_num, features_num = np.shape(lgX) + lgX1 = np.mat(np.ones((data_num, features_num + 1))) + lgX1[:, 1:5] = np.mat(lgX) + ws = standRegres(lgX1, lgY) + print('%f%+f*年份%+f*部件数量%+f*是否为全新%+f*原价' % (ws[0],ws[1],ws[2],ws[3],ws[4])) + +def usesklearn(): + """ + 函数说明:使用sklearn + Parameters: + 无 + Returns: + 无 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-12-08 + """ + from sklearn import linear_model + reg = linear_model.Ridge(alpha = .5) + lgX = [] + lgY = [] + setDataCollect(lgX, lgY) + reg.fit(lgX, lgY) + print('%f%+f*年份%+f*部件数量%+f*是否为全新%+f*原价' % (reg.intercept_, reg.coef_[0], reg.coef_[1], reg.coef_[2], reg.coef_[3])) + +if __name__ == '__main__': + usesklearn() diff --git a/regression/lego/lego10030.html b/regression/lego/lego10030.html new file mode 100644 index 0000000..92024fe --- /dev/null +++ b/regression/lego/lego10030.html @@ -0,0 +1,55 @@ +lego star destroyer 10030 items - Get great deals on Star Wars, lego star destroyer items on eBay.com! +

    + +
    +
    +
    +
    Skip to main content
    Hi, pbharrin! (Sign out)You're Invited! Join eBay Bucks.
    Advanced

    11 results found for lego star destroyer 10030

    Save search
    Preferences: Completed listings See only active listings | Edit preferences | Clear preferences
    +
    +
    +

    Distance

    Please enter valid zipcode.
    Please select a valid popular city.
    Please enter valid zipcode or select a valid popular city.
    Within miles of ZIP
    +
    +
    +
    +
    +
    +
    View as:
    Sort by:
    You have specified additional options in Advanced Search.
    Item image
     
    1 Bid
    Sold
    $699.99
    Free shipping
    End Date:Jan-26 20:12
    Item image
     
    12 Bids
    Sold
    $602.00End Date:Jan-26 16:05
    Item image
     
    22 Bids
    Sold
    $515.00End Date:Jan-24 14:33
    Item image
    Used - Rare
     
    2 Bids
    Sold
    $510.00End Date:Jan-24 08:44
    Item image
     
    1 Bid
    Sold
    $375.00End Date:Jan-23 12:36
    Item image
     
    Buy It Now
    Sold
    $1,050.00End Date:Jan-21 07:49
    Item image
    Expedited shipping available
     
    26 Bids
    Sold
    $740.00End Date:Jan-17 20:08
    Item image
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    31 Bids
    Sold
    $759.00End Date:Jan-17 16:27
    Item image
    One-day shipping available
     
    6 Bids
    Sold
    $730.00
    Free shipping
    End Date:Jan-15 12:39
    Item image
     
    Best Offer
    Sold
    $750.00End Date:Jan-14 01:40
    Item image
     
    0 Bids$30.00End Date:Jan-13 19:12
    1 item found from eBay international sellers
    Item image
    Location: United Kingdom
     
    0 Bids$63.76End Date:Jan-16 12:43
    +
    +
    +
    This page was last updated: Jan-28 11:31. Number of bids and bid amounts may be slightly out of date. See each listing for international shipping options and costs.
    +
    +
    +
    +
    Popular products
    No suggestions
    \ No newline at end of file diff --git a/regression/lego/lego10179.html b/regression/lego/lego10179.html new file mode 100644 index 0000000..4407610 --- /dev/null +++ b/regression/lego/lego10179.html @@ -0,0 +1,55 @@ +lego falcon 10179 items - Get great deals on Toys Hobbies, lego 10179 items on eBay.com! +
    + +
    +
    +
    +
    Skip to main content
    Hi, pbharrin! (Sign out)You're Invited! Join eBay Bucks.
    Advanced

    27 results found for lego falcon 10179

    Save search
    Preferences: Completed listings See only active listings | Edit preferences | Clear preferences
    +
    +
    +

    Distance

    Please enter valid zipcode.
    Please select a valid popular city.
    Please enter valid zipcode or select a valid popular city.
    Within miles of ZIP
    +
    +
    +
    +
    +
    +
    View as:
    Sort by:
    Item image
     
    7 Bids
    Sold
    $910.00End Date:Jan-27 19:30
    Item image
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $1,199.99End Date:Jan-24 11:58
    Item image
     
    9 Bids
    Sold
    $811.88End Date:Jan-24 08:36
    Item image
     
    Best Offer
    $1,138.00
    Free shipping
    End Date:Jan-23 19:40
    Item image
     
    15 Bids
    Sold
    $1,324.79End Date:Jan-23 13:13
    Item image
     
    Buy It Now
    Sold
    $850.00
    Free shipping
    End Date:Jan-22 21:04
    Item image
     
    Buy It Now
    Sold
    $800.00
    Free shipping
    End Date:Jan-22 21:03
    Item image
     
    4 Bids
    Sold
    $810.00End Date:Jan-22 12:55
    Item image
     
    Buy It Now
    Sold
    $1,075.00End Date:Jan-22 05:28
    Item image
    Not in US E-mail me to see if box can be mailed to you
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    1 Bid
    Sold
    $1,050.00
    Free shipping
    End Date:Jan-21 21:15
    Item image
    Expedited shipping available
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $1,199.99End Date:Jan-21 16:22
    Item image
     
    Best Offer
    Sold
    $1,342.31End Date:Jan-21 14:47
    Item image
     
    Buy It Now
    Sold
    $1,000.00End Date:Jan-21 03:08
    Item image
    2 SEALED SETS WITH FREE SHIPPING WITH BUY IT NOW RETIRE
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $1,780.00
    Free shipping
    End Date:Jan-20 13:57
    Item image
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $750.00End Date:Jan-19 09:22
    Item image
     
    Buy It Now$1,050.00End Date:Jan-17 18:19
    Item image
     
    11 Bids
    Sold
    $2,204.99End Date:Jan-17 15:46
    Item image
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellersBuy It Now$1,099.99End Date:Jan-16 18:24
    Item image
    GUARANTEED XMAS DELIVERY IN US IF PURCHASED BY 12/20
    One-day shipping available
     
    Best Offer
    Sold
    $925.00End Date:Jan-16 15:12
    Item image
     
    9 Bids
    Sold
    $860.00End Date:Jan-15 19:58
    Item image
     
    Buy It Now$1,675.00End Date:Jan-15 19:16
    Item image
     
    Buy It Now$9.99End Date:Jan-15 09:17
    Item image
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $1,199.99
    Free shipping
    End Date:Jan-14 01:04
    Item image
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $1,099.99
    Free shipping
    End Date:Jan-13 16:48
    Item image
    Expedited shipping available
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $1,149.99End Date:Jan-13 14:46
    Item image
     
    Buy It Now
    Sold
    $800.00
    Free shipping
    End Date:Jan-13 14:13
    Item image
     
    Buy It Now
    Sold
    $850.00
    Free shipping
    End Date:Jan-13 09:50
    1 item found from eBay international sellers
    Item image
    Location: United Kingdom
     
    20 Bids
    Sold
    $1,343.74End Date:Jan-23 13:13
    +
    +
    +
    Amounts shown in italicized text are for items listed in currency other than U.S. dollars and are approximate conversions to U.S. dollars based upon Bloomberg's conversion rates. For more recent exchange rates, please use the Universal Currency Converter.

    This page was last updated: Jan-28 08:08. Number of bids and bid amounts may be slightly out of date. See each listing for international shipping options and costs.
    +
    +
    +
    +
    Popular products
    No suggestions
    \ No newline at end of file diff --git a/regression/lego/lego10181.html b/regression/lego/lego10181.html new file mode 100644 index 0000000..511540d --- /dev/null +++ b/regression/lego/lego10181.html @@ -0,0 +1,55 @@ +lego 10143 items - Get great deals on Star Wars, lego 10030 items on eBay.com! +
    + +
    +
    +
    +
    Skip to main content
    Hi, pbharrin! (Sign out)You're Invited! Join eBay Bucks.
    Advanced

    7 results found for lego 10143

    Save search
    Preferences: Completed listings See only active listings | Edit preferences | Clear preferences
    +
    +
    +

    Distance

    Please enter valid zipcode.
    Please select a valid popular city.
    Please enter valid zipcode or select a valid popular city.
    Within miles of ZIP
    +
    +
    +
    +
    +
    +
    View as:
    Sort by:
    You have specified additional options in Advanced Search.
    +
    +
    +
    This page was last updated: Jan-28 11:30. Number of bids and bid amounts may be slightly out of date. See each listing for international shipping options and costs.
    +
    +
    +
    +
    Popular products
    No suggestions
    \ No newline at end of file diff --git a/regression/lego/lego10189.html b/regression/lego/lego10189.html new file mode 100644 index 0000000..edc5062 --- /dev/null +++ b/regression/lego/lego10189.html @@ -0,0 +1,55 @@ +lego taj mahal items - Get great deals on Sets, lego eiffel tower items on eBay.com! +
    + +
    +
    +
    +
    Skip to main content
    Hi, pbharrin! (Sign out)You're Invited! Join eBay Bucks.
    Advanced

    16 results found for lego taj mahal

    Save search
    Preferences: Completed listings See only active listings | Edit preferences | Clear preferences
    +
    +
    +

    Distance

    Please enter valid zipcode.
    Please select a valid popular city.
    Please enter valid zipcode or select a valid popular city.
    Within miles of ZIP
    +
    +
    +
    +
    +
    +
    View as:
    Sort by:
    You have specified additional options in Advanced Search.
    Item image
     
    5 Bids
    Sold
    $530.00
    Free shipping
    End Date:Jan-26 12:56
    Item image
     
    Buy It Now
    $549.95
    Free shipping
    End Date:Jan-25 21:16
    Item image
     
    Buy It Now
    Sold
    $599.95End Date:Jan-25 18:18
    Item image
     
    18 Bids
    Sold
    $510.00End Date:Jan-23 19:05
    Item image
     
    8 Bids
    Sold
    $423.00End Date:Jan-23 07:41
    Item image
     
    Buy It Now
    $599.95
    Free shipping
    End Date:Jan-22 21:13
    Item image
     
    0 Bids
    Buy It Now
    $449.99
    $500.00
    End Date:Jan-22 14:44
    Item image
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $599.99End Date:Jan-21 18:13
    Item image
    Next Day Shipping Available Guaranteed
    One-day shipping available
     
    Buy It Now$550.00End Date:Jan-21 16:48
    Item image
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $589.99
    Free shipping
    End Date:Jan-21 04:29
    Item image
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $569.99
    Free shipping
    End Date:Jan-20 16:06
    Item image
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $529.99End Date:Jan-20 14:11
    Item image
     
    1 Bid
    Sold
    $500.00End Date:Jan-17 16:49
    Item image
     
    Buy It Now
    Sold
    $549.95End Date:Jan-16 18:38
    Item image
     
    1 Bid
    Sold
    $300.00End Date:Jan-16 00:38
    Item image
     
    0 Bids
    Buy It Now
    $569.00
    $629.00
    Free shipping
    End Date:Jan-15 19:40
    1 item found from eBay international sellers
    Item image
    Location: Netherlands
     
    Buy It Now
    Sold
    $637.52End Date:Jan-23 13:22
    +
    +
    +
    This page was last updated: Jan-28 11:32. Number of bids and bid amounts may be slightly out of date. See each listing for international shipping options and costs.
    +
    +
    +
    +
    Popular products
    No suggestions
    \ No newline at end of file diff --git a/regression/lego/lego10196.html b/regression/lego/lego10196.html new file mode 100644 index 0000000..524593c --- /dev/null +++ b/regression/lego/lego10196.html @@ -0,0 +1,55 @@ +lego 10196 items - Get great deals on lego 10197, lego 10195 items on eBay.com! +
    + +
    +
    +
    +
    Skip to main content
    Hi, pbharrin! (Sign out)You're Invited! Join eBay Bucks.
    Advanced

    13 results found for lego 10196

    Save search
    Preferences: Completed listings See only active listings | Edit preferences | Clear preferences
    +
    +
    +

    Distance

    Please enter valid zipcode.
    Please select a valid popular city.
    Please enter valid zipcode or select a valid popular city.
    Within miles of ZIP
    +
    +
    +
    +
    +
    +
    View as:
    Sort by:
    You have specified additional options in Advanced Search.
    Are you looking for... items near New York, New York?
    Item image
     
    3 Bids
    Sold
    $380.00End Date:Jan-26 20:22
    Item image
     
    1 Bid
    Sold
    $399.00End Date:Jan-24 18:03
    Item image
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $427.99End Date:Jan-24 03:32
    Item image
     
    22 Bids
    Sold
    $360.00End Date:Jan-23 20:07
    Item image
     
    0 Bids
    Buy It Now
    $450.00
    $550.00
    End Date:Jan-23 19:21
    Item image
     
    Buy It Now$489.00End Date:Jan-23 17:31
    Item image
    FedEx 2-day shipping!!
     
    1 Bid
    Sold
    $399.00End Date:Jan-22 11:43
    Item image
     
    Buy It Now
    Sold
    $399.95
    Free shipping
    End Date:Jan-21 05:51
    Item image
     
    Get fast shipping and excellent service when you buy from eBay Top-rated sellers
    Buy It Now
    Sold
    $499.99End Date:Jan-19 00:26
    Item image
     
    Buy It Now
    $459.95
    Free shipping
    End Date:Jan-18 16:10
    Item image
     
    1 Bid
    Sold
    $399.95
    Free shipping
    End Date:Jan-17 15:40
    Item image
     
    Buy It Now
    $459.95
    Free shipping
    End Date:Jan-15 14:26
    Item image
     
    12 Bids
    Sold
    $331.51End Date:Jan-15 12:29
    +
    +
    +
    This page was last updated: Jan-28 17:54. Number of bids and bid amounts may be slightly out of date. See each listing for international shipping options and costs.
    +
    +
    +
    +
    Popular products
    No suggestions
    \ No newline at end of file diff --git a/regression/lego/lego8288.html b/regression/lego/lego8288.html new file mode 100644 index 0000000..6d4dae3 --- /dev/null +++ b/regression/lego/lego8288.html @@ -0,0 +1,43 @@ +lego 8288 items - Get great deals on Technic, lego 8421 items on eBay.com! +
    + +
    +
    +
    +
    Skip to main content
    Hi, pbharrin! (Sign out)You're Invited! Join eBay Bucks.
    Advanced

    5 results found for lego 8288

    Save search
    Preferences: Completed listings See only active listings | Edit preferences | Clear preferences
    +
    +
    +

    Distance

    Please enter valid zipcode.
    Please select a valid popular city.
    Please enter valid zipcode or select a valid popular city.
    Within miles of ZIP
    +
    +
    +
    +
    +
    +
    View as:
    Sort by:
    You have specified additional options in Advanced Search.
    +
    +
    +
    This page was last updated: Jan-28 11:24. Number of bids and bid amounts may be slightly out of date. See each listing for international shipping options and costs.
    +
    +
    +
    +
    Popular products
    No suggestions
    \ No newline at end of file diff --git a/regression/log_regres.py b/regression/log_regres.py new file mode 100755 index 0000000..25d2297 --- /dev/null +++ b/regression/log_regres.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python2 +# -*- coding:utf-8 -*- +import numpy as np +import matplotlib.pyplot as plt + + +# 加载数据 +def loadDataSet(): + dataMat = [] + labelMat = [] + fr = open('testSet.txt') + for line in fr.readlines(): + lineArr = line.strip().split() + dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) + labelMat.append(int(lineArr[2])) + fr.close() + + return dataMat, labelMat + + +# sigmoid 激活函数 +def sigmoid(intX): + return 1.0 / (1 + np.exp(-intX)) + + +# 梯度上升算法 +def gradAscent(dataMatIn, classLabels): + dataMatrix = np.mat(dataMatIn) + labelMat = np.mat(classLabels).transpose() + m, n = np.shape(dataMatrix) + alpha = 0.001 + maxCycles = 500 + weights = np.ones((n, 1)) + for k in range(maxCycles): + h = sigmoid(dataMatrix * weights) + error = labelMat - h + weights = weights + alpha * dataMatrix.transpose() * error + + return weights.getA() + + +def plotBeastFit(weights): + dataMat, labelMat = loadDataSet() + dataArr = np.array(dataMat) + n = np.shape(dataArr)[0] + xcord1 = [] + xcord2 = [] + ycode1 = [] + ycode2 = [] + for i in range(n): + if int(labelMat[i]) == 1: + xcord1.append(dataArr[i, 1]) + ycode1.append(dataArr[i, 2]) + else: + xcord2.append(dataArr[i, 1]) + ycode2.append(dataArr[i, 2]) + + fig = plt.figure() + ax = fig.add_subplot(111) + ax.scatter(xcord1, ycode1, s=20, c='red', marker='s', alpha=0.5) + ax.scatter(xcord2, ycode2, s=20, c='green', alpha=0.5) + x = np.arange(-3.0, 3.0, 0.1) + y = (-weights[0] - weights[1] * x) / weights[2] + ax.plot(x, y) + plt.title('BestFit') + plt.xlabel('X1') + plt.ylabel('X2') + plt.show() + + +# 随机梯度上升算法 +def stocGradAscent0(dataMatrix, classLabels): + m, n = np.shape(dataMatrix) + alpha = 0.01 + weights = np.ones(n) + for i in range(m): + h = sigmoid(sum(dataMatrix[i] * weights)) + error = classLabels[i] - h + weights = weights + alpha * error * dataMatrix[i] + + return weights + + +# 优化后的梯度上升算法 +def stocGradAscent1(dataMatrix, classLabels, numIter=150): + m, n = np.shape(dataMatrix) + weights = np.ones(n) + for j in range(numIter): + dataIndex = range(m) + for i in range(m): + # alpha 每次都需要调整 + alpha = 4 / (1.0 + j + i) + 0.01 + # 随机选取跟新 + rangeIndex = int(np.random.uniform(0, len(dataIndex))) + h = sigmoid(sum(dataMatrix[rangeIndex] * weights)) + error = classLabels[rangeIndex] - h + weights = weights + alpha * error * dataMatrix[rangeIndex] + + return weights + + +if __name__ == '__main__': + dataMat, labelMat = loadDataSet() + # weights = gradAscent(dataMat, labelMat) + # weights = stocGradAscent0(np.array(dataMat), labelMat) + weights = stocGradAscent1(np.array(dataMat), labelMat) + plotBeastFit(weights) diff --git a/regression/multiple.csv b/regression/multiple.csv new file mode 100644 index 0000000..54c5904 --- /dev/null +++ b/regression/multiple.csv @@ -0,0 +1,10 @@ +100,4,9.3 +50,3,4.8 +100,4,8.9 +100,2,6.5 +50,2,4.2 +80,2,6.2 +75,3,7.4 +65,4,6.0 +90,3,7.6 +90,2,6.1 \ No newline at end of file diff --git a/regression/multipleDummy.csv b/regression/multipleDummy.csv new file mode 100644 index 0000000..f04253b --- /dev/null +++ b/regression/multipleDummy.csv @@ -0,0 +1,13 @@ +100,4,0,1,0,9.3 +50,3,1,0,0,4.8 +100,4,0,1,0,8.9 +100,2,0,0,1,6.5 +50,2,0,0,1,4.2 +80,2,0,1,0,6.2 +75,3,0,1,0,7.4 +65,4,1,0,0,6.0 +90,3,1,0,0,7.6 +100,4,0,1,0,9.3 +50,3,1,0,0,4.8 +100,4,0,1,0,8.9 +100,2,0,0,1,6.5 diff --git a/regression/regression.py b/regression/regression.py new file mode 100755 index 0000000..1d8b6d7 --- /dev/null +++ b/regression/regression.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python3 +# -*-coding:utf-8 -*- +from matplotlib.font_manager import FontProperties +import matplotlib.pyplot as plt +import numpy as np + +def loadDataSet(fileName): + """ + 函数说明:加载数据 + Parameters: + fileName - 文件名 + Returns: + xArr - x数据集 + yArr - y数据集 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-20 + """ + numFeat = len(open(fileName).readline().split('\t')) - 1 + xArr = []; yArr = [] + fr = open(fileName) + for line in fr.readlines(): + lineArr =[] + curLine = line.strip().split('\t') + for i in range(numFeat): + lineArr.append(float(curLine[i])) + xArr.append(lineArr) + yArr.append(float(curLine[-1])) + return xArr, yArr + +def ridgeRegres(xMat, yMat, lam = 0.2): + """ + 函数说明:岭回归 + Parameters: + xMat - x数据集 + yMat - y数据集 + lam - 缩减系数 + Returns: + ws - 回归系数 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-20 + """ + xTx = xMat.T * xMat + denom = xTx + np.eye(np.shape(xMat)[1]) * lam + if np.linalg.det(denom) == 0.0: + print("矩阵为奇异矩阵,不能求逆") + return + ws = denom.I * (xMat.T * yMat) + return ws + +def ridgeTest(xArr, yArr): + """ + 函数说明:岭回归测试 + Parameters: + xMat - x数据集 + yMat - y数据集 + Returns: + wMat - 回归系数矩阵 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-20 + """ + xMat = np.mat(xArr); yMat = np.mat(yArr).T + #数据标准化 + yMean = np.mean(yMat, axis = 0) #行与行操作,求均值 + yMat = yMat - yMean #数据减去均值 + xMeans = np.mean(xMat, axis = 0) #行与行操作,求均值 + xVar = np.var(xMat, axis = 0) #行与行操作,求方差 + xMat = (xMat - xMeans) / xVar #数据减去均值除以方差实现标准化 + numTestPts = 30 #30个不同的lambda测试 + wMat = np.zeros((numTestPts, np.shape(xMat)[1])) #初始回归系数矩阵 + for i in range(numTestPts): #改变lambda计算回归系数 + ws = ridgeRegres(xMat, yMat, np.exp(i - 10)) #lambda以e的指数变化,最初是一个非常小的数, + wMat[i, :] = ws.T #计算回归系数矩阵 + return wMat + +def plotwMat(): + """ + 函数说明:绘制岭回归系数矩阵 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-20 + """ + #font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14) + abX, abY = loadDataSet('abalone.txt') + redgeWeights = ridgeTest(abX, abY) + fig = plt.figure() + ax = fig.add_subplot(111) + ax.plot(redgeWeights) + ax_title_text = ax.set_title(u'log(lambada) and regession') + ax_xlabel_text = ax.set_xlabel(u'log(lambada)') + ax_ylabel_text = ax.set_ylabel(u'regression') + plt.setp(ax_title_text, size = 20, weight = 'bold', color = 'red') + plt.setp(ax_xlabel_text, size = 10, weight = 'bold', color = 'black') + plt.setp(ax_ylabel_text, size = 10, weight = 'bold', color = 'black') + plt.show() + + +def regularize(xMat, yMat): + """ + 函数说明:数据标准化 + Parameters: + xMat - x数据集 + yMat - y数据集 + Returns: + inxMat - 标准化后的x数据集 + inyMat - 标准化后的y数据集 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-12-03 + """ + inxMat = xMat.copy() #数据拷贝 + inyMat = yMat.copy() + yMean = np.mean(yMat, 0) #行与行操作,求均值 + inyMat = yMat - yMean #数据减去均值 + inMeans = np.mean(inxMat, 0) #行与行操作,求均值 + inVar = np.var(inxMat, 0) #行与行操作,求方差 + inxMat = (inxMat - inMeans) / inVar #数据减去均值除以方差实现标准化 + return inxMat, inyMat + +def rssError(yArr,yHatArr): + """ + 函数说明:计算平方误差 + Parameters: + yArr - 预测值 + yHatArr - 真实值 + Returns: + + Website: + http://www.cuijiahua.com/ + Modify: + 2017-12-03 + """ + return ((yArr-yHatArr)**2).sum() + +def stageWise(xArr, yArr, eps = 0.01, numIt = 100): + """ + 函数说明:前向逐步线性回归 + Parameters: + xArr - x输入数据 + yArr - y预测数据 + eps - 每次迭代需要调整的步长 + numIt - 迭代次数 + Returns: + returnMat - numIt次迭代的回归系数矩阵 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-12-03 + """ + xMat = np.mat(xArr); yMat = np.mat(yArr).T #数据集 + xMat, yMat = regularize(xMat, yMat) #数据标准化 + m, n = np.shape(xMat) + returnMat = np.zeros((numIt, n)) #初始化numIt次迭代的回归系数矩阵 + ws = np.zeros((n, 1)) #初始化回归系数矩阵 + wsTest = ws.copy() + wsMax = ws.copy() + for i in range(numIt): #迭代numIt次 + # print(ws.T) #打印当前回归系数矩阵 + lowestError = float('inf'); #正无穷 + for j in range(n): #遍历每个特征的回归系数 + for sign in [-1, 1]: + wsTest = ws.copy() + wsTest[j] += eps * sign #微调回归系数 + yTest = xMat * wsTest #计算预测值 + rssE = rssError(yMat.A, yTest.A) #计算平方误差 + if rssE < lowestError: #如果误差更小,则更新当前的最佳回归系数 + lowestError = rssE + wsMax = wsTest + ws = wsMax.copy() + returnMat[i,:] = ws.T #记录numIt次迭代的回归系数矩阵 + return returnMat + +def plotstageWiseMat(): + """ + 函数说明:绘制岭回归系数矩阵 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-12-03 + """ + #font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14) + xArr, yArr = loadDataSet('abalone.txt') + returnMat = stageWise(xArr, yArr, 0.005, 1000) + fig = plt.figure() + ax = fig.add_subplot(111) + ax.plot(returnMat) + ax_title_text = ax.set_title(u'front regression') + ax_xlabel_text = ax.set_xlabel(u'regression') + ax_ylabel_text = ax.set_ylabel(u'regression coefficient') + plt.setp(ax_title_text, size = 15, weight = 'bold', color = 'red') + plt.setp(ax_xlabel_text, size = 10, weight = 'bold', color = 'black') + plt.setp(ax_ylabel_text, size = 10, weight = 'bold', color = 'black') + plt.show() + + +if __name__ == '__main__': + plotstageWiseMat() diff --git a/regression/regression_old.py b/regression/regression_old.py new file mode 100755 index 0000000..4605299 --- /dev/null +++ b/regression/regression_old.py @@ -0,0 +1,198 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +from matplotlib.font_manager import FontProperties +import matplotlib.pyplot as plt +import numpy as np + +def loadDataSet(fileName): + """ + 函数说明:加载数据 + Parameters: + fileName - 文件名 + Returns: + xArr - x数据集 + yArr - y数据集 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-12 + """ + numFeat = len(open(fileName).readline().split('\t')) - 1 + xArr = []; yArr = [] + fr = open(fileName) + for line in fr.readlines(): + lineArr =[] + curLine = line.strip().split('\t') + for i in range(numFeat): + lineArr.append(float(curLine[i])) + xArr.append(lineArr) + yArr.append(float(curLine[-1])) + return xArr, yArr + +def standRegres(xArr,yArr): + """ + 函数说明:计算回归系数w + Parameters: + xArr - x数据集 + yArr - y数据集 + Returns: + ws - 回归系数 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-12 + """ + xMat = np.mat(xArr); yMat = np.mat(yArr).T + xTx = xMat.T * xMat #根据文中推导的公示计算回归系数 + if np.linalg.det(xTx) == 0.0: + print("矩阵为奇异矩阵,不能求逆") + return + ws = xTx.I * (xMat.T*yMat) + return ws + + +def plotDataSet(): + """ + 函数说明:绘制数据集 + Parameters: + 无 + Returns: + 无 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-12 + """ + xArr, yArr = loadDataSet('ex0.txt') #加载数据集 + n = len(xArr) #数据个数 + xcord = []; ycord = [] #样本点 + for i in range(n): + xcord.append(xArr[i][1]); ycord.append(yArr[i]) #样本点 + fig = plt.figure() + ax = fig.add_subplot(111) #添加subplot + ax.scatter(xcord, ycord, s = 20, c = 'blue',alpha = .5) #绘制样本点 + plt.title('DataSet') #绘制title + plt.xlabel('X') + plt.show() + +def plotRegression(): + """ + 函数说明:绘制回归曲线和数据点 + Parameters: + 无 + Returns: + 无 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-12 + """ + xArr, yArr = loadDataSet('ex0.txt') #加载数据集 + ws = standRegres(xArr, yArr) #计算回归系数 + xMat = np.mat(xArr) #创建xMat矩阵 + yMat = np.mat(yArr) #创建yMat矩阵 + xCopy = xMat.copy() #深拷贝xMat矩阵 + xCopy.sort(0) #排序 + yHat = xCopy * ws #计算对应的y值 + fig = plt.figure() + ax = fig.add_subplot(111) #添加subplot + ax.plot(xCopy[:, 1], yHat, c = 'red') #绘制回归曲线 + ax.scatter(xMat[:,1].flatten().A[0], yMat.flatten().A[0], s = 20, c = 'blue',alpha = .5) #绘制样本点 + plt.title('DataSet') #绘制title + plt.xlabel('X') + plt.show() + +def plotlwlrRegression(): + """ + 函数说明:绘制多条局部加权回归曲线 + Parameters: + 无 + Returns: + 无 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-15 + """ + #font = FontProperties(fname=r"c:\windows\fonts\simsun.ttc", size=14) + xArr, yArr = loadDataSet('ex0.txt') #加载数据集 + yHat_1 = lwlrTest(xArr, xArr, yArr, 1.0) #根据局部加权线性回归计算yHat + yHat_2 = lwlrTest(xArr, xArr, yArr, 0.01) #根据局部加权线性回归计算yHat + yHat_3 = lwlrTest(xArr, xArr, yArr, 0.003) #根据局部加权线性回归计算yHat + xMat = np.mat(xArr) #创建xMat矩阵 + yMat = np.mat(yArr) #创建yMat矩阵 + srtInd = xMat[:, 1].argsort(0) #排序,返回索引值 + xSort = xMat[srtInd][:,0,:] + fig, axs = plt.subplots(nrows=3, ncols=1,sharex=False, sharey=False, figsize=(10,8)) + + axs[0].plot(xSort[:, 1], yHat_1[srtInd], c = 'red') #绘制回归曲线 + axs[1].plot(xSort[:, 1], yHat_2[srtInd], c = 'red') #绘制回归曲线 + axs[2].plot(xSort[:, 1], yHat_3[srtInd], c = 'red') #绘制回归曲线 + axs[0].scatter(xMat[:,1].flatten().A[0], yMat.flatten().A[0], s = 20, c = 'blue', alpha = .5) #绘制样本点 + axs[1].scatter(xMat[:,1].flatten().A[0], yMat.flatten().A[0], s = 20, c = 'blue', alpha = .5) #绘制样本点 + axs[2].scatter(xMat[:,1].flatten().A[0], yMat.flatten().A[0], s = 20, c = 'blue', alpha = .5) #绘制样本点 + + #设置标题,x轴label,y轴label + axs0_title_text = axs[0].set_title(u'Locally weighted regression curve,k=1.0') + axs1_title_text = axs[1].set_title(u'Locally weighted regression curve,k=0.01') + axs2_title_text = axs[2].set_title(u'Locally weighted regression curve,k=0.003') + + plt.setp(axs0_title_text, size=8, weight='bold', color='red') + plt.setp(axs1_title_text, size=8, weight='bold', color='red') + plt.setp(axs2_title_text, size=8, weight='bold', color='red') + + plt.xlabel('X') + plt.show() + +def lwlr(testPoint, xArr, yArr, k = 1.0): + """ + 函数说明:使用局部加权线性回归计算回归系数w + Parameters: + testPoint - 测试样本点 + xArr - x数据集 + yArr - y数据集 + k - 高斯核的k,自定义参数 + Returns: + ws - 回归系数 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-15 + """ + xMat = np.mat(xArr); yMat = np.mat(yArr).T + m = np.shape(xMat)[0] + weights = np.mat(np.eye((m))) #创建权重对角矩阵 + for j in range(m): #遍历数据集计算每个样本的权重 + diffMat = testPoint - xMat[j, :] + weights[j, j] = np.exp(diffMat * diffMat.T/(-2.0 * k**2)) + xTx = xMat.T * (weights * xMat) + if np.linalg.det(xTx) == 0.0: + print("矩阵为奇异矩阵,不能求逆") + return + ws = xTx.I * (xMat.T * (weights * yMat)) #计算回归系数 + return testPoint * ws + +def lwlrTest(testArr, xArr, yArr, k=1.0): + """ + 函数说明:局部加权线性回归测试 + Parameters: + testArr - 测试数据集 + xArr - x数据集 + yArr - y数据集 + k - 高斯核的k,自定义参数 + Returns: + ws - 回归系数 + Website: + http://www.cuijiahua.com/ + Modify: + 2017-11-15 + """ + m = np.shape(testArr)[0] #计算测试数据集大小 + yHat = np.zeros(m) + for i in range(m): #对每个样本点进行预测 + yHat[i] = lwlr(testArr[i],xArr,yArr,k) + return yHat + + +if __name__ == '__main__': + plotlwlrRegression() diff --git a/regression/testSet.txt b/regression/testSet.txt new file mode 100644 index 0000000..f2f9024 --- /dev/null +++ b/regression/testSet.txt @@ -0,0 +1,100 @@ +-0.017612 14.053064 0 +-1.395634 4.662541 1 +-0.752157 6.538620 0 +-1.322371 7.152853 0 +0.423363 11.054677 0 +0.406704 7.067335 1 +0.667394 12.741452 0 +-2.460150 6.866805 1 +0.569411 9.548755 0 +-0.026632 10.427743 0 +0.850433 6.920334 1 +1.347183 13.175500 0 +1.176813 3.167020 1 +-1.781871 9.097953 0 +-0.566606 5.749003 1 +0.931635 1.589505 1 +-0.024205 6.151823 1 +-0.036453 2.690988 1 +-0.196949 0.444165 1 +1.014459 5.754399 1 +1.985298 3.230619 1 +-1.693453 -0.557540 1 +-0.576525 11.778922 0 +-0.346811 -1.678730 1 +-2.124484 2.672471 1 +1.217916 9.597015 0 +-0.733928 9.098687 0 +-3.642001 -1.618087 1 +0.315985 3.523953 1 +1.416614 9.619232 0 +-0.386323 3.989286 1 +0.556921 8.294984 1 +1.224863 11.587360 0 +-1.347803 -2.406051 1 +1.196604 4.951851 1 +0.275221 9.543647 0 +0.470575 9.332488 0 +-1.889567 9.542662 0 +-1.527893 12.150579 0 +-1.185247 11.309318 0 +-0.445678 3.297303 1 +1.042222 6.105155 1 +-0.618787 10.320986 0 +1.152083 0.548467 1 +0.828534 2.676045 1 +-1.237728 10.549033 0 +-0.683565 -2.166125 1 +0.229456 5.921938 1 +-0.959885 11.555336 0 +0.492911 10.993324 0 +0.184992 8.721488 0 +-0.355715 10.325976 0 +-0.397822 8.058397 0 +0.824839 13.730343 0 +1.507278 5.027866 1 +0.099671 6.835839 1 +-0.344008 10.717485 0 +1.785928 7.718645 1 +-0.918801 11.560217 0 +-0.364009 4.747300 1 +-0.841722 4.119083 1 +0.490426 1.960539 1 +-0.007194 9.075792 0 +0.356107 12.447863 0 +0.342578 12.281162 0 +-0.810823 -1.466018 1 +2.530777 6.476801 1 +1.296683 11.607559 0 +0.475487 12.040035 0 +-0.783277 11.009725 0 +0.074798 11.023650 0 +-1.337472 0.468339 1 +-0.102781 13.763651 0 +-0.147324 2.874846 1 +0.518389 9.887035 0 +1.015399 7.571882 0 +-1.658086 -0.027255 1 +1.319944 2.171228 1 +2.056216 5.019981 1 +-0.851633 4.375691 1 +-1.510047 6.061992 0 +-1.076637 -3.181888 1 +1.821096 10.283990 0 +3.010150 8.401766 1 +-1.099458 1.688274 1 +-0.834872 -1.733869 1 +-0.846637 3.849075 1 +1.400102 12.628781 0 +1.752842 5.468166 1 +0.078557 0.059736 1 +0.089392 -0.715300 1 +1.825662 12.693808 0 +0.197445 9.744638 0 +0.126117 0.922311 1 +-0.679797 1.220530 1 +0.677983 2.556666 1 +0.761349 10.693862 0 +-2.168791 0.143632 1 +1.388610 9.341997 0 +0.317029 14.739025 0 diff --git a/regression/线性模型.md b/regression/线性模型.md new file mode 100644 index 0000000..81bee61 --- /dev/null +++ b/regression/线性模型.md @@ -0,0 +1,96 @@ +# 线性回归 +线性回归问题就是试图学到一个线性模型尽可能准确地预测新样本的输出值,例如:通过历年的人口数据预测2017年人口数量。 + +有时这些输入的属性值并不能直接被我们的学习模型所用,需要进行相应的处理,对于连续值的属性,一般都可以被学习器所用,有时 +会根据具体的情形作相应的预处理,例如:归一化等;对于离散值的属性,可作下面的处理: +- 若属性值之间存在“序关系”,则可以将其转化为连续值,例如:身高属性分为“高”“中等”“矮”,可转化为数值:{1, 0.5, 0}。 +- 若属性值之间不存在“序关系”,则通常将其转化为向量的形式,例如:性别属性分为“男”“女”,可转化为二维向量:{(1,0),(0,1)}。 + + +(1) 当输入属性只有一个的时候,就是最简单的情形,也就是我们高中时最熟悉的“最小二乘法”(Euclidean distance),首先计算出每个样 +本预测值与真实值之间的误差并求和,通过最小化均方误差MSE,使用求偏导等于零的方法计算出拟合直线y=wx+b的两个参数w和b,计算 +过程如下图所示: +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/1.png) + +(2) 当输入属性有多个的时候,例如对于一个样本有d个属性{(x1,x2...xd),y},则y=wx+b需要写成:
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/2.png)
    +通常对于多元问题,常常使用矩阵的形式来表示数据。在本问题中,将具有m个样本的数据集表示成矩阵X,将系数w与b合并成一个列向 +量,这样每个样本的预测值以及所有样本的均方误差最小化就可以写成下面的形式:
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/4.png)
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/3.png)
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/5.png)
    + +同样地,我们使用最小二乘法对w和b进行估计,令均方误差的求导等于0,需要注意的是,当一个矩阵的行列式不等于0时,我们才可能 +对其求逆,因此对于下式,我们需要考虑矩阵(X的转置*X)的行列式是否为0,若不为0,则可以求出其解,若为0,则需要使用其它的 +方法进行计算,书中提到了引入正则化
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/6.png)
    + +另一方面,有时像上面这种原始的线性回归可能并不能满足需求,例如:y值并不是线性变化,而是在指数尺度上变化。这时我们可以采 +用线性模型来逼近y的衍生物,例如lny,这时衍生的线性模型如下所示,实际上就是相当于将指数曲线投影在一条直线上,如下图所示:
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/7.png)
    + +更一般地,考虑所有y的衍生物的情形,就得到了“广义的线性模型”(generalized linear model),其中,g(*)称为联系函数(link +function)。
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/8.png)
    + +# 对数几率函数 +回归就是通过输入的属性值得到一个预测值,利用上述广义线性模型的特征,是否可以通过一个联系函数,将预测值转化为离散值从而 +进行分类呢?线性几率回归正是研究这样的问题。对数几率引入了一个对数几率函数(logistic function),将预测值投影到0-1之间, +从而将线性回归问题转化为二分类问题。
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/9.png)
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/10.png)
    + +若将y看做样本为正例的概率,(1-y)看做样本为反例的概率,则上式实际上使用线性回归模型的预测结果器逼近真实标记的对数几率。 +因此这个模型称为“对数几率回归”(logistic regression),也有一些书籍称之为“逻辑回归”。下面使用最大似然估计的方法来计算出 +w和b两个参数的取值,下面只列出求解的思路,不列出具体的计算过程。
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/11.png)
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/12.png)
    + +# 线性判别分析 +线性判别分析(Linear Discriminant Analysis,简称LDA),其基本思想是:将训练样本投影到一条直线上,使得同类的样例尽可能近, +不同类的样例尽可能远。如图所示:
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/13.png)
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/14.png)
    +想让同类样本点的投影点尽可能接近,不同类样本点投影之间尽可能远,即:让各类的协方差之和尽可能小,不用类之间中心的距离尽 +可能大。基于这样的考虑,LDA定义了两个散度矩阵。
    +- 类内散度矩阵(within-class scatter matrix) +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/15.png)
    +- 类间散度矩阵(between-class scaltter matrix)
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/20170415112712139.png)
    +因此得到了LDA的最大化目标:“广义瑞利商”(generalized Rayleigh quotient)。
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/20170415112712138.png)
    + +从而分类问题转化为最优化求解w的问题,当求解出w后,对新的样本进行分类时,只需将该样本点投影到这条直线上,根据与各个类别 +的中心值进行比较,从而判定出新样本与哪个类别距离最近。求解w的方法如下所示,使用的方法为λ乘子。
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/20170415112712140.png)
    +若将w看做一个投影矩阵,类似PCA的思想,则LDA可将样本投影到N-1维空间(N为类簇数),投影的过程使用了类别信息(标记信息), +因此LDA也常被视为一种经典的监督降维技术。 + +# 多分类学习(不太明白) + +现实中我们经常遇到不只两个类别的分类问题,即多分类问题,在这种情形下,我们常常运用“拆分”的策略,通过多个二分类学习器来解 +决多分类问题,即将多分类问题拆解为多个二分类问题,训练出多个二分类学习器,最后将多个分类结果进行集成得出结论。最为经典的 +拆分策略有三种:“一对一”(OvO)、“一对其余”(OvR)和“多对多”(MvM),核心思想与示意图如下所示。 + +- OvO:给定数据集D,假定其中有N个真实类别,将这N个类别进行两两配对(一个正类/一个反类),从而产生N(N-1)/2个二分类学习 + 器,在测试阶段,将新样本放入所有的二分类学习器中测试,得出N(N-1)个结果,最终通过投票产生最终的分类结果。 +- OvM:给定数据集D,假定其中有N个真实类别,每次取出一个类作为正类,剩余的所有类别作为一个新的反类,从而产生N个二分类学 + 习器,在测试阶段,得出N个结果,若仅有一个学习器预测为正类,则对应的类标作为最终分类结果。 +- MvM:给定数据集D,假定其中有N个真实类别,每次取若干个类作为正类,若干个类作为反类(通过ECOC码给出,编码),若进行了M次 + 划分,则生成了M个二分类学习器,在测试阶段(解码),得出M个结果组成一个新的码,最终通过计算海明/欧式距离选择距离最小的 + 类别作为最终分类结果。 + +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/20170415112712141.png)
    +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/20170415112712142.png)
    + +# 类别不平衡问题(不太明白) + +类别不平衡(class-imbanlance)就是指分类问题中不同类别的训练样本相差悬殊的情况,例如正例有900个,而反例只有100个,这个时 +候我们就需要进行相应的处理来平衡这个问题。常见的做法有三种: + +- 在训练样本较多的类别中进行“欠采样”(undersampling),比如从正例中采出100个,常见的算法有:EasyEnsemble。 +- 在训练样本较少的类别中进行“过采样”(oversampling),例如通过对反例中的数据进行插值,来产生额外的反例,常见的算法有SMOTE。 +- 直接基于原数据集进行学习,对预测值进行“再缩放”处理。其中再缩放也是代价敏感学习的基础。 + +![一元线性](http://index.zeekling.cn/gogsPics/ml/regression/20170415112712143.png)
    + diff --git a/rl/README.md b/rl/README.md new file mode 100644 index 0000000..1053fc5 --- /dev/null +++ b/rl/README.md @@ -0,0 +1,57 @@ +# 强化学习 + +[强化学习详解讲解](https://morvanzhou.github.io/tutorials/machine-learning/reinforcement-learning/) + +## 强化学习的特点 + +- 基本是以一个闭环形式 +- 不会直接指示哪种行为 +- 一系列的actions和奖励信号都会影响之后较长时间 + +## 定义 +它主要包含四个元素,agent,环境状态,行动,奖励, 强化学习的目标就是获得最多的累计奖励。 +我们列举几个形象的例子: 小孩想要走路,但在这之前,他需要先站起来,站起来之后还要保持平衡,接下来还要先迈出一条腿,是左 +腿还是右腿,迈出一步后还要迈出下一步。 小孩就是 agent,他试图通过采取行动(即行走)来操纵环境(行走的表面),并且从一个 +状态转变到另一个状态(即他走的每一步),当他完成任务的子任务(即走了几步)时,孩子得到奖励(给巧克力吃),并且当他不能 +走路时,就不会给巧克力。 + +![pic](http://www.zeekling.cn/gogsPics/ml/rl/1.png) + +上图中agent代表自身,如果是自动驾驶,agent就是车;无人驾驶的action就是车左转、右转或刹车等等,它无时无刻都在与环境产生交 +互,action会反馈给环境,进而改变环境; + +反馈又两种方式: +- 做的好(reward)即正反馈 +- 做得不好(punishment惩罚)即负反馈 + +Agent可能做得好,也可能做的不好,环境始终都会给它反馈,agent会尽量去做对自身有利的决策,通过反反复复这样的一个循环, +agent会越来越做的好,就像孩子在成长过程中会逐渐明辨是非,这就是强化学习。 + +## 强化学习和监督式学习、非监督式学习的区别 + +当前的机器学习算法可以分为3种:有监督的学习(Supervised Learning)、无监督的学习(Unsupervised Learning)和强化学习 +(Reinforcement Learning),结构图如下所示: + +![pic](http://www.zeekling.cn/gogsPics/ml/rl/2.png) + +### 强化学习和监督式学习的区别 + +监督式学习就好比你在学习的时候,有一个导师在旁边指点,他知道怎么是对的怎么是错的,但在很多实际问题中,例如 chess,go, +这种有成千上万种组合方式的情况,不可能有一个导师知道所有可能的结果。 + +而这时,强化学习会在没有任何标签的情况下,通过先尝试做出一些行为得到一个结果,通过这个结果是对还是错的反馈,调整之前的行 +为,就这样不断的调整,算法能够学习到在什么样的情况下选择什么样的行为可以得到最好的结果。 + + +## 强化学习主要有哪些算法 + +强化学习不需要监督信号,可以在模型未知的环境中平衡探索和利用, 其主要算法有蒙特卡罗强化学习, 时间差分(temporal difference: +TD)学习, 策略梯度等。典型的深度强化学习算法特点及性能比较如下图所示: + +![pic](http://www.zeekling.cn/gogsPics/ml/rl/3.png) + +除了上述深度强化学习算法,还有深度迁移强化学习、分层深度强化学习、深度记忆强化学习以及多智能体强化学习等算法。 + + + + diff --git a/sitmap-generator.py b/sitmap-generator.py new file mode 100755 index 0000000..1214b95 --- /dev/null +++ b/sitmap-generator.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +import os +from xml.dom.minidom import Document +import time + + +html_path = '_book' +http_path = 'http://www.zeekling.cn/book/ml' +site_map_name = 'ml.xml' + + +def dirlist(path, all_file): + file_list = os.listdir(path) + for file_name in file_list: + file_path = os.path.join(path, file_name) + if os.path.isdir(file_path): + if str(file_path).endswith('gitbook'): + continue + all_file.append(file_path + '/') + dirlist(file_path, all_file) + else: + all_file.append(file_path) + + return all_file + + +def write_xml(url_paths): + doc = Document() + doc.encoding = 'UTF-8' + url_set = doc.createElement('urlset') + doc.appendChild(url_set) + url_set.setAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9') + date_str = time.strftime('%Y-%m-%d', time.localtime()) + for url_path in url_paths: + url = doc.createElement('url') + url_set.appendChild(url) + loc = doc.createElement('loc') + loc_value = doc.createTextNode(url_path) + loc.appendChild(loc_value) + changefreq = doc.createElement('changefreq') + freq_value = doc.createTextNode('weekly') + changefreq.appendChild(freq_value) + priority = doc.createElement('priority') + prio_value = doc.createTextNode('0.8') + priority.appendChild(prio_value) + lastmod = doc.createElement('lastmod') + mode_value = doc.createTextNode(date_str) + lastmod.appendChild(mode_value) + url.appendChild(loc) + url.appendChild(changefreq) + url.appendChild(priority) + url.appendChild(lastmod) + path = os.getcwd() + '/' + site_map_name + f = open(path, 'w') + f.write(doc.toprettyxml(indent=' ')) + f.close() + + +if __name__ == '__main__': + pwd = os.getcwd() + '/' + html_path + all_file = [] + all_file = dirlist(pwd, all_file) + all_html_file = [] + for file_name in all_file: + file_name = str(file_name) + if file_name.endswith('.html') or file_name.endswith('/'): + html_name = file_name.replace(pwd, http_path) + all_html_file.append(html_name) + + write_xml(all_html_file) + diff --git a/svm/README.md b/svm/README.md new file mode 100644 index 0000000..80812dc --- /dev/null +++ b/svm/README.md @@ -0,0 +1,13 @@ +# 支持向量机 + +## 相关数学知识 +1. [核函数](https://www.jianshu.com/p/a3d9f75546b3) +2. [凸优化](https://blog.csdn.net/qq_39422642/article/details/78816637) https://blog.csdn.net/qq_39422642/article/details/78816637 + +## 线性可区分和线性不可区分 + + +## 超平面 +![超平面公式](http://index.zeekling.cn/gogsPics/ml/supportVectorMachine/20170817153338491.png) + + diff --git a/svm/svm-digits.py b/svm/svm-digits.py new file mode 100755 index 0000000..c19ee6b --- /dev/null +++ b/svm/svm-digits.py @@ -0,0 +1,329 @@ +# -*-coding:utf-8 -*- +import matplotlib.pyplot as plt +import numpy as np +import random + +""" +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-10-03 +""" + +class optStruct: + """ + 数据结构,维护所有需要操作的值 + Parameters: + dataMatIn - 数据矩阵 + classLabels - 数据标签 + C - 松弛变量 + toler - 容错率 + kTup - 包含核函数信息的元组,第一个参数存放核函数类别,第二个参数存放必要的核函数需要用到的参数 + """ + def __init__(self, dataMatIn, classLabels, C, toler, kTup): + self.X = dataMatIn #数据矩阵 + self.labelMat = classLabels #数据标签 + self.C = C #松弛变量 + self.tol = toler #容错率 + self.m = np.shape(dataMatIn)[0] #数据矩阵行数 + self.alphas = np.mat(np.zeros((self.m,1))) #根据矩阵行数初始化alpha参数为0 + self.b = 0 #初始化b参数为0 + self.eCache = np.mat(np.zeros((self.m,2))) #根据矩阵行数初始化虎误差缓存,第一列为是否有效的标志位,第二列为实际的误差E的值。 + self.K = np.mat(np.zeros((self.m,self.m))) #初始化核K + for i in range(self.m): #计算所有数据的核K + self.K[:,i] = kernelTrans(self.X, self.X[i,:], kTup) + +def kernelTrans(X, A, kTup): + """ + 通过核函数将数据转换更高维的空间 + Parameters: + X - 数据矩阵 + A - 单个数据的向量 + kTup - 包含核函数信息的元组 + Returns: + K - 计算的核K + """ + m,n = np.shape(X) + K = np.mat(np.zeros((m,1))) + if kTup[0] == 'lin': K = X * A.T #线性核函数,只进行内积。 + elif kTup[0] == 'rbf': #高斯核函数,根据高斯核函数公式进行计算 + for j in range(m): + deltaRow = X[j,:] - A + K[j] = deltaRow*deltaRow.T + K = np.exp(K/(-1*kTup[1]**2)) #计算高斯核K + else: raise NameError('核函数无法识别') + return K #返回计算的核K + +def loadDataSet(fileName): + """ + 读取数据 + Parameters: + 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 + +def calcEk(oS, k): + """ + 计算误差 + Parameters: + oS - 数据结构 + k - 标号为k的数据 + Returns: + Ek - 标号为k的数据误差 + """ + fXk = float(np.multiply(oS.alphas,oS.labelMat).T*oS.K[:,k] + oS.b) + Ek = fXk - float(oS.labelMat[k]) + return Ek + +def selectJrand(i, m): + """ + 函数说明:随机选择alpha_j的索引值 + + Parameters: + i - alpha_i的索引值 + m - alpha参数个数 + Returns: + j - alpha_j的索引值 + """ + j = i #选择一个不等于i的j + while (j == i): + j = int(random.uniform(0, m)) + return j + +def selectJ(i, oS, Ei): + """ + 内循环启发方式2 + Parameters: + i - 标号为i的数据的索引值 + oS - 数据结构 + Ei - 标号为i的数据误差 + Returns: + j, maxK - 标号为j或maxK的数据的索引值 + Ej - 标号为j的数据误差 + """ + maxK = -1; maxDeltaE = 0; Ej = 0 #初始化 + oS.eCache[i] = [1,Ei] #根据Ei更新误差缓存 + validEcacheList = np.nonzero(oS.eCache[:,0].A)[0] #返回误差不为0的数据的索引值 + if (len(validEcacheList)) > 1: #有不为0的误差 + for k in validEcacheList: #遍历,找到最大的Ek + if k == i: continue #不计算i,浪费时间 + Ek = calcEk(oS, k) #计算Ek + deltaE = abs(Ei - Ek) #计算|Ei-Ek| + if (deltaE > maxDeltaE): #找到maxDeltaE + maxK = k; maxDeltaE = deltaE; Ej = Ek + return maxK, Ej #返回maxK,Ej + else: #没有不为0的误差 + j = selectJrand(i, oS.m) #随机选择alpha_j的索引值 + Ej = calcEk(oS, j) #计算Ej + return j, Ej #j,Ej + +def updateEk(oS, k): + """ + 计算Ek,并更新误差缓存 + Parameters: + oS - 数据结构 + k - 标号为k的数据的索引值 + Returns: + 无 + """ + Ek = calcEk(oS, k) #计算Ek + oS.eCache[k] = [1,Ek] #更新误差缓存 + + +def clipAlpha(aj,H,L): + """ + 修剪alpha_j + Parameters: + aj - alpha_j的值 + H - alpha上限 + L - alpha下限 + Returns: + aj - 修剪后的alpah_j的值 + """ + if aj > H: + aj = H + if L > aj: + aj = L + return aj + +def innerL(i, oS): + """ + 优化的SMO算法 + Parameters: + i - 标号为i的数据的索引值 + oS - 数据结构 + Returns: + 1 - 有任意一对alpha值发生变化 + 0 - 没有任意一对alpha值发生变化或变化太小 + """ + #步骤1:计算误差Ei + Ei = calcEk(oS, i) + #优化alpha,设定一定的容错率。 + if ((oS.labelMat[i] * Ei < -oS.tol) and (oS.alphas[i] < oS.C)) or ((oS.labelMat[i] * Ei > oS.tol) and (oS.alphas[i] > 0)): + #使用内循环启发方式2选择alpha_j,并计算Ej + j,Ej = selectJ(i, oS, Ei) + #保存更新前的aplpha值,使用深拷贝 + alphaIold = oS.alphas[i].copy(); alphaJold = oS.alphas[j].copy(); + #步骤2:计算上下界L和H + if (oS.labelMat[i] != oS.labelMat[j]): + L = max(0, oS.alphas[j] - oS.alphas[i]) + H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i]) + else: + L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C) + H = min(oS.C, oS.alphas[j] + oS.alphas[i]) + if L == H: + print("L==H") + return 0 + #步骤3:计算eta + eta = 2.0 * oS.K[i,j] - oS.K[i,i] - oS.K[j,j] + if eta >= 0: + print("eta>=0") + return 0 + #步骤4:更新alpha_j + oS.alphas[j] -= oS.labelMat[j] * (Ei - Ej)/eta + #步骤5:修剪alpha_j + oS.alphas[j] = clipAlpha(oS.alphas[j],H,L) + #更新Ej至误差缓存 + updateEk(oS, j) + if (abs(oS.alphas[j] - alphaJold) < 0.00001): + print("alpha_j变化太小") + return 0 + #步骤6:更新alpha_i + oS.alphas[i] += oS.labelMat[j]*oS.labelMat[i]*(alphaJold - oS.alphas[j]) + #更新Ei至误差缓存 + updateEk(oS, i) + #步骤7:更新b_1和b_2 + b1 = oS.b - Ei- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.K[i,i] - oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.K[i,j] + b2 = oS.b - Ej- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.K[i,j]- oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.K[j,j] + #步骤8:根据b_1和b_2更新b + if (0 < oS.alphas[i]) and (oS.C > oS.alphas[i]): oS.b = b1 + elif (0 < oS.alphas[j]) and (oS.C > oS.alphas[j]): oS.b = b2 + else: oS.b = (b1 + b2)/2.0 + return 1 + else: + return 0 + +def smoP(dataMatIn, classLabels, C, toler, maxIter, kTup = ('lin',0)): + """ + 完整的线性SMO算法 + Parameters: + dataMatIn - 数据矩阵 + classLabels - 数据标签 + C - 松弛变量 + toler - 容错率 + maxIter - 最大迭代次数 + kTup - 包含核函数信息的元组 + Returns: + oS.b - SMO算法计算的b + oS.alphas - SMO算法计算的alphas + """ + oS = optStruct(np.mat(dataMatIn), np.mat(classLabels).transpose(), C, toler, kTup) #初始化数据结构 + iter = 0 #初始化当前迭代次数 + entireSet = True; alphaPairsChanged = 0 + while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)): #遍历整个数据集都alpha也没有更新或者超过最大迭代次数,则退出循环 + alphaPairsChanged = 0 + if entireSet: #遍历整个数据集 + for i in range(oS.m): + alphaPairsChanged += innerL(i,oS) #使用优化的SMO算法 + print("全样本遍历:第%d次迭代 样本:%d, alpha优化次数:%d" % (iter,i,alphaPairsChanged)) + iter += 1 + else: #遍历非边界值 + nonBoundIs = np.nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0] #遍历不在边界0和C的alpha + for i in nonBoundIs: + alphaPairsChanged += innerL(i,oS) + print("非边界遍历:第%d次迭代 样本:%d, alpha优化次数:%d" % (iter,i,alphaPairsChanged)) + iter += 1 + if entireSet: #遍历一次后改为非边界遍历 + entireSet = False + elif (alphaPairsChanged == 0): #如果alpha没有更新,计算全样本遍历 + entireSet = True + print("迭代次数: %d" % iter) + return oS.b,oS.alphas #返回SMO算法计算的b和alphas + + +def img2vector(filename): + """ + 将32x32的二进制图像转换为1x1024向量。 + Parameters: + filename - 文件名 + Returns: + returnVect - 返回的二进制图像的1x1024向量 + """ + 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 loadImages(dirName): + """ + 加载图片 + Parameters: + dirName - 文件夹的名字 + Returns: + trainingMat - 数据矩阵 + hwLabels - 数据标签 + """ + from os import listdir + hwLabels = [] + trainingFileList = listdir(dirName) + 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]) + if classNumStr == 9: hwLabels.append(-1) + else: hwLabels.append(1) + trainingMat[i,:] = img2vector('%s/%s' % (dirName, fileNameStr)) + return trainingMat, hwLabels + +def testDigits(kTup=('rbf', 10)): + """ + 测试函数 + Parameters: + kTup - 包含核函数信息的元组 + Returns: + 无 + """ + dataArr,labelArr = loadImages('trainingDigits') + b,alphas = smoP(dataArr, labelArr, 200, 0.0001, 10, kTup) + datMat = np.mat(dataArr); labelMat = np.mat(labelArr).transpose() + svInd = np.nonzero(alphas.A>0)[0] + sVs=datMat[svInd] + labelSV = labelMat[svInd]; + print("支持向量个数:%d" % np.shape(sVs)[0]) + m,n = np.shape(datMat) + errorCount = 0 + for i in range(m): + kernelEval = kernelTrans(sVs,datMat[i,:],kTup) + predict=kernelEval.T * np.multiply(labelSV,alphas[svInd]) + b + if np.sign(predict) != np.sign(labelArr[i]): errorCount += 1 + print("训练集错误率: %.2f%%" % (float(errorCount)/m)) + dataArr,labelArr = loadImages('testDigits') + errorCount = 0 + datMat = np.mat(dataArr); labelMat = np.mat(labelArr).transpose() + m,n = np.shape(datMat) + for i in range(m): + kernelEval = kernelTrans(sVs,datMat[i,:],kTup) + predict=kernelEval.T * np.multiply(labelSV,alphas[svInd]) + b + if np.sign(predict) != np.sign(labelArr[i]): errorCount += 1 + print("测试集错误率: %.2f%%" % (float(errorCount)/m)) + +if __name__ == '__main__': + testDigits() \ No newline at end of file diff --git a/svm/svm-simple.py b/svm/svm-simple.py new file mode 100755 index 0000000..982e151 --- /dev/null +++ b/svm/svm-simple.py @@ -0,0 +1,270 @@ +# -*- coding:UTF-8 -*- +import matplotlib.pyplot as plt +import numpy as np +import random + +""" +函数说明:读取数据 + +Parameters: + fileName - 文件名 +Returns: + dataMat - 数据矩阵 + labelMat - 数据标签 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-09-21 +""" +def loadDataSet(fileName): + 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 + + +""" +函数说明:随机选择alpha + +Parameters: + i - alpha_i的索引值 + m - alpha参数个数 +Returns: + j - alpha_j的索引值 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-09-21 +""" +def selectJrand(i, m): + j = i #选择一个不等于i的j + while (j == i): + j = int(random.uniform(0, m)) + return j + +""" +函数说明:修剪alpha + +Parameters: + aj - alpha_j值 + H - alpha上限 + L - alpha下限 +Returns: + aj - alpah值 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-09-21 +""" +def clipAlpha(aj,H,L): + if aj > H: + aj = H + if L > aj: + aj = L + return aj + +""" +函数说明:数据可视化 + +Parameters: + dataMat - 数据矩阵 + labelMat - 数据标签 +Returns: + 无 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-09-21 +""" +def showDataSet(dataMat, labelMat): + data_plus = [] #正样本 + data_minus = [] #负样本 + for i in range(len(dataMat)): + if labelMat[i] > 0: + data_plus.append(dataMat[i]) + else: + data_minus.append(dataMat[i]) + data_plus_np = np.array(data_plus) #转换为numpy矩阵 + data_minus_np = np.array(data_minus) #转换为numpy矩阵 + plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1]) #正样本散点图 + plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1]) #负样本散点图 + plt.show() + + +""" +函数说明:简化版SMO算法 + +Parameters: + dataMatIn - 数据矩阵 + classLabels - 数据标签 + C - 松弛变量 + toler - 容错率 + maxIter - 最大迭代次数 +Returns: + 无 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-09-23 +""" +def smoSimple(dataMatIn, classLabels, C, toler, maxIter): + #转换为numpy的mat存储 + dataMatrix = np.mat(dataMatIn); labelMat = np.mat(classLabels).transpose() + #初始化b参数,统计dataMatrix的维度 + b = 0; m,n = np.shape(dataMatrix) + #初始化alpha参数,设为0 + alphas = np.mat(np.zeros((m,1))) + #初始化迭代次数 + iter_num = 0 + #最多迭代matIter次 + while (iter_num < maxIter): + alphaPairsChanged = 0 + for i in range(m): + #步骤1:计算误差Ei + fXi = float(np.multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[i,:].T)) + b + Ei = fXi - float(labelMat[i]) + #优化alpha,设定一定的容错率。 + if ((labelMat[i]*Ei < -toler) and (alphas[i] < C)) or ((labelMat[i]*Ei > toler) and (alphas[i] > 0)): + #随机选择另一个与alpha_i成对优化的alpha_j + j = selectJrand(i,m) + #步骤1:计算误差Ej + fXj = float(np.multiply(alphas,labelMat).T*(dataMatrix*dataMatrix[j,:].T)) + b + Ej = fXj - float(labelMat[j]) + #保存更新前的aplpha值,使用深拷贝 + alphaIold = alphas[i].copy(); alphaJold = alphas[j].copy(); + #步骤2:计算上下界L和H + if (labelMat[i] != labelMat[j]): + L = max(0, alphas[j] - alphas[i]) + H = min(C, C + alphas[j] - alphas[i]) + else: + L = max(0, alphas[j] + alphas[i] - C) + H = min(C, alphas[j] + alphas[i]) + if L==H: print("L==H"); continue + #步骤3:计算eta + eta = 2.0 * dataMatrix[i,:]*dataMatrix[j,:].T - dataMatrix[i,:]*dataMatrix[i,:].T - dataMatrix[j,:]*dataMatrix[j,:].T + if eta >= 0: print("eta>=0"); continue + #步骤4:更新alpha_j + alphas[j] -= labelMat[j]*(Ei - Ej)/eta + #步骤5:修剪alpha_j + alphas[j] = clipAlpha(alphas[j],H,L) + if (abs(alphas[j] - alphaJold) < 0.00001): print("alpha_j变化太小"); continue + #步骤6:更新alpha_i + alphas[i] += labelMat[j]*labelMat[i]*(alphaJold - alphas[j]) + #步骤7:更新b_1和b_2 + b1 = b - Ei- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[i,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[i,:]*dataMatrix[j,:].T + b2 = b - Ej- labelMat[i]*(alphas[i]-alphaIold)*dataMatrix[i,:]*dataMatrix[j,:].T - labelMat[j]*(alphas[j]-alphaJold)*dataMatrix[j,:]*dataMatrix[j,:].T + #步骤8:根据b_1和b_2更新b + if (0 < alphas[i]) and (C > alphas[i]): b = b1 + elif (0 < alphas[j]) and (C > alphas[j]): b = b2 + else: b = (b1 + b2)/2.0 + #统计优化次数 + alphaPairsChanged += 1 + #打印统计信息 + print("第%d次迭代 样本:%d, alpha优化次数:%d" % (iter_num,i,alphaPairsChanged)) + #更新迭代次数 + if (alphaPairsChanged == 0): iter_num += 1 + else: iter_num = 0 + print("迭代次数: %d" % iter_num) + return b,alphas + +""" +函数说明:分类结果可视化 + +Parameters: + dataMat - 数据矩阵 + w - 直线法向量 + b - 直线解决 +Returns: + 无 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-09-23 +""" +def showClassifer(dataMat, w, b): + #绘制样本点 + data_plus = [] #正样本 + data_minus = [] #负样本 + for i in range(len(dataMat)): + if labelMat[i] > 0: + data_plus.append(dataMat[i]) + else: + data_minus.append(dataMat[i]) + data_plus_np = np.array(data_plus) #转换为numpy矩阵 + data_minus_np = np.array(data_minus) #转换为numpy矩阵 + plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1], s=30, alpha=0.7) #正样本散点图 + plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1], s=30, alpha=0.7) #负样本散点图 + #绘制直线 + x1 = max(dataMat)[0] + x2 = min(dataMat)[0] + a1, a2 = w + b = float(b) + a1 = float(a1[0]) + a2 = float(a2[0]) + y1, y2 = (-b- a1*x1)/a2, (-b - a1*x2)/a2 + plt.plot([x1, x2], [y1, y2]) + #找出支持向量点 + for i, alpha in enumerate(alphas): + if abs(alpha) > 0: + x, y = dataMat[i] + plt.scatter([x], [y], s=150, c='none', alpha=0.7, linewidth=1.5, edgecolor='red') + plt.show() + + +""" +函数说明:计算w + +Parameters: + dataMat - 数据矩阵 + labelMat - 数据标签 + alphas - alphas值 +Returns: + 无 +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-09-23 +""" +def get_w(dataMat, labelMat, alphas): + alphas, dataMat, labelMat = np.array(alphas), np.array(dataMat), np.array(labelMat) + w = np.dot((np.tile(labelMat.reshape(1, -1).T, (1, 2)) * dataMat).T, alphas) + return w.tolist() + + +if __name__ == '__main__': + dataMat, labelMat = loadDataSet('testSet.txt') + b,alphas = smoSimple(dataMat, labelMat, 0.6, 0.001, 40) + w = get_w(dataMat, labelMat, alphas) + showClassifer(dataMat, w, b) + diff --git a/svm/svm-smo.py b/svm/svm-smo.py new file mode 100755 index 0000000..0130b88 --- /dev/null +++ b/svm/svm-smo.py @@ -0,0 +1,291 @@ +# -*-coding:utf-8 -*- +import matplotlib.pyplot as plt +import numpy as np +import random + +""" +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-10-03 +""" + +class optStruct: + """ + 数据结构,维护所有需要操作的值 + Parameters: + dataMatIn - 数据矩阵 + classLabels - 数据标签 + C - 松弛变量 + toler - 容错率 + """ + def __init__(self, dataMatIn, classLabels, C, toler): + self.X = dataMatIn #数据矩阵 + self.labelMat = classLabels #数据标签 + self.C = C #松弛变量 + self.tol = toler #容错率 + self.m = np.shape(dataMatIn)[0] #数据矩阵行数 + self.alphas = np.mat(np.zeros((self.m,1))) #根据矩阵行数初始化alpha参数为0 + self.b = 0 #初始化b参数为0 + self.eCache = np.mat(np.zeros((self.m,2))) #根据矩阵行数初始化虎误差缓存,第一列为是否有效的标志位,第二列为实际的误差E的值。 + +def loadDataSet(fileName): + """ + 读取数据 + Parameters: + 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 + +def calcEk(oS, k): + """ + 计算误差 + Parameters: + oS - 数据结构 + k - 标号为k的数据 + Returns: + Ek - 标号为k的数据误差 + """ + fXk = float(np.multiply(oS.alphas,oS.labelMat).T*(oS.X*oS.X[k,:].T) + oS.b) + Ek = fXk - float(oS.labelMat[k]) + return Ek + +def selectJrand(i, m): + """ + 函数说明:随机选择alpha_j的索引值 + + Parameters: + i - alpha_i的索引值 + m - alpha参数个数 + Returns: + j - alpha_j的索引值 + """ + j = i #选择一个不等于i的j + while (j == i): + j = int(random.uniform(0, m)) + return j + +def selectJ(i, oS, Ei): + """ + 内循环启发方式2 + Parameters: + i - 标号为i的数据的索引值 + oS - 数据结构 + Ei - 标号为i的数据误差 + Returns: + j, maxK - 标号为j或maxK的数据的索引值 + Ej - 标号为j的数据误差 + """ + maxK = -1; maxDeltaE = 0; Ej = 0 #初始化 + oS.eCache[i] = [1,Ei] #根据Ei更新误差缓存 + validEcacheList = np.nonzero(oS.eCache[:,0].A)[0] #返回误差不为0的数据的索引值 + if (len(validEcacheList)) > 1: #有不为0的误差 + for k in validEcacheList: #遍历,找到最大的Ek + if k == i: continue #不计算i,浪费时间 + Ek = calcEk(oS, k) #计算Ek + deltaE = abs(Ei - Ek) #计算|Ei-Ek| + if (deltaE > maxDeltaE): #找到maxDeltaE + maxK = k; maxDeltaE = deltaE; Ej = Ek + return maxK, Ej #返回maxK,Ej + else: #没有不为0的误差 + j = selectJrand(i, oS.m) #随机选择alpha_j的索引值 + Ej = calcEk(oS, j) #计算Ej + return j, Ej #j,Ej + +def updateEk(oS, k): + """ + 计算Ek,并更新误差缓存 + Parameters: + oS - 数据结构 + k - 标号为k的数据的索引值 + Returns: + 无 + """ + Ek = calcEk(oS, k) #计算Ek + oS.eCache[k] = [1,Ek] #更新误差缓存 + + +def clipAlpha(aj,H,L): + """ + 修剪alpha_j + Parameters: + aj - alpha_j的值 + H - alpha上限 + L - alpha下限 + Returns: + aj - 修剪后的alpah_j的值 + """ + if aj > H: + aj = H + if L > aj: + aj = L + return aj + +def innerL(i, oS): + """ + 优化的SMO算法 + Parameters: + i - 标号为i的数据的索引值 + oS - 数据结构 + Returns: + 1 - 有任意一对alpha值发生变化 + 0 - 没有任意一对alpha值发生变化或变化太小 + """ + #步骤1:计算误差Ei + Ei = calcEk(oS, i) + #优化alpha,设定一定的容错率。 + if ((oS.labelMat[i] * Ei < -oS.tol) and (oS.alphas[i] < oS.C)) or ((oS.labelMat[i] * Ei > oS.tol) and (oS.alphas[i] > 0)): + #使用内循环启发方式2选择alpha_j,并计算Ej + j,Ej = selectJ(i, oS, Ei) + #保存更新前的aplpha值,使用深拷贝 + alphaIold = oS.alphas[i].copy(); alphaJold = oS.alphas[j].copy(); + #步骤2:计算上下界L和H + if (oS.labelMat[i] != oS.labelMat[j]): + L = max(0, oS.alphas[j] - oS.alphas[i]) + H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i]) + else: + L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C) + H = min(oS.C, oS.alphas[j] + oS.alphas[i]) + if L == H: + print("L==H") + return 0 + #步骤3:计算eta + eta = 2.0 * oS.X[i,:] * oS.X[j,:].T - oS.X[i,:] * oS.X[i,:].T - oS.X[j,:] * oS.X[j,:].T + if eta >= 0: + print("eta>=0") + return 0 + #步骤4:更新alpha_j + oS.alphas[j] -= oS.labelMat[j] * (Ei - Ej)/eta + #步骤5:修剪alpha_j + oS.alphas[j] = clipAlpha(oS.alphas[j],H,L) + #更新Ej至误差缓存 + updateEk(oS, j) + if (abs(oS.alphas[j] - alphaJold) < 0.00001): + print("alpha_j变化太小") + return 0 + #步骤6:更新alpha_i + oS.alphas[i] += oS.labelMat[j]*oS.labelMat[i]*(alphaJold - oS.alphas[j]) + #更新Ei至误差缓存 + updateEk(oS, i) + #步骤7:更新b_1和b_2 + b1 = oS.b - Ei- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.X[i,:]*oS.X[i,:].T - oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.X[i,:]*oS.X[j,:].T + b2 = oS.b - Ej- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.X[i,:]*oS.X[j,:].T - oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.X[j,:]*oS.X[j,:].T + #步骤8:根据b_1和b_2更新b + if (0 < oS.alphas[i]) and (oS.C > oS.alphas[i]): oS.b = b1 + elif (0 < oS.alphas[j]) and (oS.C > oS.alphas[j]): oS.b = b2 + else: oS.b = (b1 + b2)/2.0 + return 1 + else: + return 0 + +def smoP(dataMatIn, classLabels, C, toler, maxIter): + """ + 完整的线性SMO算法 + Parameters: + dataMatIn - 数据矩阵 + classLabels - 数据标签 + C - 松弛变量 + toler - 容错率 + maxIter - 最大迭代次数 + Returns: + oS.b - SMO算法计算的b + oS.alphas - SMO算法计算的alphas + """ + oS = optStruct(np.mat(dataMatIn), np.mat(classLabels).transpose(), C, toler) #初始化数据结构 + iter = 0 #初始化当前迭代次数 + entireSet = True; alphaPairsChanged = 0 + while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)): #遍历整个数据集都alpha也没有更新或者超过最大迭代次数,则退出循环 + alphaPairsChanged = 0 + if entireSet: #遍历整个数据集 + for i in range(oS.m): + alphaPairsChanged += innerL(i,oS) #使用优化的SMO算法 + print("全样本遍历:第%d次迭代 样本:%d, alpha优化次数:%d" % (iter,i,alphaPairsChanged)) + iter += 1 + else: #遍历非边界值 + nonBoundIs = np.nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0] #遍历不在边界0和C的alpha + for i in nonBoundIs: + alphaPairsChanged += innerL(i,oS) + print("非边界遍历:第%d次迭代 样本:%d, alpha优化次数:%d" % (iter,i,alphaPairsChanged)) + iter += 1 + if entireSet: #遍历一次后改为非边界遍历 + entireSet = False + elif (alphaPairsChanged == 0): #如果alpha没有更新,计算全样本遍历 + entireSet = True + print("迭代次数: %d" % iter) + return oS.b,oS.alphas #返回SMO算法计算的b和alphas + + +def showClassifer(dataMat, classLabels, w, b): + """ + 分类结果可视化 + Parameters: + dataMat - 数据矩阵 + w - 直线法向量 + b - 直线解决 + Returns: + 无 + """ + #绘制样本点 + data_plus = [] #正样本 + data_minus = [] #负样本 + for i in range(len(dataMat)): + if classLabels[i] > 0: + data_plus.append(dataMat[i]) + else: + data_minus.append(dataMat[i]) + data_plus_np = np.array(data_plus) #转换为numpy矩阵 + data_minus_np = np.array(data_minus) #转换为numpy矩阵 + plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1], s=30, alpha=0.7) #正样本散点图 + plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1], s=30, alpha=0.7) #负样本散点图 + #绘制直线 + x1 = max(dataMat)[0] + x2 = min(dataMat)[0] + a1, a2 = w + b = float(b) + a1 = float(a1[0]) + a2 = float(a2[0]) + y1, y2 = (-b- a1*x1)/a2, (-b - a1*x2)/a2 + plt.plot([x1, x2], [y1, y2]) + #找出支持向量点 + for i, alpha in enumerate(alphas): + if alpha > 0: + x, y = dataMat[i] + plt.scatter([x], [y], s=150, c='none', alpha=0.7, linewidth=1.5, edgecolor='red') + plt.show() + + +def calcWs(alphas,dataArr,classLabels): + """ + 计算w + Parameters: + dataArr - 数据矩阵 + classLabels - 数据标签 + alphas - alphas值 + Returns: + w - 计算得到的w + """ + X = np.mat(dataArr); labelMat = np.mat(classLabels).transpose() + m,n = np.shape(X) + w = np.zeros((n,1)) + for i in range(m): + w += np.multiply(alphas[i]*labelMat[i],X[i,:].T) + return w + +if __name__ == '__main__': + dataArr, classLabels = loadDataSet('testSet.txt') + b, alphas = smoP(dataArr, classLabels, 0.6, 0.001, 40) + w = calcWs(alphas,dataArr, classLabels) + showClassifer(dataArr, classLabels, w, b) diff --git a/svm/svm-svc.py b/svm/svm-svc.py new file mode 100755 index 0000000..2db1673 --- /dev/null +++ b/svm/svm-svc.py @@ -0,0 +1,91 @@ +# -*- coding: UTF-8 -*- +import numpy as np +import operator +from os import listdir +from sklearn.svm import SVC + +""" +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-10-04 +""" + +def img2vector(filename): + """ + 将32x32的二进制图像转换为1x1024向量。 + Parameters: + filename - 文件名 + Returns: + returnVect - 返回的二进制图像的1x1024向量 + """ + #创建1x1024零向量 + returnVect = np.zeros((1, 1024)) + #打开文件 + fr = open(filename) + #按行读取 + for i in range(32): + #读一行数据 + lineStr = fr.readline() + #每一行的前32个元素依次添加到returnVect中 + for j in range(32): + returnVect[0, 32*i+j] = int(lineStr[j]) + #返回转换后的1x1024向量 + return returnVect + +def handwritingClassTest(): + """ + 手写数字分类测试 + Parameters: + 无 + Returns: + 无 + """ + #测试集的Labels + hwLabels = [] + #返回trainingDigits目录下的文件名 + trainingFileList = listdir('trainingDigits') + #返回文件夹下文件的个数 + m = len(trainingFileList) + #初始化训练的Mat矩阵,测试集 + trainingMat = np.zeros((m, 1024)) + #从文件名中解析出训练集的类别 + for i in range(m): + #获得文件的名字 + fileNameStr = trainingFileList[i] + #获得分类的数字 + classNumber = int(fileNameStr.split('_')[0]) + #将获得的类别添加到hwLabels中 + hwLabels.append(classNumber) + #将每一个文件的1x1024数据存储到trainingMat矩阵中 + trainingMat[i,:] = img2vector('trainingDigits/%s' % (fileNameStr)) + clf = SVC(C=200,kernel='rbf') + clf.fit(trainingMat,hwLabels) + #返回testDigits目录下的文件列表 + testFileList = listdir('testDigits') + #错误检测计数 + errorCount = 0.0 + #测试数据的数量 + mTest = len(testFileList) + #从文件中解析出测试集的类别并进行分类测试 + for i in range(mTest): + #获得文件的名字 + fileNameStr = testFileList[i] + #获得分类的数字 + classNumber = int(fileNameStr.split('_')[0]) + #获得测试集的1x1024向量,用于训练 + vectorUnderTest = img2vector('testDigits/%s' % (fileNameStr)) + #获得预测结果 + # classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3) + classifierResult = clf.predict(vectorUnderTest) + print("分类返回结果为%d\t真实结果为%d" % (classifierResult, classNumber)) + if(classifierResult != classNumber): + errorCount += 1.0 + print("总共错了%d个数据\n错误率为%f%%" % (errorCount, errorCount/mTest * 100)) + +if __name__ == '__main__': + handwritingClassTest() \ No newline at end of file diff --git a/svm/svmMLiA.py b/svm/svmMLiA.py new file mode 100755 index 0000000..82cba1d --- /dev/null +++ b/svm/svmMLiA.py @@ -0,0 +1,313 @@ +# -*-coding:utf-8 -*- +import matplotlib.pyplot as plt +import numpy as np +import random + +""" +Author: + Jack Cui +Blog: + http://blog.csdn.net/c406495762 +Zhihu: + https://www.zhihu.com/people/Jack--Cui/ +Modify: + 2017-10-03 +""" + +class optStruct: + """ + 数据结构,维护所有需要操作的值 + Parameters: + dataMatIn - 数据矩阵 + classLabels - 数据标签 + C - 松弛变量 + toler - 容错率 + kTup - 包含核函数信息的元组,第一个参数存放核函数类别,第二个参数存放必要的核函数需要用到的参数 + """ + def __init__(self, dataMatIn, classLabels, C, toler, kTup): + self.X = dataMatIn #数据矩阵 + self.labelMat = classLabels #数据标签 + self.C = C #松弛变量 + self.tol = toler #容错率 + self.m = np.shape(dataMatIn)[0] #数据矩阵行数 + self.alphas = np.mat(np.zeros((self.m,1))) #根据矩阵行数初始化alpha参数为0 + self.b = 0 #初始化b参数为0 + self.eCache = np.mat(np.zeros((self.m,2))) #根据矩阵行数初始化虎误差缓存,第一列为是否有效的标志位,第二列为实际的误差E的值。 + self.K = np.mat(np.zeros((self.m,self.m))) #初始化核K + for i in range(self.m): #计算所有数据的核K + self.K[:,i] = kernelTrans(self.X, self.X[i,:], kTup) + +def kernelTrans(X, A, kTup): + """ + 通过核函数将数据转换更高维的空间 + Parameters: + X - 数据矩阵 + A - 单个数据的向量 + kTup - 包含核函数信息的元组 + Returns: + K - 计算的核K + """ + m,n = np.shape(X) + K = np.mat(np.zeros((m,1))) + if kTup[0] == 'lin': K = X * A.T #线性核函数,只进行内积。 + elif kTup[0] == 'rbf': #高斯核函数,根据高斯核函数公式进行计算 + for j in range(m): + deltaRow = X[j,:] - A + K[j] = deltaRow*deltaRow.T + K = np.exp(K/(-1*kTup[1]**2)) #计算高斯核K + else: raise NameError('核函数无法识别') + return K #返回计算的核K + +def loadDataSet(fileName): + """ + 读取数据 + Parameters: + 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 + +def calcEk(oS, k): + """ + 计算误差 + Parameters: + oS - 数据结构 + k - 标号为k的数据 + Returns: + Ek - 标号为k的数据误差 + """ + fXk = float(np.multiply(oS.alphas,oS.labelMat).T*oS.K[:,k] + oS.b) + Ek = fXk - float(oS.labelMat[k]) + return Ek + +def selectJrand(i, m): + """ + 函数说明:随机选择alpha_j的索引值 + + Parameters: + i - alpha_i的索引值 + m - alpha参数个数 + Returns: + j - alpha_j的索引值 + """ + j = i #选择一个不等于i的j + while (j == i): + j = int(random.uniform(0, m)) + return j + +def selectJ(i, oS, Ei): + """ + 内循环启发方式2 + Parameters: + i - 标号为i的数据的索引值 + oS - 数据结构 + Ei - 标号为i的数据误差 + Returns: + j, maxK - 标号为j或maxK的数据的索引值 + Ej - 标号为j的数据误差 + """ + maxK = -1; maxDeltaE = 0; Ej = 0 #初始化 + oS.eCache[i] = [1,Ei] #根据Ei更新误差缓存 + validEcacheList = np.nonzero(oS.eCache[:,0].A)[0] #返回误差不为0的数据的索引值 + if (len(validEcacheList)) > 1: #有不为0的误差 + for k in validEcacheList: #遍历,找到最大的Ek + if k == i: continue #不计算i,浪费时间 + Ek = calcEk(oS, k) #计算Ek + deltaE = abs(Ei - Ek) #计算|Ei-Ek| + if (deltaE > maxDeltaE): #找到maxDeltaE + maxK = k; maxDeltaE = deltaE; Ej = Ek + return maxK, Ej #返回maxK,Ej + else: #没有不为0的误差 + j = selectJrand(i, oS.m) #随机选择alpha_j的索引值 + Ej = calcEk(oS, j) #计算Ej + return j, Ej #j,Ej + +def updateEk(oS, k): + """ + 计算Ek,并更新误差缓存 + Parameters: + oS - 数据结构 + k - 标号为k的数据的索引值 + Returns: + 无 + """ + Ek = calcEk(oS, k) #计算Ek + oS.eCache[k] = [1,Ek] #更新误差缓存 + + +def clipAlpha(aj,H,L): + """ + 修剪alpha_j + Parameters: + aj - alpha_j的值 + H - alpha上限 + L - alpha下限 + Returns: + aj - 修剪后的alpah_j的值 + """ + if aj > H: + aj = H + if L > aj: + aj = L + return aj + +def innerL(i, oS): + """ + 优化的SMO算法 + Parameters: + i - 标号为i的数据的索引值 + oS - 数据结构 + Returns: + 1 - 有任意一对alpha值发生变化 + 0 - 没有任意一对alpha值发生变化或变化太小 + """ + #步骤1:计算误差Ei + Ei = calcEk(oS, i) + #优化alpha,设定一定的容错率。 + if ((oS.labelMat[i] * Ei < -oS.tol) and (oS.alphas[i] < oS.C)) or ((oS.labelMat[i] * Ei > oS.tol) and (oS.alphas[i] > 0)): + #使用内循环启发方式2选择alpha_j,并计算Ej + j,Ej = selectJ(i, oS, Ei) + #保存更新前的aplpha值,使用深拷贝 + alphaIold = oS.alphas[i].copy(); alphaJold = oS.alphas[j].copy(); + #步骤2:计算上下界L和H + if (oS.labelMat[i] != oS.labelMat[j]): + L = max(0, oS.alphas[j] - oS.alphas[i]) + H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i]) + else: + L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C) + H = min(oS.C, oS.alphas[j] + oS.alphas[i]) + if L == H: + print("L==H") + return 0 + #步骤3:计算eta + eta = 2.0 * oS.K[i,j] - oS.K[i,i] - oS.K[j,j] + if eta >= 0: + print("eta>=0") + return 0 + #步骤4:更新alpha_j + oS.alphas[j] -= oS.labelMat[j] * (Ei - Ej)/eta + #步骤5:修剪alpha_j + oS.alphas[j] = clipAlpha(oS.alphas[j],H,L) + #更新Ej至误差缓存 + updateEk(oS, j) + if (abs(oS.alphas[j] - alphaJold) < 0.00001): + print("alpha_j变化太小") + return 0 + #步骤6:更新alpha_i + oS.alphas[i] += oS.labelMat[j]*oS.labelMat[i]*(alphaJold - oS.alphas[j]) + #更新Ei至误差缓存 + updateEk(oS, i) + #步骤7:更新b_1和b_2 + b1 = oS.b - Ei- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.K[i,i] - oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.K[i,j] + b2 = oS.b - Ej- oS.labelMat[i]*(oS.alphas[i]-alphaIold)*oS.K[i,j]- oS.labelMat[j]*(oS.alphas[j]-alphaJold)*oS.K[j,j] + #步骤8:根据b_1和b_2更新b + if (0 < oS.alphas[i]) and (oS.C > oS.alphas[i]): oS.b = b1 + elif (0 < oS.alphas[j]) and (oS.C > oS.alphas[j]): oS.b = b2 + else: oS.b = (b1 + b2)/2.0 + return 1 + else: + return 0 + +def smoP(dataMatIn, classLabels, C, toler, maxIter, kTup = ('lin',0)): + """ + 完整的线性SMO算法 + Parameters: + dataMatIn - 数据矩阵 + classLabels - 数据标签 + C - 松弛变量 + toler - 容错率 + maxIter - 最大迭代次数 + kTup - 包含核函数信息的元组 + Returns: + oS.b - SMO算法计算的b + oS.alphas - SMO算法计算的alphas + """ + oS = optStruct(np.mat(dataMatIn), np.mat(classLabels).transpose(), C, toler, kTup) #初始化数据结构 + iter = 0 #初始化当前迭代次数 + entireSet = True; alphaPairsChanged = 0 + while (iter < maxIter) and ((alphaPairsChanged > 0) or (entireSet)): #遍历整个数据集都alpha也没有更新或者超过最大迭代次数,则退出循环 + alphaPairsChanged = 0 + if entireSet: #遍历整个数据集 + for i in range(oS.m): + alphaPairsChanged += innerL(i,oS) #使用优化的SMO算法 + print("全样本遍历:第%d次迭代 样本:%d, alpha优化次数:%d" % (iter,i,alphaPairsChanged)) + iter += 1 + else: #遍历非边界值 + nonBoundIs = np.nonzero((oS.alphas.A > 0) * (oS.alphas.A < C))[0] #遍历不在边界0和C的alpha + for i in nonBoundIs: + alphaPairsChanged += innerL(i,oS) + print("非边界遍历:第%d次迭代 样本:%d, alpha优化次数:%d" % (iter,i,alphaPairsChanged)) + iter += 1 + if entireSet: #遍历一次后改为非边界遍历 + entireSet = False + elif (alphaPairsChanged == 0): #如果alpha没有更新,计算全样本遍历 + entireSet = True + print("迭代次数: %d" % iter) + return oS.b,oS.alphas #返回SMO算法计算的b和alphas + + +def testRbf(k1 = 1.3): + """ + 测试函数 + Parameters: + k1 - 使用高斯核函数的时候表示到达率 + Returns: + 无 + """ + dataArr,labelArr = loadDataSet('testSetRBF.txt') #加载训练集 + b,alphas = smoP(dataArr, labelArr, 200, 0.0001, 100, ('rbf', k1)) #根据训练集计算b和alphas + datMat = np.mat(dataArr); labelMat = np.mat(labelArr).transpose() + svInd = np.nonzero(alphas.A > 0)[0] #获得支持向量 + sVs = datMat[svInd] + labelSV = labelMat[svInd]; + print("支持向量个数:%d" % np.shape(sVs)[0]) + m,n = np.shape(datMat) + errorCount = 0 + for i in range(m): + kernelEval = kernelTrans(sVs,datMat[i,:],('rbf', k1)) #计算各个点的核 + predict = kernelEval.T * np.multiply(labelSV,alphas[svInd]) + b #根据支持向量的点,计算超平面,返回预测结果 + if np.sign(predict) != np.sign(labelArr[i]): errorCount += 1 #返回数组中各元素的正负符号,用1和-1表示,并统计错误个数 + print("训练集错误率: %.2f%%" % ((float(errorCount)/m)*100)) #打印错误率 + dataArr,labelArr = loadDataSet('testSetRBF2.txt') #加载测试集 + errorCount = 0 + datMat = np.mat(dataArr); labelMat = np.mat(labelArr).transpose() + m,n = np.shape(datMat) + for i in range(m): + kernelEval = kernelTrans(sVs,datMat[i,:],('rbf', k1)) #计算各个点的核 + predict=kernelEval.T * np.multiply(labelSV,alphas[svInd]) + b #根据支持向量的点,计算超平面,返回预测结果 + if np.sign(predict) != np.sign(labelArr[i]): errorCount += 1 #返回数组中各元素的正负符号,用1和-1表示,并统计错误个数 + print("测试集错误率: %.2f%%" % ((float(errorCount)/m)*100)) #打印错误率 + + +def showDataSet(dataMat, labelMat): + """ + 数据可视化 + Parameters: + dataMat - 数据矩阵 + labelMat - 数据标签 + Returns: + 无 + """ + data_plus = [] #正样本 + data_minus = [] #负样本 + for i in range(len(dataMat)): + if labelMat[i] > 0: + data_plus.append(dataMat[i]) + else: + data_minus.append(dataMat[i]) + data_plus_np = np.array(data_plus) #转换为numpy矩阵 + data_minus_np = np.array(data_minus) #转换为numpy矩阵 + plt.scatter(np.transpose(data_plus_np)[0], np.transpose(data_plus_np)[1]) #正样本散点图 + plt.scatter(np.transpose(data_minus_np)[0], np.transpose(data_minus_np)[1]) #负样本散点图 + plt.show() + +if __name__ == '__main__': + testRbf() \ No newline at end of file diff --git a/svm/testSet.txt b/svm/testSet.txt new file mode 100644 index 0000000..538931e --- /dev/null +++ b/svm/testSet.txt @@ -0,0 +1,100 @@ +3.542485 1.977398 -1 +3.018896 2.556416 -1 +7.551510 -1.580030 1 +2.114999 -0.004466 -1 +8.127113 1.274372 1 +7.108772 -0.986906 1 +8.610639 2.046708 1 +2.326297 0.265213 -1 +3.634009 1.730537 -1 +0.341367 -0.894998 -1 +3.125951 0.293251 -1 +2.123252 -0.783563 -1 +0.887835 -2.797792 -1 +7.139979 -2.329896 1 +1.696414 -1.212496 -1 +8.117032 0.623493 1 +8.497162 -0.266649 1 +4.658191 3.507396 -1 +8.197181 1.545132 1 +1.208047 0.213100 -1 +1.928486 -0.321870 -1 +2.175808 -0.014527 -1 +7.886608 0.461755 1 +3.223038 -0.552392 -1 +3.628502 2.190585 -1 +7.407860 -0.121961 1 +7.286357 0.251077 1 +2.301095 -0.533988 -1 +-0.232542 -0.547690 -1 +3.457096 -0.082216 -1 +3.023938 -0.057392 -1 +8.015003 0.885325 1 +8.991748 0.923154 1 +7.916831 -1.781735 1 +7.616862 -0.217958 1 +2.450939 0.744967 -1 +7.270337 -2.507834 1 +1.749721 -0.961902 -1 +1.803111 -0.176349 -1 +8.804461 3.044301 1 +1.231257 -0.568573 -1 +2.074915 1.410550 -1 +-0.743036 -1.736103 -1 +3.536555 3.964960 -1 +8.410143 0.025606 1 +7.382988 -0.478764 1 +6.960661 -0.245353 1 +8.234460 0.701868 1 +8.168618 -0.903835 1 +1.534187 -0.622492 -1 +9.229518 2.066088 1 +7.886242 0.191813 1 +2.893743 -1.643468 -1 +1.870457 -1.040420 -1 +5.286862 -2.358286 1 +6.080573 0.418886 1 +2.544314 1.714165 -1 +6.016004 -3.753712 1 +0.926310 -0.564359 -1 +0.870296 -0.109952 -1 +2.369345 1.375695 -1 +1.363782 -0.254082 -1 +7.279460 -0.189572 1 +1.896005 0.515080 -1 +8.102154 -0.603875 1 +2.529893 0.662657 -1 +1.963874 -0.365233 -1 +8.132048 0.785914 1 +8.245938 0.372366 1 +6.543888 0.433164 1 +-0.236713 -5.766721 -1 +8.112593 0.295839 1 +9.803425 1.495167 1 +1.497407 -0.552916 -1 +1.336267 -1.632889 -1 +9.205805 -0.586480 1 +1.966279 -1.840439 -1 +8.398012 1.584918 1 +7.239953 -1.764292 1 +7.556201 0.241185 1 +9.015509 0.345019 1 +8.266085 -0.230977 1 +8.545620 2.788799 1 +9.295969 1.346332 1 +2.404234 0.570278 -1 +2.037772 0.021919 -1 +1.727631 -0.453143 -1 +1.979395 -0.050773 -1 +8.092288 -1.372433 1 +1.667645 0.239204 -1 +9.854303 1.365116 1 +7.921057 -1.327587 1 +8.500757 1.492372 1 +1.339746 -0.291183 -1 +3.107511 0.758367 -1 +2.609525 0.902979 -1 +3.263585 1.367898 -1 +2.912122 -0.202359 -1 +1.731786 0.589096 -1 +2.387003 1.573131 -1 diff --git a/svm/testSetRBF.txt b/svm/testSetRBF.txt new file mode 100644 index 0000000..bf5f979 --- /dev/null +++ b/svm/testSetRBF.txt @@ -0,0 +1,100 @@ +-0.214824 0.662756 -1.000000 +-0.061569 -0.091875 1.000000 +0.406933 0.648055 -1.000000 +0.223650 0.130142 1.000000 +0.231317 0.766906 -1.000000 +-0.748800 -0.531637 -1.000000 +-0.557789 0.375797 -1.000000 +0.207123 -0.019463 1.000000 +0.286462 0.719470 -1.000000 +0.195300 -0.179039 1.000000 +-0.152696 -0.153030 1.000000 +0.384471 0.653336 -1.000000 +-0.117280 -0.153217 1.000000 +-0.238076 0.000583 1.000000 +-0.413576 0.145681 1.000000 +0.490767 -0.680029 -1.000000 +0.199894 -0.199381 1.000000 +-0.356048 0.537960 -1.000000 +-0.392868 -0.125261 1.000000 +0.353588 -0.070617 1.000000 +0.020984 0.925720 -1.000000 +-0.475167 -0.346247 -1.000000 +0.074952 0.042783 1.000000 +0.394164 -0.058217 1.000000 +0.663418 0.436525 -1.000000 +0.402158 0.577744 -1.000000 +-0.449349 -0.038074 1.000000 +0.619080 -0.088188 -1.000000 +0.268066 -0.071621 1.000000 +-0.015165 0.359326 1.000000 +0.539368 -0.374972 -1.000000 +-0.319153 0.629673 -1.000000 +0.694424 0.641180 -1.000000 +0.079522 0.193198 1.000000 +0.253289 -0.285861 1.000000 +-0.035558 -0.010086 1.000000 +-0.403483 0.474466 -1.000000 +-0.034312 0.995685 -1.000000 +-0.590657 0.438051 -1.000000 +-0.098871 -0.023953 1.000000 +-0.250001 0.141621 1.000000 +-0.012998 0.525985 -1.000000 +0.153738 0.491531 -1.000000 +0.388215 -0.656567 -1.000000 +0.049008 0.013499 1.000000 +0.068286 0.392741 1.000000 +0.747800 -0.066630 -1.000000 +0.004621 -0.042932 1.000000 +-0.701600 0.190983 -1.000000 +0.055413 -0.024380 1.000000 +0.035398 -0.333682 1.000000 +0.211795 0.024689 1.000000 +-0.045677 0.172907 1.000000 +0.595222 0.209570 -1.000000 +0.229465 0.250409 1.000000 +-0.089293 0.068198 1.000000 +0.384300 -0.176570 1.000000 +0.834912 -0.110321 -1.000000 +-0.307768 0.503038 -1.000000 +-0.777063 -0.348066 -1.000000 +0.017390 0.152441 1.000000 +-0.293382 -0.139778 1.000000 +-0.203272 0.286855 1.000000 +0.957812 -0.152444 -1.000000 +0.004609 -0.070617 1.000000 +-0.755431 0.096711 -1.000000 +-0.526487 0.547282 -1.000000 +-0.246873 0.833713 -1.000000 +0.185639 -0.066162 1.000000 +0.851934 0.456603 -1.000000 +-0.827912 0.117122 -1.000000 +0.233512 -0.106274 1.000000 +0.583671 -0.709033 -1.000000 +-0.487023 0.625140 -1.000000 +-0.448939 0.176725 1.000000 +0.155907 -0.166371 1.000000 +0.334204 0.381237 -1.000000 +0.081536 -0.106212 1.000000 +0.227222 0.527437 -1.000000 +0.759290 0.330720 -1.000000 +0.204177 -0.023516 1.000000 +0.577939 0.403784 -1.000000 +-0.568534 0.442948 -1.000000 +-0.011520 0.021165 1.000000 +0.875720 0.422476 -1.000000 +0.297885 -0.632874 -1.000000 +-0.015821 0.031226 1.000000 +0.541359 -0.205969 -1.000000 +-0.689946 -0.508674 -1.000000 +-0.343049 0.841653 -1.000000 +0.523902 -0.436156 -1.000000 +0.249281 -0.711840 -1.000000 +0.193449 0.574598 -1.000000 +-0.257542 -0.753885 -1.000000 +-0.021605 0.158080 1.000000 +0.601559 -0.727041 -1.000000 +-0.791603 0.095651 -1.000000 +-0.908298 -0.053376 -1.000000 +0.122020 0.850966 -1.000000 +-0.725568 -0.292022 -1.000000 diff --git a/svm/testSetRBF2.txt b/svm/testSetRBF2.txt new file mode 100644 index 0000000..ac7145f --- /dev/null +++ b/svm/testSetRBF2.txt @@ -0,0 +1,100 @@ +0.676771 -0.486687 -1.000000 +0.008473 0.186070 1.000000 +-0.727789 0.594062 -1.000000 +0.112367 0.287852 1.000000 +0.383633 -0.038068 1.000000 +-0.927138 -0.032633 -1.000000 +-0.842803 -0.423115 -1.000000 +-0.003677 -0.367338 1.000000 +0.443211 -0.698469 -1.000000 +-0.473835 0.005233 1.000000 +0.616741 0.590841 -1.000000 +0.557463 -0.373461 -1.000000 +-0.498535 -0.223231 -1.000000 +-0.246744 0.276413 1.000000 +-0.761980 -0.244188 -1.000000 +0.641594 -0.479861 -1.000000 +-0.659140 0.529830 -1.000000 +-0.054873 -0.238900 1.000000 +-0.089644 -0.244683 1.000000 +-0.431576 -0.481538 -1.000000 +-0.099535 0.728679 -1.000000 +-0.188428 0.156443 1.000000 +0.267051 0.318101 1.000000 +0.222114 -0.528887 -1.000000 +0.030369 0.113317 1.000000 +0.392321 0.026089 1.000000 +0.298871 -0.915427 -1.000000 +-0.034581 -0.133887 1.000000 +0.405956 0.206980 1.000000 +0.144902 -0.605762 -1.000000 +0.274362 -0.401338 1.000000 +0.397998 -0.780144 -1.000000 +0.037863 0.155137 1.000000 +-0.010363 -0.004170 1.000000 +0.506519 0.486619 -1.000000 +0.000082 -0.020625 1.000000 +0.057761 -0.155140 1.000000 +0.027748 -0.553763 -1.000000 +-0.413363 -0.746830 -1.000000 +0.081500 -0.014264 1.000000 +0.047137 -0.491271 1.000000 +-0.267459 0.024770 1.000000 +-0.148288 -0.532471 -1.000000 +-0.225559 -0.201622 1.000000 +0.772360 -0.518986 -1.000000 +-0.440670 0.688739 -1.000000 +0.329064 -0.095349 1.000000 +0.970170 -0.010671 -1.000000 +-0.689447 -0.318722 -1.000000 +-0.465493 -0.227468 -1.000000 +-0.049370 0.405711 1.000000 +-0.166117 0.274807 1.000000 +0.054483 0.012643 1.000000 +0.021389 0.076125 1.000000 +-0.104404 -0.914042 -1.000000 +0.294487 0.440886 -1.000000 +0.107915 -0.493703 -1.000000 +0.076311 0.438860 1.000000 +0.370593 -0.728737 -1.000000 +0.409890 0.306851 -1.000000 +0.285445 0.474399 -1.000000 +-0.870134 -0.161685 -1.000000 +-0.654144 -0.675129 -1.000000 +0.285278 -0.767310 -1.000000 +0.049548 -0.000907 1.000000 +0.030014 -0.093265 1.000000 +-0.128859 0.278865 1.000000 +0.307463 0.085667 1.000000 +0.023440 0.298638 1.000000 +0.053920 0.235344 1.000000 +0.059675 0.533339 -1.000000 +0.817125 0.016536 -1.000000 +-0.108771 0.477254 1.000000 +-0.118106 0.017284 1.000000 +0.288339 0.195457 1.000000 +0.567309 -0.200203 -1.000000 +-0.202446 0.409387 1.000000 +-0.330769 -0.240797 1.000000 +-0.422377 0.480683 -1.000000 +-0.295269 0.326017 1.000000 +0.261132 0.046478 1.000000 +-0.492244 -0.319998 -1.000000 +-0.384419 0.099170 1.000000 +0.101882 -0.781145 -1.000000 +0.234592 -0.383446 1.000000 +-0.020478 -0.901833 -1.000000 +0.328449 0.186633 1.000000 +-0.150059 -0.409158 1.000000 +-0.155876 -0.843413 -1.000000 +-0.098134 -0.136786 1.000000 +0.110575 -0.197205 1.000000 +0.219021 0.054347 1.000000 +0.030152 0.251682 1.000000 +0.033447 -0.122824 1.000000 +-0.686225 -0.020779 -1.000000 +-0.911211 -0.262011 -1.000000 +0.572557 0.377526 -1.000000 +-0.073647 -0.519163 -1.000000 +-0.281830 -0.797236 -1.000000 +-0.555263 0.126232 -1.000000 diff --git a/targetDetection/README.md b/targetDetection/README.md new file mode 100644 index 0000000..569bbff --- /dev/null +++ b/targetDetection/README.md @@ -0,0 +1,38 @@ +# 目标检测 + +## 基本概念 +计算机视觉中关于图像识别有四大类任务: +1. 分类-Classification:解决“是什么?”的问题,即给定一张图片或一段视频判断里面包含什么类别的目标。 +2. 定位-Location:解决“在哪里?”的问题,即定位出这个目标的的位置。 +3. 检测-Detection:解决“是什么?在哪里?”的问题,即定位出这个目标的的位置并且知道目标物是什么。 +4. 分割-Segmentation:分为实例的分割(Instance-level)和场景分割(Scene-level),解决“每一个像素属于哪个目标物或场景”的问题。 + +![pic](http://index.zeekling.cn/gogsPics/ml/targetDection/1.png) + +## 目标检测算法分类 +![pic](http://index.zeekling.cn/gogsPics/ml/targetDection/2.png) +### Two stage目标检测算法 +先进行区域生成(region proposal,RP)(一个有可能包含待检物体的预选框),再通过卷积神经网络进行样本分类。 + +任务:特征提取—>生成RP—>分类/定位回归。 + +常见的two stage目标检测算法有:R-CNN、SPP-Net、Fast R-CNN、Faster R-CNN和R-FCN等。 + +#### R-CNN +> **标题**:《Rich feature hierarchies for accurate object detection and semantic segmentation》
    +> **时间**:2014
    +> **出版源**:CVPR 2014 + +主要链接: +1. **arXiv**:[http://arxiv.org/abs/1311.2524 ](http://arxiv.org/abs/1311.2524) +2. **github(caffe)**:[https://github.com/rbgirshick/rcnn ](https://github.com/rbgirshick/rcnn) + + +### 2.One stage目标检测算法 +不用RP,直接在网络中提取特征来预测物体分类和位置。 + +任务:特征提取—>分类/定位回归。 + +常见的one stage目标检测算法有:OverFeat、YOLOv1、YOLOv2、YOLOv3、SSD和RetinaNet等。 + +