master
aolingwen 5 years ago
parent e352b98deb
commit f565eff1ac

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@ -1,2 +1,2 @@
# 第十章 推荐系统
# 第十章 打造电影推荐系统

@ -1,5 +1,6 @@
# 10.4 动手实现基于矩阵分解的协同过滤
弄清楚了基于矩阵分解的协同过滤算法的原理和算法流程之后,我们可以很容易的使用`python`,来实现算法。代码如下:
```python
# -*- coding: utf-8 -*-

@ -1,17 +1,30 @@
# 10.2 基于矩阵分解的协同过滤算法思想
在推荐系统中,我们经常看到如下图的表格,表格中的数字代表用户对某个物品的评分,`0`代表未评分。我们希望能够预测目标用户对物品的评分,进而根据评分高低,将分高的物品推荐给用户。
假设现在需要为用户推荐他可能喜欢的电影,如果你是这个项目的设计者,你会以什么样的依据来对不同的用户推荐他可能喜欢的电影呢?
|y | 物品1| 物品2| 物品3| 物品4| 物品5|
嗯,你可能会认为,如果我有不同用户对不同电影的评分,或者好评率等一些可以量化的数值,那么我只要找到用户对所有电影中评分最高那部电影,然后推荐给他就行了。
是的,没错!其实很多推荐系统就是这样实现的。也就是说,如果有下面这样的表格,我想你应该会像 2 号用户推荐 3 号电影。
|y | 电影1| 电影2| 电影3| 电影4| 电影5|
| --- | --- | --- | --- | --- | --- |
| 用户1 | 5 | 5 | 4 | 1 | 1 |
| 用户2 | 4 | 4 | 5 | 3 | 2 |
| 用户3 | 1 | 3| 1 | 5 | 5 |
| 用户4 | 1 | 1 | 3 | 4 | 2 |
但是我们的用户,不可能所有电影都看过,也就是说,在实际场景中,我们的表格中会有很多缺失值,在这里假设用`0`来代表缺失值,就如下表一样:
|y | 电影1| 电影2| 电影3| 电影4| 电影5|
| --- | --- | --- | --- | --- | --- |
| 用户1 | 5 | 5 | 0 | 1 | 1 |
| 用户2 | 5 | 0 | 4 | 1 | 1 |
| 用户3 | 1 | 0 | 1 | 5 | 5 |
| 用户4 | 1 | 1 | 0 | 4 | 0 |
基于矩阵分解的协同过滤算法正好能解决这个问题。
所以我们希望能够有一种算法,它能预测目标用户对物品的评分,进而根据评分高低,将分高的物品推荐给用户
基于矩阵分解的协同过滤算法通常都会构造如下图所示评分表`y`,这里我们以电影为例:
基于矩阵分解的协同过滤算法正好能解决这个问题。假设现有的表格如下所示
|y | 电影1| 电影2| 电影3| 电影4| 电影5|
| --- | --- | --- | --- | --- | --- |
@ -62,9 +75,9 @@
所以不难看出,基于矩阵分解的协同过滤算法的流程如下:
- 1.随机初始矩阵值
- 2.构造损失函数,求得矩阵参数梯度
- 3.进行梯度下降,更新矩阵参数值
- 4.喜好矩阵与内容矩阵相乘得到预测评分
- 5.根据预测评分进行推荐
- 随机初始矩阵值
- 构造损失函数,求得矩阵参数梯度
- 进行梯度下降,更新矩阵参数值
- 喜好矩阵与内容矩阵相乘得到预测评分
- 根据预测评分进行推荐

@ -4,6 +4,8 @@
你可能会有这样的经历当你在电商网站闲逛时电商网站会根据你的历史行为轨迹分析出你的喜好像你推荐一些你可能喜欢的商品。当你刷抖音快手等小视频APP时这些APP会根据你观看视频的时长、视频类型等数据进行判别判别出你接下来可能更想要看到的视频。其实这些基本上都是推荐系统的应用。
![](1.jpg)
总结下来,使用的场景不外乎两个:帮你做内容推荐,或者说是筛选;另外就是做消费刺激,找到你想要买的东西。再抽象一点,其实考量的就是信息的相关行或者关联程度的问题。
## 基本概念

@ -1,2 +1,2 @@
# 第四章 k-近邻
# 第四章 使用k近邻算法检测红酒品质

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@ -1,2 +1 @@
# 第五章 线性回归
# 第五章 使用线性回归算法预测房价

@ -1,19 +1,20 @@
# 5.4 动手实现线性回归
# 5.3 动手实现线性回归
线性回归`python`实现代码如下:
知道线性回归的正规方程解的公式之后,我们可以很容易的使用`python`实现线性回归算法。`python`实现代码如下:
```python
#encoding=utf8
import numpy as np
# 线性回归算法
def lr(train_feature,train_label,test_feature):
'''
input:
train_feature(ndarray):训练样本特征
train_label(ndarray):训练样本标签
test_feature(ndarray):测试样本特征
train_feature(ndarray):历史数据
train_label(ndarray):每条历史数据所对应的答案
test_feature(ndarray):测试数据
output:
predict(ndarray):测试样本预测标签
predict(ndarray):每条测试数据所对应的预测结果
'''
#将x0=1加入训练数据
train_x = np.hstack([np.ones((len(train_feature),1)),train_feature])

@ -1,4 +1,4 @@
# 5.5 实战案例
# 5.4 预测房价
### 波士顿房价数据
@ -21,15 +21,19 @@ x = boston.data
y = boston.target
```
然后再对数据集进行划分:
然后再对数据集进行划分,因为我们需要人为的划分出两个部分,一部分代表历史数据,另一部分代表未来的数据。用于检验我们线性回归算法的准确度。划分数据,我们可以使用`sklearn`中提供的`train_test_split`函数来实现,示例代码如下
```python
from sklearn.model_selection import train_test_split
#划分训练集测试集所有样本的20%作为测试集
# train_feature表示历史数据
# test_feature表示未来数据
# train_label表示每条历史记录所对应的答案
# test_label表示每条未来记录所对应的答案
train_feature,test_feature,train_label,test_label = train_test_split(x,y,test_size=0.2,random_state=666)
```
### 进行预测
### 预测房价
同样的只需要调用之前实现线性回归方法就可以对测试集的波士顿房价数据进行预测了:
@ -117,7 +121,7 @@ $$
这里使用`python`实现了`MSE``R-Squared`方法,代码如下:
```
```python
import numpy as np
#mse
@ -146,4 +150,5 @@ r2
>>>0.63
```
可以看到,我们已经能够根据房价的历史数据,来预测未知房屋的价格了,而且预测的准确度也是可以接受的。

@ -1,71 +1,72 @@
# 5.2 线性回归算法原理
### 线性回归训练流程
## 什么是线性回归
我们已经知道线性回归模型如下:
线性回归是什么意思?可以拆字释义。回归肯定不用我多说了,那什么是线性呢?我们可以回忆一下初中 时学过的直线方程:`y=k*x+b`
这个式子表达的是,当我知道 k (参数)和 b (参数)的情况下,我随便给一个 x 我都能通过这个方程 算出 y 来。而且呢,这个式子是线性的,为什么呢?因为从直觉上来说,你都知道,这个式子的函数图像 是条直线。
$$
y = b +w_1x_1+w_2x_2+...+w_nx_n
$$
从理论上来说,这式子满足线性系统的性质。你可能会觉得疑惑,这一节要说的是线性回归,我说个这么 low 直线方程干啥?其实,说白了,线性回归就是在 N 维空间中找一个形式像直线方程一样的函数来拟合数据而已。比如说,我 现在有这么一张图,横坐标代表房子的面积,纵坐标代表房价。
为了方便,我们稍微将模型进行变换:
![](2.jpg)
$$
y = w_0x_0 +w_1x_1+w_2x_2+...+w_nx_n
$$
然后呢,线性回归就是要找一条直线,并且让这条直线尽可能地拟合图中的数据点。
其中`x0=1`,`w0=b`,通过向量化公式可写成如下形式:
那如果让 1000 位朋友来找这条直线就可能找出 1000 种直线来,比如这样
$$
Y=X.W
$$
![](4.jpg)
$$
W = (w_0,w_1,...,w_n)
$$
这样
$$
X = (1,x_1,...,x_n)
$$
![](5.jpg)
而我们的目的就是找出能够正确预测的多元线性回归模型,即找出正确的`W`(即权重与偏置)。那么如何寻找呢?通常在监督学习里面都会使用这么一个套路,构造一个损失函数,用来衡量真实值与预测值之间的差异,然后将问题转化为最优化损失函数。既然损失函数是用来衡量真实值与预测值之间的差异那么很多人自然而然的想到了用所有真实值与预测值的差的绝对值来表示损失函数。不过带绝对值的函数不容易求导,所以采用`MSE`(均方误差)作为损失函数,公式如下:
或者这样
$$
loss = \frac{1}{m}\sum\limits_{i=1}^m(y^{(i)}-p^{(i)})^2
$$
![](6.jpg)
其中`p`表示预测值,`y`表示真实值,`m`为样本总个数,`i`表示第`i`个样本。最后,我们再使用**正规方程解**来求得我们所需要的参数
喏,其实找直线的过程就是在做线性回归,只不过这个叫法更有高大上而已。
线性回归模型训练流程图如下:
## 损失函数
![lr2](lr2.jpg)
那既然是找直线,那肯定是要有一个评判的标准,来评判哪条直线才是最好的。道理我们都懂,那咋评判呢?其实只要算一下实际房价和我找出的直线根据房子大小预测出来的房价之间的差距就行了。说白了就 是算两点的距离。当把所有实际房价和预测出来的房价的差距(距离)算出来然后做个加和,就能量化出 现在预测的房价和实际房价之间的误差。例如下图中我画了很多条小数线,每一条小数线就是实际房价和预测房价的差距(距离)。
### 正规方程解
![](7.jpg)
对线性回归模型,假设训练集中`m`个训练样本,每个训练样本中有`n`个特征,可以使用矩阵的表示方法,预测函数可以写为:
然后把每条小竖线的长度加起来就等于现在通过这条直线预测出的房价与实际房价之间的差距。那每条小竖线的长度的加和怎么算?其实就是欧式距离加和,公式为:$$\sum_{i=1}^m(y^{(i)}-\hat y{^{(i)}})^2$$(其中$$y(i)$$表示的是实际房价,$$\hat y (i)$$表示的是预测房价)。
$$
Y = X.W
$$
其损失函数可以表示为
这个欧氏距离加和其实就是用来量化预测结果和真实结果的误差的一个函数。在机器学习中称它为**损失函数**(说白了就是计算误差的函数)。那有了这个函数,就相当于有了一个评判标准,当这个函数的值越小,就越说明找到的这条直线越能拟合房价数据。所以说啊,线性回归就是通过这个损失函数做为评判标准来找出一条直线。
如果假设$$h_{(\theta)}(x)$$表示当权重为$$\theta$$,输入为$$x$$时计算出来的$$ \hat y(i)$$,那么线性回归的损失函数$$J(\theta)$$就是:
<center>
$$
loss = \frac{1}{m}(Y-X.W)^T(Y-X.W)
J(\theta)=\frac{1}{2}\sum^m_{i=1}(h_\theta(x^i)-y^i)^2
$$
</center>
其中,标签`Y`为`m`行`1`列的矩阵,训练特征`X`为`m`行`(n+1)`列的矩阵,回归系数`W`为`(n+1)`行`1`列的矩阵,对`W`求导,并令其导数为零可解得:
## 怎样计算出线性回归的解?
$$
W=(X^TX)^{-1}X^TY
$$
现在你应该已经弄明白了一个事实,那就是我只要找到一组参数(也就是线性方程每一项上的系数)能让我的损失函数的值最小,那我这一组参数就能最好的拟合我现在的训练数据。
这个就是正规方程解,我们可以通过正规方程解直接求得我们所需要的参数
那怎么来找到这一组参数呢?其实我们可以使用线性回归的**正规方程解**,这名字听起来高大上,其实本质就是根据一个固定的式子计算出参数。线性回归的正规方程解是这样算出来的。
假设数据中`m`条记录,每条记录中有`n`个特征,可以使用矩阵的表示方法,预测函数可以写为:
$$
Y = X.W
$$
其损失函数可以表示为
$$
loss = \frac{1}{m}(Y-X.\theta)^T(Y-X.\theta)
$$
其中,标签`Y`为`m`行`1`列的矩阵,特征`X`为`m`行`(n+1)`列的矩阵,回归系数\theta为`(n+1)`行`1`列的矩阵,对\theta求导并令其导数为零可解得
$$
W=(\theta^T\theta)^{-1}\theta^TY
$$
这个就是正规方程解,我们可以通过正规方程解直接求得我们所需要的参数。

@ -1,29 +1,13 @@
# 5.1 线性回归算法思想
# 5.1 什么是回归
### 简单线性回归
在上一章介绍了如何使用k近邻算法来对红酒的品质进行检测。由于红酒的品质是一种离散值所以红酒品质检测这件事说白了就是将对红酒的品质进行分类。
在生活中,我们常常能碰到这么一种情况,一个变量会跟着另一个变量的变化而变化,如圆的周长与半径的关系,当圆的半径确定了,那么周长也就确定了。还有一种情况就是,两个变量之间看似存在某种关系,但又没那么确定,如青少年的身高与体重,他们存在一种近似的**线性**关系:
那么细心的你可能会发现一个问题,如果我们想要的输出是连续值而非离散值,该怎么办呢?
`身高/cm = 体重/kg +105`
![](1.jpg)
但是,并不是每个青少年都符合这个公式,只能说每个青少年的身高体重都存在这么一种近似的线性关系。这就是其实就是简单的**线性回归**,那么,到底什么是线性回归呢?假如我们将青少年的身高和体重值作为坐标,不同人的身高体重就会在平面上构成不同的坐标点,然后用一条直线,尽可能的去拟合这些点,这就是简单的线性回归
那这个时候,就可以引出一个概念了,那就是回归。那回归是什么意思呢?其实说白了,就是这个我们的算法的输出的结果是个连续的值。如果输出不是个连续值而是个离散值那就叫分类。那什么叫做连续值呢?非常简单
![lr1](lr1.jpg)
举个栗子:比如我告诉你我这里有间房子,这间房子有 40 平在地铁口然后你来猜一猜我的房子总共值多少钱这就是连续值因为房子可能值80万也可能值 80.2 万,也可能值 80.111 万。再比如我告诉你我有间房子120 平,在地铁口,总共值 180 万,然后你来猜猜我这间房子会有几个卧室?那这就是离散值了。因为卧室的个数只可能是 1 2 34充其量到 5 个封顶了,而且卧室个数也不可能是什么 1.1 2.9 个。所以呢,对于数据挖掘新手来说,你只要知道我要完成的任务是预测一个连续值的话,那这个任务就是回归。是离散值的话就是分类。
简单的线性回归模型如下:
$$
y = wx+b
$$
其中`x`表示特征值(如:体重值)`w`表示权重,`b`表示偏置,`y`表示标签(如:身高值)。
### 多元线性回归
简单线性回归中,一个变量跟另一个变量的变化而变化,但是生活中,还有很多变量,可能由多个变量的变化决定着它的变化,比如房价,影响它的因素可能有:房屋面积、地理位置等等。如果我们要给它们建立出近似的线性关系,这就是多元线性回归,多元线性回归模型如下:
$$
y=b+w_1x_1+w_2x_2+...+w_nx_n
$$
其中,$$x_i$$表示第`i`个特征,$$w_i$$表示第`i`个特征对于的权重,`b`表示偏置,`y`表示标签。
所以预测房价其实就是一种回归问题。而接下来要介绍的线性回归算法就是回归算法中的一种。

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@ -1,3 +1,3 @@
# 第六章 决策树
# 第六章 使用决策树算法识别花朵

@ -1,4 +1,4 @@
# 6.1 决策树算法思想
# 6.1 决策树算法的核心思想
决策树是一种可以用于分类与回归的机器学习算法,但主要用于分类。用于分类的决策树是一种描述对实例进行分类的树形结构。决策树由**结点**和**边**组成,其中结点分为**内部结点**和**叶子结点****内部结点表示一个特征或者属性,叶子结点表示标签。**

@ -1,8 +1,25 @@
# 6.3 决策树算法流程
# 6.3 决策树构建流程
接下来将通过使用上一节中客户流失的数据来描述一下`ID3`算法构建决策树的过程。
一开始我们已经算过信息增益最大的是活跃度,所以决策树的根节点是活跃度 。所以这个时候树是这样的:
![](1.jpg)
然后发现训练集中的数据表示当我活跃度低的时候一定会流失,活跃度高的时候一定不流失,所以可以先 在根节点上接上两个叶子节点。
![](2.jpg)
但是活跃度为中的时候就不一定流失了,所以这个时候就可以把活跃度为低和为高的数据屏蔽掉,屏蔽掉 之后 5 条数据,接着把这 5 条数据当成训练集来继续算哪个特征的信息增益最高,很明显算完之后是性别 这个特征,所以这时候树变成了这样:
![](3.jpg)
这时候呢,数据集里没有其他特征可以选择了(总共就两个特征,活跃度已经是根节点了),所以就看我 性别是男或女的时候那种情况最有可能出现了。此时性别为男的用户中有 1 个是流失1 个是不流失,五五开。所以可以考虑随机选个结果当输出了。性别为女的用户中有全部都流失,所以性别为女时输出是流失。所以呢,树就成了这样:
![](4.jpg)
好了,决策树构造好了。从图可以看出决策树有一个非常好的地方就是模型的解释性非常强!!很明显, 如果现在来了一条数据 (男, 高) 的话,输出会是不流失。
我们最终的目的是根据创建的决策树模型对测试集数据进行预测,算法实现流程如下:
- 1.计算训练样本信息增益
- 2.获得信息增益最高的特征
- 3.递归创建决策树
- 4.根据决策树模型对测试集数据进行预测

@ -1,51 +1,8 @@
# 6.4 动手实现决策树
```python
#encoding=utf8
import numpy as np
理解了`ID3`算法之后,我们可以尝试使用`python`来实现该算法了。由于`ID3`算法在构建决策树的时候需要计算信息增益。所以首先可以使用如下代码,实现信息增益的计算。实现思路是分别实现熵和条件熵的计算,再根据信息增益的公式实现信息增益的计算。
# 计算熵
def calcInfoEntropy(label):
'''
label(narray):样本标签
'''
label_set = set(label)
result = 0
for l in label_set:
count = 0
for j in range(len(label)):
if label[j] == l:
count += 1
# 计算标签在数据集中出现的概率
p = count / len(label)
# 计算熵
result -= p * np.log2(p)
return result
#计算条件熵
def calcHDA(feature,label,index,value):
'''
input:
feature(ndarray):样本特征
label(ndarray):样本标签
index(int):需要使用的特征列索引
value(int):index所表示的特征列中需要考察的特征值
output:
HDA(float):信息熵
'''
count = 0
# sub_feature和sub_label表示根据特征列和特征值分割出的子数据集中的特征和标签
sub_feature = []
sub_label = []
for i in range(len(feature)):
if feature[i][index] == value:
count += 1
sub_feature.append(feature[i])
sub_label.append(label[i])
pHA = count / len(feature)
e = calcInfoEntropy(sub_label)
HDA = pHA * e
return HDA
```python
#计算信息增益
def calcInfoGain(feature, label, index):
@ -57,6 +14,49 @@ def calcInfoGain(feature, label, index):
output:
InfoGain(float):信息增益
'''
# 计算熵
def calcInfoEntropy(label):
'''
label(narray):样本标签
'''
label_set = set(label)
result = 0
for l in label_set:
count = 0
for j in range(len(label)):
if label[j] == l:
count += 1
# 计算标签在数据集中出现的概率
p = count / len(label)
# 计算熵
result -= p * np.log2(p)
return result
#计算条件熵
def calcHDA(feature,label,index,value):
'''
input:
feature(ndarray):样本特征
label(ndarray):样本标签
index(int):需要使用的特征列索引
value(int):index所表示的特征列中需要考察的特征值
output:
HDA(float):信息熵
'''
count = 0
# sub_feature和sub_label表示根据特征列和特征值分割出的子数据集中的特征和标签
sub_feature = []
sub_label = []
for i in range(len(feature)):
if feature[i][index] == value:
count += 1
sub_feature.append(feature[i])
sub_label.append(label[i])
pHA = count / len(feature)
e = calcInfoEntropy(sub_label)
HDA = pHA * e
return HDA
base_e = calcInfoEntropy(label)
f = np.array(feature)
# 得到指定特征列的值的集合
@ -68,7 +68,12 @@ def calcInfoGain(feature, label, index):
# 计算信息增益
InfoGain = base_e - sum_HDA
return InfoGain
```
有了计算信息增益的功能后,我们还需要一个功能,就是需要找到数据中信息增益最高的特征是哪个,这就需要一个函数来计算出信息增益最高的特征的索引。实现方法如下:
```python
# 获得信息增益最高的特征
def getBestFeature(feature, label):
'''
@ -86,7 +91,12 @@ def getBestFeature(feature, label):
max_infogain = infogain
best_feature = i
return best_feature
```
有了以上的这些功能以后,我们可以开始实现决策树的构造过程了。大致过程和上一节所描述的一样,实现如下:
```python
#创建决策树
def createTree(feature, label):
'''
@ -132,6 +142,12 @@ def createTree(feature, label):
tree[best_feature][v] = createTree(sub_feature, sub_label)
return tree
```
构造好决策树之后,我们就可以实现使用这棵决策树来进行预测的方法了,实现如下:
```python
#决策树分类
def dt_clf(train_feature,train_label,test_feature):
'''
@ -165,6 +181,6 @@ def dt_clf(train_feature,train_label,test_feature):
result.append(classify(tree,f))
predict = np.array(result)
return predict
```
OK现在我们已经实现了决策树算法接下来我们来看一下怎样使用我们实现好了的算法来识别花朵。

@ -1,4 +1,4 @@
# 6.5 实战案例
# 6.5 识别花朵
### 鸢尾花数据
@ -60,4 +60,4 @@ acc
>>>1.0
```
可以看到,使用决策树对鸢尾花进行分类,正确率可以达到`100%`
可以看到,使用决策树对鸢尾花进行分类,正确率可以达到`100%`

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

@ -1,5 +1,6 @@
# 7.2 k-均值算法原理
# 7.2 k均值算法原理
k 均值算法通常是大家接触到的第一个聚类算法其思想非常简单是一种典型的基于距离的聚类算法。k 均值算法,之所以称为 k 均值 是因为它可以发现 k 个簇(即类别),且每个簇的中心采用簇中所含值的均值计算而成。簇内的样本连接紧密,而簇之间的距离尽量大。简单来讲,其思想就是**物以类聚**。
假设我们有`k`个簇:$$(c_1,c_2,...,c_k)$$

@ -1,4 +1,44 @@
# 7.1 k-均值算法思想
# 7.1 什么是图像分割
## 图像是由像素组成的
![](1.jpg)
这是从新浪`2009`年的验证码中截出来的一张图。相信大家已经看出来了是字母`y`。这张看似非常简单的图在计算机中却是由一个个像素所排列组成的。像素(`pixel`)是图像的组成单位,像素的值域是`[0, 255]`。像素值越低的话我们看起来就越黑,越高的话看起来就越白。如图所示:
![](2.jpg)
正因为像素有代表明暗的属性,所以我们看到的这张图在计算机中的存储是这样的。
![](3.jpg)
相信你可以站远点看能够看得出来也是一个`y`。
## 图像分割的意义
现在已经知道数字图像是由很多个像素组成的,如果图像的高和宽很大的时候,我们想识别出图像中的某个对象的时候就面临了一个问题,就是搜索范围太大了。比如下面这张图,如果我想识别出图中的建筑,那我的算法可能需要查看所有像素,很显然,这是一种非常低效的方式。
![](4.jpg)
倘若现在我换个思路,我在识别建筑之前我先把图像中对象用不同的编号或者颜色来划分成不同的区域(图像处理中将其称为感兴趣区域也叫`ROI`),然后再根据我想要识别的对象来查看对象对应的`ROI`即可。这样做能很好的提高图像识别的效率,并且能够在一定程度上过滤掉一些无用的信息。比如我要识别出上图中的建筑,我可能会对整张图做图像分割,然后我只要对整张图的上半部分做图像识别就可以了。
![](5.jpg)
## 图像分割与聚类
此时出现了一个新名词叫做**聚类**。其实**聚类**和**分类**是比较相近的。他们的共同点是将数据划分成好几个类别,而不同的是,**分类**的历史数据中是带有标准答案的;而**聚类**时,历史数据中是不带标准答案的。如下图所示:
![](6.jpg)
![](7.jpg)
也就是说,**聚类**算法会将觉得长得差不多的数据划分为同一种类别。这种思想与图像分割的功能是一致的,因为图像分割其实就是将觉得长得差不多的像素划分为同一种类别。所以**聚类**算法可是实现图像分割的功能。接下来要介绍的 k 均值算法,就是一种典型的聚类算法。
`k-means`是属于机器学习里面的**非监督学习**,通常是大家接触到的第一个聚类算法,其思想非常简单,是一种典型的基于距离的聚类算法。`k-means`K-均值)聚类,之所以称为 K-均值 是因为它可以发现`K`个簇,且每个簇的中心采用簇中所含值的均值计算而成。簇内的样本连接紧密,而簇之间的距离尽量大。简单来讲,其思想就是**物以类聚**。

@ -1,54 +1,129 @@
# 7.5 实战案例
# 7.3 图像分割
### 鸢尾花数据
## 了解数据
本次我们使用的仍然是鸢尾花数据,不过为了能够进行可视化我们只使用数据中的两个特征:
既然要对图像进行图像分割,那肯定需要有图像。在这里,为你准备了一张图像,如下图所示:
![](9.jpg)
如果我们想将整张图分割成双黄线,马路,路边,天空这 4 个部分,那么很明显我们可以使用 k均值算法来进行分割而且此时的 k 为 4。因为我们样将所有的像素聚类成 4 个簇。
## 代码实现
### 读取图像
首先我们需要将图像读入内存,`python`有很多库都实现了读取图像的功能。在这里,我将使用`opencv`这个库来读取图像。`opencv`在计算机视觉领域的使用是非常广泛的,如果你对计算机视觉感兴趣,可以深入了解一下`opencv`以及一些图像处理的知识,在这里我就不多做介绍了。
`opencv`读图像很简单,只需要使用如下代码即可:
```python
from sklearn.datasets import load_iris
# 导入opencv库
import cv2
iris = load_iris()
x,y = iris.data,iris.target
x = x[:,2:]
# 读取图像图像名字为test.jpg并将图像保存到img变量中
img = cv2.imread('test.jpg')
```
可视化数据分布:
读取到图像后,就可以着手实现 k 均值算法了。
```python
import matplotlib.pyplot as plt
### k均值算法
plt.scatter(x[:,0],x[:,1])
plt.show()
在实现 k 均值算法之前,可以思考一下 k 均值算法所需要的参数,很明显需要三个参数,一个是数据,在这里也就是读取到的图像;另一个就是 k刚刚已经提到过在这里k 为 4。还有一个就是 k 均值算法的最大迭代次数。
因此可以写出如下函数声明:
```python
def kmeans(n, k, image):
```
可视化结果:
接下来我们来实现函数体。对于图像来说,它可以看成是一个三维数组,但是 k 均值算法需要的是一个二维数组,所以我们需要对数据进行变形。而且还需要将图像进行升维,因为在算法结束时,需要知道每个像素所对应的簇标签值。所以会有如下代码
![k-means](k-means.jpg)
```python
# 图像的高
height = image.shape[0]
# 图像的高
width = image.shape[1]
tmp = image.reshape(-1, 3)
result = tmp.copy()
#扩展一个维度用来存放标签
result = np.column_stack((result, np.ones(height*width)))
```
我们可以先根据数据的真实标签查看数据类别情况:
做好数据处理后,可以开始根据上一节所提到的 k 均值算法的原理来实现该算法了。首先需要初始化质心。
```python
import matplotlib.pyplot as plt
# 初始化质心
center_point = np.random.choice(height*width, k, replace=False)
center = result[center_point, :]
# 初始化距离矩阵
distance = [[] for i in range(k)]
```
plt.scatter(x[:,0],x[:,1],c=y)
plt.show()
然后需要不断地迭代更新我们的质心。
```python
# 迭代n次
for i in range(n):
# 计算每个像素到各个质心的距离
for j in range(k):
distance[j] = np.sqrt(np.sum(np.square(result - np.array(center[j])), axis=1))
# 为每个像素打上簇标签
result[:, 3] = np.argmin(np.array(distance), axis=0)
# 更新质心
for j in range(k):
center[j] = np.mean(result[result[:, 3] == j], axis=0)
return result
```
效果如下:
因此,完整的代码如下:
![kmeans1](kmeans1.jpg)
```python
def kmeans(n, k, image):
height = image.shape[0]
width = image.shape[1]
tmp = image.reshape(-1, 3)
result = tmp.copy()
#扩展一个维度用来存放标签
result = np.column_stack((result, np.ones(height*width)))
center_point = np.random.choice(height*width, k, replace=False)
center = result[center_point, :]
distance = [[] for i in range(k)]
#迭代
for i in range(n):
for j in range(k):
distance[j] = np.sqrt(np.sum(np.square(result - np.array(center[j])), axis=1))
result[:, 3] = np.argmin(np.array(distance), axis=0)
for j in range(k):
center[j] = np.mean(result[result[:, 3] == j], axis=0)
return result
```
### 进行聚类
### 分割图像
最后,使用我们实现的`k-means`方法对数据进行聚类并查看聚类效果:
有了 k 均值算法后,就可以分割图像了。
```python
predict = predict(3,x,500,0.0001)
plt.subplot('121')
plt.imshow(img)
height = img.shape[0]
width = img.shape[1]
# 使用刚刚实现的k均值算法
result_img = kmeans(150, 5, img)
# 将最终结果变形为二维数组
result_img = result_img[:, 3].reshape(height, width)
plt.scatter(x[:,0],x[:,1],c=predict)
plt.subplot('122')
plt.imshow(result_img)
plt.show()
```
![kmeans2](kmeans2.jpg)
最终可以看到 k 均值算法能够较好的对图像进行分割。
可以发现,使用实现的方法进行聚类的结果与真实情况非常吻合。
![](8.jpg)

@ -1,2 +1,2 @@
# 第八章 Apriori算法
# 第八章 使用Apriori算法找出毒蘑菇的共性

@ -1,8 +1,10 @@
# 8.3 动手实现Apriori
```python
# 寻找频繁项集部分 Begin
想要从数据中挖掘出关联规则,就需要先能够寻找频繁项集,所以首先我们可以实现一些用于寻找频繁项集的函数。
频繁项集来源于项集,所以首先需要构建只有一个元素的项集,再构建只有两个元素的项集,...,一直到有 K 个元素的项集。因此首先需要构建只有一个元素的项集,构建的函数实现如下:
```python
# 构建只有一个元素的项集, 假设dataSet为[[1, 2], [0, 1]. [3, 4]]
# 那么该项集为frozenset({0}), frozenset({1}), frozenset({2}),frozenset({3}), frozenset({4})
def createC1(dataSet):
@ -13,6 +15,11 @@ def createC1(dataSet):
C1.append([item])
C1.sort()
return map(frozenset, C1)
```
有了从无到有之后,接下来需要从 1 到 K。不过需要注意的是这个时候需要排除掉支持度小于最小支持度的项集。代码实现如下
```python
# 从只有k个元素的项集生成有k+1个元素的频繁项集排除掉支持度小于最小支持度的项集
# D为数据集ck为createC1的输出minsupport为最小支持度
@ -35,7 +42,11 @@ def scanD(D, ck, minsupport):
supportData[key] = support
#reList为有k+1个元素的频繁项集supportData为频繁项集对应的支持度
return reList, supportData
```
这就完了吗?还没有,我们还需要一个能够实现构建含有 K 个元素的频繁项集的函数。实现代码如下:
```python
#构建含有k个元素的频繁项集
#如输入为{0},{1},{2}会生成{0,1},{0, 2},{1,2}
def aprioriGen(Lk, k):
@ -48,7 +59,11 @@ def aprioriGen(Lk, k):
if L1 == L2:
relist.append(Lk[i] | Lk[j])
return reList
```
有了以上的函数之后,我们就可以根据生成候选频繁项集的流程,使用这些函数来实现这个功能了。代码如下:
```python
#生成候选的频繁项集列表,以及候选频繁项集的支持度,因为在算可信度时要用到
def apriori(dataSet, minsupport=0.5):
C1 = creatC1(dataSet)
@ -62,12 +77,14 @@ def apriori(dataSet, minsupport=0.5):
supportData.update(supK)
L.append(Lk)
k += 1
# L为候选频繁项集列表supportData为候选频繁项集的支持度
return L, supportData
```
# 寻找频繁项集部分 End
有了候选频繁项集和它的支持度之后,就可以开始着手挖掘关联规则了。在挖掘关联规则时,需要排除可信度比较小的关联规则,所以首先需要实现计算关联规则的可信度的功能。代码实现如下:
# 挖掘关联规则部分 Begin
```python
# 计算关联规则的可信度,并排除可信度小于最小可信度的关联规则
# freqSet为频繁项集H为规则右边可能出现的元素的集合supportData为频繁项集的支持度brl为存放关联规则的列表minConf为最小可信度
def calcConf(freqSet, H, supportData, brl, minConf = 0.7):
@ -78,7 +95,11 @@ def calcConf(freqSet, H, supportData, brl, minConf = 0.7):
brl.append((freqSet - conseq, conseq, conf))
prunedH.append(conseq)
return prunedH
```
接下来就需要实现从频繁项集中生成关联规则的功能了,若已经忘记了算法流程,可以翻看一下上一节的内容,实现如下:
```python
# 从频繁项集中生成关联规则
# freqSet为频繁项集H为规则右边可能出现的元素的集合supportData为频繁项集的支持度brl为存放关联规则的列表minConf为最小可信度
def ruleFromConseq(freqSet, H, supportData, brl, minConf = 0.7):
@ -88,7 +109,11 @@ def ruleFromConseq(freqSet, H, supportData, brl, minConf = 0.7):
Hmp1 = calcConf(freqSet, Hmp1, supporData, brl, minConf)
if len(Hmp1) > 1:
ruleFromConseq(freqSet, Hmp1, supportData, brl, minConf)
```
由于使用`apriori`函数后得到的是一个候选频繁项集的列表,所以需要遍历整个候选频繁项集的列表来挖掘关联规则,所以代码实现如下:
```python
# 从频繁项集中挖掘关联规则
# L为频繁项集 supportData为频繁项集的支持度minConf为最小可信度
def generateRules(L, supportData, minConf = 0.7):
@ -105,4 +130,6 @@ def generateRules(L, supportData, minConf = 0.7):
return digRuleList
# 挖掘关联规则部分 End
```
```
到这里,我们已经实现了`Apriori`算法和关联规则挖掘算法。接下来,将介绍如何使用刚刚实现的算法来挖掘毒蘑菇的共性特征。

@ -1,4 +1,4 @@
# 8.4 实战案例
# 8.4 发现毒蘑菇的特性
最后我们来尝试使用 Apriori 算法来寻找毒蘑菇中的一些公共特征,利用这些特征就能避免吃到那些有毒的蘑菇。现在有这样一个数据集,数据集合中有一个关于蘑菇的 23 种特征的数据集,每一个特征都包含一
个标称数据值。部分数据截图如下:

@ -1,2 +1,2 @@
# 第九章 PageRank
# 第九章 谷歌的网页推荐算法--PageRank

@ -20,37 +20,34 @@
* [4.2 k近邻算法原理](Chapter4/k-近邻算法原理.md)
* [4.3 动手实现k近邻算法](Chapter4/动手实现k-近邻.md)
* [4.4 检测红酒品质](Chapter4/品鉴红酒.md)
* [第五章 线性回归](Chapter5/README.md)
* [5.1 线性回归算法思想](Chapter5/线性回归算法思想.md)
* [第五章 使用线性回归算法预测房价](Chapter5/README.md)
* [5.1 什么是回归](Chapter5/线性回归算法思想.md)
* [5.2 线性回归算法原理](Chapter5/线性回归算法原理.md)
* [5.3 线性回归算法流程](Chapter5/线性回归算法流程.md)
* [5.4 动手实现线性回归](Chapter5/动手实现线性回归.md)
* [5.5 实战案例](Chapter5/实战案例.md)
* [第六章 决策树](Chapter6/README.md)
* [6.1 决策树算法思想](Chapter6/决策树算法思想.md)
* [5.3 动手实现线性回归](Chapter5/动手实现线性回归.md)
* [5.4 预测房价](Chapter5/实战案例.md)
* [第六章 使用决策树算法识别花朵](Chapter6/README.md)
* [6.1 决策树的核心思想](Chapter6/决策树算法思想.md)
* [6.2 决策树算法原理](Chapter6/决策树算法原理.md)
* [6.3 决策树算法流程](Chapter6/决策树算法流程.md)
* [6.4 动手实现决策树](Chapter6/动手实现决策树.md)
* [6.5 实战案例](Chapter6/实战案例.md)
* [第七章 k-均值](Chapter7/README.md)
* [7.1 k-均值算法思想](Chapter7/k-均值算法思想.md)
* [7.2 k-均值算法原理](Chapter7/k-均值算法原理.md)
* [7.3 k-均值算法流程](Chapter7/k-均值算法流程.md)
* [7.4 动手实现k-均值](Chapter7/动手实现k-均值.md)
* [7.5 实战案例](Chapter7/实战案例.md)
* [第八章 Apriori](Chapter8/README.md)
* [6.5 识别花朵](Chapter6/实战案例.md)
* [第七章 使用k均值算法分割图像](Chapter7/README.md)
* [7.1 什么是图像分割](Chapter7/k-均值算法思想.md)
* [7.2 k均值算法原理](Chapter7/k-均值算法原理.md)
* [7.3 图像分割](Chapter7/实战案例.md)
* [第八章 使用Apriori算法找出毒蘑菇的共性](Chapter8/README.md)
* [8.1 关联规则与Apriori](Chapter8/关联规则与Apriori算法.md)
* [8.2 Apriori算法原理](Chapter8/Apriori算法原理.md)
* [8.3 动手实现Apriori](Chapter8/动手实现Apriori.md)
* [8.4 实战案例](Chapter8/实战案例.md)
* [第九章 PageRank](Chapter9/README.md)
* [第九章 谷歌的网页推荐算法--PageRank](Chapter9/README.md)
* [9.1 什么是PageRank](Chapter9/什么是PageRank.md)
* [9.2 PageRank算法原理](Chapter9/PageRank算法原理.md)
* [9.3 动手实现PageRank](Chapter9/动手实现PageRank.md)
* [第十章 推荐系统](Chapter10/README.md)
* [第十章 打造电影推荐系统](Chapter10/README.md)
* [10.1 推荐系统概述](Chapter10/推荐系统概述.md)
* [10.2 基于矩阵分解的协同过滤算法思想](Chapter10/基于矩阵分解的协同过滤算法思想.md)
* [10.3 基于矩阵分解的协同过滤算法原理](Chapter10/基于矩阵分解的协同过滤算法原理.md)
* [10.4 动手实现基于矩阵分解的协同过滤](Chapter10/动手实现基于矩阵分解的协同过滤.md)
* [10.5 实战案例](Chapter10/实战案例.md)
* [10.5 实现电影推荐系统](Chapter10/实战案例.md)

Binary file not shown.
Loading…
Cancel
Save