课程
机器学习 --- 决策树
机器学习 --- 决策树
第1关:什么是决策树
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握决策树的相关基础知识。
引例
在炎热的夏天,没有什么比冰镇后的西瓜更能令人感到心旷神怡的了。现在我要去水果店买西瓜,但什么样的西瓜能入我法眼呢?那根据我的个人习惯,在挑西瓜时可能就有这样的脑回路。
假设现在水果店里有3个西瓜,它们的属性如下:
| 编号 | 瓤是否够红 | 够不够冰 | 是否便宜 | 是否有籽 |
|---|---|---|---|---|
| 1 | 是 | 否 | 是 | 否 |
| 2 | 是 | 是 | 否 | 是 |
| 3 | 否 | 是 | 是 | 否 |
那么根据我的脑回路我会买1和2号西瓜。
其实我的脑回路可以看成一棵树,并且这棵树能够帮助我对买不买西瓜这件事做决策,所以它就是一棵决策树。
决策树的相关概念
决策树是一种可以用于分类与回归的机器学习算法,但主要用于分类。用于分类的决策树是一种描述对实例进行分类的树形结构。决策树由结点和边组成,其中结点分为内部结点和叶子结点,内部结点表示一个特征或者属性,叶子结点表示标签(脑回路图中黄色的是内部结点,蓝色的是叶子结点)。
从代码角度来看,决策树其实可以看成是一堆if-else语句的集合,例如引例中的决策树完全可以看成是如下代码:
if isRed:
if isCold:
if hasSeed:
print("buy")
else:
print("don't buy")
else:
if isCheap:
print("buy")
else:
print("don't buy")
else:
print("don't buy")
因此决策树的一个非常大的优势就是模型的可理解性非常高,甚至可以用来挖掘数据中比较重要的信息。
那么如何构造出一棵好的决策树呢?其实构造决策树时会遵循一个指标,有的是按照信息增益来构建,如ID3算法;有的是信息增益率来构建,如C4.5算法;有的是按照基尼系数来构建的,如CART算法。但不管是使用哪种构建算法,决策树的构建过程通常都是一个递归选择最优特征,并根据特征对训练集进行分割,使得对各个子数据集有一个最好的分类的过程。
这一过程对应着对特征空间的划分,也对应着决策树的构建。一开始,构建决策树的根结点,将所有训练数据都放在根结点。选择一个最优特征,并按照这一特征将训练数据集分割成子集,使得各个子集有一个在当前条件下最好的分类。如果这些子集已经能够被基本正确分类,那么构建叶子结点,并将这些子集分到所对应的叶结点中去;如果还有子集不能被基本正确分类,那么就对这些子集选择新的最优特征,继续对其进行分割,并构建相应的结点。如此递归进行下去,直至所有训练数据子集被基本正确分类,或者没有合适的特征为止。最后每个子集都被分到叶子结点上,即都有了明确的类别。这就构建出了一棵决策树。
编程要求
根据本关所学习到的知识,完成所有选择题。
测试说明
平台会对你的选项进行判断,如果实际输出结果与预期结果相同,则通关;反之,则 GameOver。
选择题
第1题 (多选题)
下列说法正确的是?
- A. 训练决策树的过程就是构建决策树的过程
- B. ID3算法是根据信息增益来构建决策树
- C. C4.5算法是根据基尼系数来构建决策树
- D. 决策树模型的可理解性不高
我的答案: A, B
第2题 (单选题)
下列说法错误的是?
- A. 从树的根节点开始,根据特征的值一步一步走到叶子节点的过程是决策树做决策的过程
- B. 决策树只能是一棵二叉树
- C. 根节点所代表的特征是最优特征
我的答案: B
第2关:信息熵与信息增益
任务描述
本关任务:掌握什么是信息增益,完成计算信息增益的程序设计。
相关知识
为了完成本关任务,你需要掌握:
-
信息熵;
-
条件熵;
-
信息增益。
信息熵
信息是个很抽象的概念。人们常常说信息很多,或者信息较少,但却很难说清楚信息到底有多少。比如一本五十万字的中文书到底有多少信息量。
直到1948年,香农提出了**“信息熵”**的概念,才解决了对信息的量化度量问题。信息熵这个词是香农从热力学中借用过来的。热力学中的热熵是表示分子状态混乱程度的物理量。香农用信息熵的概念来描述信源的不确定度。信源的不确定性越大,信息熵也越大。
从机器学习的角度来看,信息熵表示的是信息量的期望值。如果数据集中的数据需要被分成多个类别,则信息量I(xi)的定义如下(其中xi表示多个类别中的第i个类别,p(xi)数据集中类别为xi的数据在数据集中出现的概率表示):
I(Xi)=−log2p(xi)
由于信息熵是信息量的期望值,所以信息熵H(X)的定义如下(其中n为数据集中类别的数量):
H(X)=−sumi=1np(xi)log2p(xi)
从这个公式也可以看出,如果概率是0或者是1的时候,熵就是0(因为这种情况下随机变量的不确定性是最低的)。那如果概率是0.5,也就是五五开的时候,此时熵达到最大,也就是1。(就像扔硬币,你永远都猜不透你下次扔到的是正面还是反面,所以它的不确定性非常高)。所以呢,熵越大,不确定性就越高。
条件熵
在实际的场景中,我们可能需要研究数据集中某个特征等于某个值时的信息熵等于多少,这个时候就需要用到条件熵。条件熵H(Y|X)表示特征X为某个值的条件下,类别为Y的熵。条件熵的计算公式如下:
H(Y∣X)=sumi=1npiH(Y∣X=xi)
当然条件熵的性质也和熵的性质一样,概率越确定,条件熵就越小,概率越五五开,条件熵就越大。
信息增益
现在已经知道了什么是熵,什么是条件熵。接下来就可以看看什么是信息增益了。所谓的信息增益就是表示我已知条件X后能得到信息Y的不确定性的减少程度。
就好比,我在玩读心术。你心里想一件东西,我来猜。我已开始什么都没问你,我要猜的话,肯定是瞎猜。这个时候我的熵就非常高。然后我接下来我会去试着问你是非题,当我问了是非题之后,我就能减小猜测你心中想到的东西的范围,这样其实就是减小了我的熵。那么我熵的减小程度就是我的信息增益。
所以信息增益如果套上机器学习的话就是,如果把特征A对训练集D的信息增益记为g(D, A)的话,那么g(D, A)的计算公式就是:
g(D,A)=H(D)−H(D,A)
为了更好的解释熵,条件熵,信息增益的计算过程,下面通过示例来描述。假设我现在有这一个数据集,第一列是编号,第二列是性别,第三列是活跃度,第四列是客户是否流失的标签(0表示未流失,1表示流失)。
| 编号 | 性别 | 活跃度 | 是否流失 |
|---|---|---|---|
| 1 | 男 | 高 | 0 |
| 2 | 女 | 中 | 0 |
| 3 | 男 | 低 | 1 |
| 4 | 女 | 高 | 0 |
| 5 | 男 | 高 | 0 |
| 6 | 男 | 中 | 0 |
| 7 | 男 | 中 | 1 |
| 8 | 女 | 中 | 0 |
| 9 | 女 | 低 | 1 |
| 10 | 女 | 中 | 0 |
| 11 | 女 | 高 | 0 |
| 12 | 男 | 低 | 1 |
| 13 | 女 | 低 | 1 |
| 14 | 男 | 高 | 0 |
| 15 | 男 | 高 | 0 |
假如要算性别和活跃度这两个特征的信息增益的话,首先要先算总的熵和条件熵。总的熵其实非常好算,就是把标签作为随机变量X。上表中标签只有两种(0和1)因此随机变量X的取值只有0或者1。所以要计算熵就需要先分别计算标签为0的概率和标签为1的概率。从表中能看出标签为0的数据有10条,所以标签为0的概率等于2/3。标签为1的概率为1/3。所以熵为:
−(1/3)∗log(1/3)−(2/3)∗log(2/3)=0.9182
接下来就是条件熵的计算,以性别为男的熵为例。表格中性别为男的数据有8条,这8条数据中有3条数据的标签为1,有5条数据的标签为0。所以根据条件熵的计算公式能够得出该条件熵为:
−(3/8)∗log(3/8)−(5/8)∗log(5/8)=0.9543
根据上述的计算方法可知,总熵为:
−(5/15)∗log(5/15)−(10/15)∗log(10/15)=0.9182
性别为男的熵为:
−(3/8)∗log(3/8)−(5/8)∗log(5/8)=0.9543
性别为女的熵为:
−(2/7)∗log(2/7)−(5/7)∗log(5/7)=0.8631
活跃度为低的熵为:
−(4/4)∗log(4/4)−0=0
活跃度为中的熵为:
−(1/5)∗log(1/5)−(4/5)∗log(4/5)=0.7219
活跃度为高的熵为:
−0−(6/6)∗log(6/6)=0
现在有了总的熵和条件熵之后就能算出性别和活跃度这两个特征的信息增益了。
**性别的信息增益=总的熵-(8/15)性别为男的熵-(7/15)性别为女的熵=0.0064
**活跃度的信息增益=总的熵-(6/15)*活跃度为高的熵-(5/15)活跃度为中的熵-(4/15)活跃度为低的熵=0.6776
那信息增益算出来之后有什么意义呢?回到读心术的问题,为了我能更加准确的猜出你心中所想,我肯定是问的问题越好就能猜得越准!换句话来说我肯定是要想出一个信息增益最大(减少不确定性程度最高)的问题来问你。其实ID3算法也是这么想的。ID3算法的思想是从训练集D中计算每个特征的信息增益,然后看哪个最大就选哪个作为当前结点。然后继续重复刚刚的步骤来构建决策树。
编程要求
根据提示,在右侧编辑器补充代码,完成calcInfoGain函数实现计算信息增益。
calcInfoGain函数中的参数:
-
feature:测试用例中字典里的feature,类型为ndarray; -
label:测试用例中字典里的label,类型为ndarray; -
index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益。
测试说明
平台会对你编写的代码进行测试,期望您的代码根据输入来输出正确的信息增益,以下为其中一个测试用例:
测试输入:
{'feature':[[0, 1], [1, 0], [1, 2], [0, 0], [1, 1]], 'label':[0, 1, 0, 0, 1], 'index': 0}
预期输出:
0.419973
提示:
计算log可以使用NumPy中的log2函数
第3关:使用ID3算法构建决策树
任务描述
本关任务:补充python代码,完成DecisionTree类中的fit和predict函数。
相关知识
为了完成本关任务,你需要掌握:
-
ID3算法构造决策树的流程; -
如何使用构造好的决策树进行预测。
ID3算法
ID3算法其实就是依据特征的信息增益来构建树的。其大致步骤就是从根结点开始,对结点计算所有可能的特征的信息增益,然后选择信息增益最大的特征作为结点的特征,由该特征的不同取值建立子结点,然后对子结点递归执行上述的步骤直到信息增益很小或者没有特征可以继续选择为止。
因此,ID3算法伪代码如下:
#假设数据集为D,标签集为A,需要构造的决策树为tree
def ID3(D, A):
if D中所有的标签都相同:
return 标签
if 样本中只有一个特征或者所有样本的特征都一样:
对D中所有的标签进行计数
return 计数最高的标签
计算所有特征的信息增益
选出增益最大的特征作为最佳特征(best_feature)
将best_feature作为tree的根结点
得到best_feature在数据集中所有出现过的值的集合(value_set)
for value in value_set:
从D中筛选出best_feature=value的子数据集(sub_feature)
从A中筛选出best_feature=value的子标签集(sub_label)
#递归构造tree
tree[best_feature][value] = ID3(sub_feature, sub_label)
return tree
使用决策树进行预测
决策树的预测思想非常简单,假设现在已经构建出了一棵用来决策是否买西瓜的决策树。
并假设现在在水果店里有这样一个西瓜,其属性如下:
| 瓤是否够红 | 够不够冰 | 是否便宜 | 是否有籽 |
|---|---|---|---|
| 是 | 否 | 是 | 否 |
那买不买这个西瓜呢?只需把西瓜的属性代入决策树即可。决策树的根结点是瓤是否够红,所以就看西瓜的属性,经查看发现够红,因此接下来就看够不够冰。而西瓜不够冰,那么看是否便宜。发现西瓜是便宜的,所以这个西瓜是可以买的。
因此使用决策树进行预测的伪代码也比较简单,伪代码如下:
#tree表示决策树,feature表示测试数据
def predict(tree, feature):
if tree是叶子结点:
return tree
根据feature中的特征值走入tree中对应的分支
if 分支依然是课树:
result = predict(分支, feature)
return result
编程要求
填写fit(self, feature, label)函数,实现ID3算法,要求决策树保存在self.tree中。其中:
-
feature:训练集数据,类型为ndarray,数值全为整数; -
label:训练集标签,类型为ndarray,数值全为整数。
填写predict(self, feature)函数,实现预测功能,并将标签返回,其中:
feature:测试集数据,类型为ndarray,数值全为整数。(PS:feature中有多条数据)
测试说明
只需完成fit与predict函数即可,程序内部会调用您所完成的fit函数构建模型并调用predict函数来对数据进行预测。预测的准确率高于0.92视为过关。(PS:若self.tree is None则会打印决策树构建失败)
第4关:信息增益率
任务描述
本关任务:根据本关所学知识,完成calcInfoGainRatio函数。
相关知识
为了完成本关任务,你需要掌握:信息增益率
信息增益率
由于在使用信息增益这一指标进行划分时,更喜欢可取值数量较多的特征。为了减少这种偏好可能带来的不利影响,Ross Quinlan使用了信息增益率这一指标来选择最优划分属性。
信息增益率的数学定义为如下,其中D表示数据集,a表示数据集中的某一列,Gain(D,a)表示D中a的信息增益,V表示a这一列中取值的集合,v表示V中的某种取值,∣D∣表示D中样本的数量,∣Dv∣表示D中a这一列中值等于v的数量。
Gain_ratio(D,a)=−v=1∑V∣D∣∣Dv∣log2∣D∣∣Dv∣Gain(D,a)
从公式可以看出,信息增益率很好算,只是用信息增益除以另一个分母,该分母通常称为固有值。举个例子,还是使用第二关中提到过的数据集,第一列是编号,第二列是性别,第三列是活跃度,第四列是客户是否流失的标签(0表示未流失,1表示流失)。
| 编号 | 性别 | 活跃度 | 是否流失 |
|---|---|---|---|
| 1 | 男 | 高 | 0 |
| 2 | 女 | 中 | 0 |
| 3 | 男 | 低 | 1 |
| 4 | 女 | 高 | 0 |
| 5 | 男 | 高 | 0 |
| 6 | 男 | 中 | 0 |
| 7 | 男 | 中 | 1 |
| 8 | 女 | 中 | 0 |
| 9 | 女 | 低 | 1 |
| 10 | 女 | 中 | 0 |
| 11 | 女 | 高 | 0 |
| 12 | 男 | 低 | 1 |
| 13 | 女 | 低 | 1 |
| 14 | 男 | 高 | 0 |
| 15 | 男 | 高 | 0 |
根据第二关已经知道性别的信息增益为0.0064,设a为性别,则有Gain(D,a)=0.0064。由根据数据可知,V=2,假设当v=1时表示性别为男,v=2时表示性别为女,则有∣D∣=15,∣D1∣=8,∣D2∣=7。因此根据信息增益率的计算公式可知Gainratio(D,a)=0.0642。同理可以算出活跃度的信息增益率为0.4328。
编程要求
根据提示,在右侧编辑器补充代码,完成calcInfoGainRatio函数实现计算信息增益。
calcInfoGainRatio函数中的参数:
-
feature:测试用例中字典里的feature,类型为ndarray; -
label:测试用例中字典里的label,类型为ndarray; -
index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算信息增益率。
测试说明
平台会对你编写的代码进行测试,期望您的代码根据输入来输出正确的信息增益,以下为其中一个测试用例:
测试输入:
{'feature':[[0, 1], [1, 0], [1, 2], [0, 0], [1, 1]], 'label':[0, 1, 0, 0, 1], 'index': 0}
预期输出:
0.432538
提示:
计算log可以使用NumPy中的log2函数
第5关:基尼系数
任务描述
本关任务:根据本关所学知识,完成calcGini函数。
相关知识
为了完成本关任务,你需要掌握:基尼系数。
基尼系数
在ID3算法中我们使用了信息增益来选择特征,信息增益大的优先选择。在C4.5算法中,采用了信息增益率来选择特征,以减少信息增益容易选择特征值多的特征的问题。但是无论是ID3还是C4.5,都是基于信息论的熵模型的,这里面会涉及大量的对数运算。能不能简化模型同时也不至于完全丢失熵模型的优点呢?当然有!那就是基尼系数!
CART算法使用基尼系数来代替信息增益率,基尼系数代表了模型的不纯度,基尼系数越小,则不纯度越低,特征越好。这和信息增益与信息增益率是相反的(它们都是越大越好)。
基尼系数的数学定义为如下,其中D表示数据集,pk表示D中第k个类别在D中所占比例。
Gini(D)=1−sumk=1∣y∣pk2
从公式可以看出,相比于信息增益和信息增益率,计算起来更加简单。举个例子,还是使用第二关中提到过的数据集,第一列是编号,第二列是性别,第三列是活跃度,第四列是客户是否流失的标签(0表示未流失,1表示流失)。
| 编号 | 性别 | 活跃度 | 是否流失 |
|---|---|---|---|
| 1 | 男 | 高 | 0 |
| 2 | 女 | 中 | 0 |
| 3 | 男 | 低 | 1 |
| 4 | 女 | 高 | 0 |
| 5 | 男 | 高 | 0 |
| 6 | 男 | 中 | 0 |
| 7 | 男 | 中 | 1 |
| 8 | 女 | 中 | 0 |
| 9 | 女 | 低 | 1 |
| 10 | 女 | 中 | 0 |
| 11 | 女 | 高 | 0 |
| 12 | 男 | 低 | 1 |
| 13 | 女 | 低 | 1 |
| 14 | 男 | 高 | 0 |
| 15 | 男 | 高 | 0 |
从表格可以看出,D中总共有2个类别,设类别为0的比例为p1,则有p1=1510。设类别为1的比例为p2,则有p2=155。根据基尼系数的公式可知Gini(D)=1−(p12+p22)=0.4444。
上面是基于数据集D的基尼系数的计算方法,那么基于数据集D与特征a的基尼系数怎样计算呢?其实和信息增益率的套路差不多。计算公式如下:
Gini(D,a)=sumv=1V∣D∣∣Dv∣Gini(Dv)
还是以用户流失的数据为例,现在算一算性别的基尼系数。设性别男为v=1,性别女为v=2则有∣D∣=15,∣D1∣=8,∣D2∣=7,Gini(D1)=0.46875,Gini(D2)=0.40816。所以Gini(D,a)=0.44048。
编程要求
根据提示,在右侧编辑器补充代码,完成calcGini函数实现计算信息增益。
calcGini函数中的参数:
-
feature:测试用例中字典里的feature,类型为ndarray; -
label:测试用例中字典里的label,类型为ndarray; -
index:测试用例中字典里的index,即feature部分特征列的索引。该索引指的是feature中第几个特征,如index:0表示使用第一个特征来计算基尼系数。
测试说明
平台会对你编写的代码进行测试,期望您的代码根据输入来输出正确的信息增益,以下为其中一个测试用例:
测试输入:
{'feature':[[0, 1], [1, 0], [1, 2], [0, 0], [1, 1]], 'label':[0, 1, 0, 0, 1], 'index': 0}
预期输出:
0.266667
第6关:预剪枝与后剪枝
任务描述
本关任务:补充python代码,完成DecisionTree类中的fit和predict函数。
相关知识
为了完成本关任务,你需要掌握:
-
为什么需要剪枝;
-
预剪枝;
-
后剪枝。
为什么需要剪枝
决策树的生成是递归地去构建决策树,直到不能继续下去为止。这样产生的树往往对训练数据有很高的分类准确率,但对未知的测试数据进行预测就没有那么准确了,也就是所谓的过拟合。
决策树容易过拟合的原因是在构建决策树的过程时会过多地考虑如何提高对训练集中的数据的分类准确率,从而会构建出非常复杂的决策树(树的宽度和深度都比较大)。在之前的实训中已经提到过,**模型的复杂度越高,模型就越容易出现过拟合的现象。**所以简化决策树的复杂度能够有效地缓解过拟合现象,而简化决策树最常用的方法就是剪枝。剪枝分为预剪枝与后剪枝。
预剪枝
预剪枝的核心思想是在决策树生成过程中,对每个结点在划分前先进行一个评估,若当前结点的划分不能带来决策树泛化性能提升,则停止划分并将当前结点标记为叶结点。
想要评估决策树算法的泛化性能如何,方法很简单。可以将训练数据集中随机取出一部分作为验证数据集,然后在用训练数据集对每个结点进行划分之前用当前状态的决策树计算出在验证数据集上的正确率。正确率越高说明决策树的泛化性能越好,如果在划分结点的时候发现泛化性能有所下降或者没有提升时,说明应该停止划分,并用投票计数的方式将当前结点标记成叶子结点。
举个例子,假如上一关中所提到的用来决定是否买西瓜的决策树模型已经出现过拟合的情况,模型如下:
假设当模型在划分是否便宜这个结点前,模型在验证数据集上的正确率为0.81。但在划分后,模型在验证数据集上的正确率降为0.67。此时就不应该划分是否便宜这个结点。所以预剪枝后的模型如下:
从上图可以看出,预剪枝能够降低决策树的复杂度。这种预剪枝处理属于贪心思想,但是贪心有一定的缺陷,就是可能当前划分会降低泛化性能,但在其基础上进行的后续划分却有可能导致性能显著提高。所以有可能会导致决策树出现欠拟合的情况。
后剪枝
后剪枝是先从训练集生成一棵完整的决策树,然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能够带来决策树泛化性能提升,则将该子树替换为叶结点。
后剪枝的思路很直接,对于决策树中的每一个非叶子结点的子树,我们尝试着把它替换成一个叶子结点,该叶子结点的类别我们用子树所覆盖训练样本中存在最多的那个类来代替,这样就产生了一个简化决策树,然后比较这两个决策树在测试数据集中的表现,如果简化决策树在验证数据集中的准确率有所提高,那么该子树就可以替换成叶子结点。该算法以bottom-up的方式遍历所有的子树,直至没有任何子树可以替换使得测试数据集的表现得以改进时,算法就可以终止。
从后剪枝的流程可以看出,后剪枝是从全局的角度来看待要不要剪枝,所以造成欠拟合现象的可能性比较小。但由于后剪枝需要先生成完整的决策树,然后再剪枝,所以后剪枝的训练时间开销更高。
编程要求
填写fit(self, train_feature, train_label, val_featrue, val_label)函数,实现带后剪枝的ID3算法,要求决策树保存在self.tree中。其中:
-
train_feature:训练集数据,类型为ndarray,数值全为整数; -
train_label:训练集标签,类型为ndarray,数值全为整数; -
val_feature:验证集数据,类型为ndarray,数值全为整数; -
val_label:验证集标签,类型为ndarray,数值全为整数。
填写predict(self, feature)函数,实现预测功能,并将标签返回,其中:
feature:测试集数据,类型为ndarray,数值全为整数。(PS:feature中有多条数据)
测试说明
只需完成fit与predict函数即可,程序内部会调用您所完成的fit函数构建模型并调用predict函数来对数据进行预测。预测的准确率高于0.935视为过关。(PS:若self.tree is None则会打印决策树构建失败)
第7关:鸢尾花识别
任务描述
本关任务:使用sklearn完成鸢尾花分类任务。
相关知识
为了完成本关任务,你需要掌握如何使用sklearn提供的DecisionTreeClassifier。
数据简介
鸢尾花数据集是一类多重变量分析的数据集。通过花萼长度,花萼宽度,花瓣长度,花瓣宽度4个属性预测鸢尾花卉属于(Setosa,Versicolour,Virginica)三个种类中的哪一类(其中分别用0,1,2代替)。
数据集中部分数据与标签如下图所示:
DecisionTreeClassifier
DecisionTreeClassifier的构造函数中有两个常用的参数可以设置:
-
criterion:划分节点时用到的指标。有gini(基尼系数),entropy(信息增益)。若不设置,默认为gini -
max_depth:决策树的最大深度,如果发现模型已经出现过拟合,可以尝试将该参数调小。若不设置,默认为None
和sklearn中其他分类器一样,DecisionTreeClassifier类中的fit函数用于训练模型,fit函数有两个向量输入:
-
X:大小为[样本数量,特征数量]的ndarray,存放训练样本; -
Y:值为整型,大小为[样本数量]的ndarray,存放训练样本的分类标签。
DecisionTreeClassifier类中的predict函数用于预测,返回预测标签,predict函数有一个向量输入:
X:大小为[样本数量,特征数量]的ndarray,存放预测样本。
DecisionTreeClassifier的使用代码如下:
from sklearn.tree import DecisionTreeClassifier
clf = tree.DecisionTreeClassifier()
clf.fit(X_train, Y_train)
result = clf.predict(X_test)
编程要求
补充python代码,实现鸢尾花数据的分类任务,其中训练集数据保存在./step7/train_data.csv中,训练集标签保存在。./step7/train_label.csv中,测试集数据保存在。./step7/test_data.csv中。请将对测试集的预测结果保存至。./step7/predict.csv中。这些csv文件可以使用pandas读取与写入。
注意:当使用pandas读取完csv文件后,请将读取到的DataFrame转换成ndarray类型。这样才能正常的使用fit和predict。
示例代码:
import pandas as pd
# as_matrix()可以将DataFrame转换成ndarray
# 此时train_df的类型为ndarray而不是DataFrame
train_df = pd.read_csv('train_data.csv').as_matrix()
数据文件格式如下图所示:
标签文件格式如下图所示:
PS:predict.csv文件的格式必须与标签文件格式一致。
测试说明
只需将结果保存至./step7/predict.csv即可,程序内部会检测您的代码,预测准确率高于0.95视为过关。
机器学习 --- 模型评估、选择与验证
第1关:为什么要有训练集与测试集
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握:1.为什么要有训练集与测试集,2.如何划分训练集与测试集。
为什么要有训练集与测试集
我们想要利用收集的西瓜数据构建一个机器学习模型,用来预测新的西瓜的好坏,但在将模型用于新的测量数据之前,我们需要知道模型是否有效,也就是说,我们是否应该相信它的预测结果。不幸的是,我们不能将用于构建模型的数据用于评估模型的性能。因为我们的模型会一直记住整个训练集,所以,对于训练集中的任何数据点总会预测成正确的标签。这种记忆无法告诉我们模型的泛化能力如何,即预测新样本的能力如何。我们要用新数据来评估模型的性能。新数据是指模型之前没见过的数据,而我们有这些新数据的标签。通常的做法是,我们把手头上的数据分为两部分,训练集与测试集。训练集用来构建机器学习模型,测试集用来评估模型性能。
如何划分训练集与测试集
通常我们将手头数据的百分之 70 或 80 用来训练数据,剩下的百分之 30 或 20 作为测试用来评估模型性能。值得注意的是,在划分数据集之前,我们要先把手头上的数据的顺序打乱,因为我们搜集数据时,数据可能是按照标签排放的。比如,现在有 100 个西瓜的数据,前 50 个是好瓜,后 50 个是坏瓜,如果将后面的 30 个西瓜数据当做测试集,这时测试集中只有坏瓜一个类别,这无法告诉我们模型的泛化能力如何,所以我们将数据打乱,确保测试集中包含所有类别的数据。
编程要求
根据相关知识,按照要求完成右侧选择题任务。
测试说明
平台会对你的代码进行运行测试,如果实际输出与预期输出相同,则算通关。
选择题
第1题 (单选题)
下面正确的是?
- A. 将手头上所有的数据拿来训练模型,预测结果正确率最高的模型就是我们所要选的模型。
- B. 将所有数据中的前百分之70拿来训练模型,剩下的百分之30作为测试集,预测结果正确率最高的模型就是我们所要选的模型。
- C. 将所有数据先随机打乱顺序,一半用来训练模型,一半作为测试集,预测结果正确率最高的模型就是我们所要选的模型。
- D. 将所有数据先随机打乱顺序,百分之80用来训练模型,剩下的百分之20作为测试集,预测结果正确率最高的模型就是我们所要选的模型。
我的答案: D
第2题 (单选题)
训练集与测试集的划分对最终模型的确定有无影响?
- A. 有
- B. 无
我的答案: A
第2关:欠拟合与过拟合
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握:1.什么是欠拟合与欠拟合的原因,2.什么是过拟合与过拟合的原因。
什么是欠拟合与欠拟合的原因
-
欠拟合:模型在训练集上误差很高;
-
欠拟合原因:模型过于简单,没有很好的捕捉到数据特征,不能很好的拟合数据。
如上面例子,我们的数据是一份非线性数据,如果你想要用线性回归来拟合这份数据,由于数据是非线性的,模型是线性,则过于简单。所以,无论模型怎么训练,最终都不能很好的拟合数据。
什么是过拟合与过拟合的原因
-
过拟合:在训练集上误差低,测试集上误差高;
-
过拟合原因:模型把数据学习的太彻底,以至于把噪声数据的特征也学习到了,这样就会导致在后期测试的时候不能够很好地识别数据,模型泛化能力太差。
如上面例子,在训练集上,模型为了拟合数据,添加了更多的多次项,使模型过于复杂,对噪音数据也能很好的拟合,所以在训练集上正确率很高,而在测试集上没有这些噪音数据,所以正确率很低。
在分类的问题中,如下例子:
欠拟合:由于模型过于简单,只学习到绿色这个特征,只要是绿色就都判断为树叶,结果将树当做了树叶。
过拟合:模型过于复杂,将锯齿这个普通特征,看的过于重要,认为必须有锯齿才是树叶,结果将树叶误判为不是树叶。
编程要求
根据相关知识,按照要求完成右侧选择题任务。
测试说明
平台会对你的代码进行运行测试,如果实际输出与预期输出相同,则算通关。
选择题
第1题 (单选题)
](https://data.educoder.net/attachments/download/bEUya2FvM1k0bVo5S1JVckl0djNDdz09) 请问,图中A与B分别处于什么状态?
- A. 欠拟合,欠拟合
- B. 欠拟合,过拟合
- C. 过拟合,欠拟合
- D. 过拟合,过拟合
我的答案: B
第2题 (多选题)
如果一个模型在训练集上正确率为99%,测试集上正确率为60%。我们应该怎么做?
- A. 加入正则化项
- B. 增加训练样本数量
- C. 增加模型复杂度
- D. 减少模型复杂度
我的答案: A, B, D
第3关:偏差与方差
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握:1.模型误差来源,2.偏差与方差。
模型误差来源
在上一部分,我们知道了欠拟合是模型在训练集上误差过高,过拟合模型是在训练集上误差低,在测试集上误差高。那么模型误差的来源是什么呢?
其实,模型在训练集上的误差来源主要来自于偏差,在测试集上误差来源主要来自于方差。
上图表示,如果一个模型在训练集上正确率为 80%,测试集上正确率为 79% ,则模型欠拟合,其中 20% 的误差来自于偏差,1% 的误差来自于方差。如果一个模型在训练集上正确率为 99%,测试集上正确率为 80% ,则模型过拟合,其中 1% 的误差来自于偏差,19% 的误差来自于方差。
可以看出,欠拟合是一种高偏差的情况。过拟合是一种低偏差,高方差的情况。
偏差与方差
-
偏差:预计值的期望与真实值之间的差距;
-
方差:预测值的离散程度,也就是离其期望值的距离。
以射击打靶为例,蓝色的小点是我们在靶子上的射击记录,蓝色点的质心(黑色点)到靶心的距离为偏差,某个点到质心的距离为方差。所以,某个点到质心的误差就是由偏差与方差所组成。那么,为什么欠拟合是一直高偏差情况,过拟合是一种低偏差高方差情况呢?
我们知道,欠拟合是因为模型过于简单,模型过于简单我们可以当做是我们射击时射击的范围比较小,它所涵盖的范围不包括靶心,所以无论怎么射击,射击点的质心里靶心的距离都很远,所以偏差很高。但是因为射击范围很小,所以所有射击点相互离的比较紧密,则方差低。
而过拟合是因为模型过于复杂,我们可以理解为这个时候射击的范围很大了,经过不断的训练射击的点的质心离靶心的距离很近了,但是由于数据量有限,而射击范围很大,所以所有射击点之间非常离散,也就是方差很大。
编程要求
根据相关知识,按照要求完成右侧选择题任务。
测试说明
平台会对你的代码进行运行测试,如果实际输出与预期输出相同,则算通关。
选择题
第1题 (单选题)
如果一个模型,它在训练集上正确率为85%,测试集上正确率为80%,则模型是过拟合还是欠拟合?其中,来自于偏差的误差为?来自方差的误差为?
- A. 欠拟合,5%,5%
- B. 欠拟合,15%,5%
- C. 过拟合,15%,15%
- D. 过拟合,5%,5%
我的答案: B
第4关:验证集与交叉验证
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握:1.为什么需要验证集,2.k 折交叉验证。
为什么需要验证集
在机器学习中,通常需要评估若⼲候选模型的表现并从中选择模型。这⼀过程称为模型选择。可供选择的候选模型可以是有着不同超参数的同类模型。以神经网络为例,我们可以选择隐藏层的个数,学习率大小和激活函数。为了得到有效的模型,我们通常要在模型选择上下⼀番功夫。从严格意义上讲,测试集只能在所有超参数和模型参数选定后使⽤⼀次。不可以使⽤测试数据选择模型,如调参。由于⽆法从训练误差估计泛化误差,因此也不应只依赖训练数据选择模型。鉴于此,我们可以预留⼀部分在训练数据集和测试数据集以外的数据来进⾏模型选择。这部分数据被称为验证数据集,简称验证集。
为了方便大家理解,举一个生活中的案例进行类比,我们一般是通过考试衡量学生的学习情况。老师上完课后,给学生布置的作业相当于训练数据集,中期的测试题相当于验证集,期末考试题相当于测试数据集。为了更加客观的衡量学生学习情况,期末考试题的内容不应该出现在平常的作业题和中期的测试题中,因为之前做过的题,对于计算机而言,相当于已经记住了,如果再次做同样的题,准确率就会很高。同样的道理,平常的作业题也不应该出现在中期的测试题里。中期的测试题,是为了掌握学生的学习情况,了解自己哪些方面内容没掌握,从而调整下一步学习的方向,为期末考试做好准备。
k折交叉验证
由于验证数据集不参与模型训练,当训练数据不够⽤时,预留⼤量的验证数据显得太奢侈。⼀种改善的⽅法是 K 折交叉验证。在 K 折交叉验证中,我们把原始训练数据集分割成 K 个不重合的⼦数据集,然后我们做K次模型训练和验证。每⼀次,我们使⽤⼀个⼦数据集验证模型,并使⽤其它 K−1 个⼦数据集来训练模型。在这 K 次训练和验证中,每次⽤来验证模型的⼦数据集都不同。最后,我们对这 K 次训练误差和验证误差分别求平均。 k 的值由我们自己来指定,如以下为 5 折交叉验证。
还是以考试为例,解释上图内容。交叉验证,相当于把平常的作业题和中期的测试题合并成一个题库,然后等分成几份。图中所示,将题库分成了五份,第一行的意思是,先让学生做后面的四份训练题,再用第一份题进行测试。以此类推,再重复四次,每一次相当于重新进行学习。最后,取五次的平均成绩,平均成绩高,说明老师的教学方法好,对应到模型,就是超参数更好。
集成学习
在机器学习的有监督学习算法中,我们的目标是学习出一个稳定的且在各个方面表现都较好的模型,但实际情况往往不这么理想,有时我们只能得到多个有偏好的模型(弱监督模型,在某些方面表现的比较好)。集成学习就是组合这里的多个弱监督模型以期得到一个更好更全面的强监督模型。集成学习潜在的思想是即便某一个弱分类器得到了错误的预测,其他的弱分类器也可以将错误纠正回来。集成方法是将几种机器学习技术组合成一个预测模型的元算法,以达到减小方差、偏差或改进预测的效果。
自助法
在统计学中,自助法是一种从给定训练集中有放回的均匀抽样,也就是说,每当选中一个样本,它等可能地被再次选中并被再次添加到训练集中。自助法以自助采样法为基础,给定包含 m 个样本的数据集 D,我们对它进行采样产生数据集 D’;每次随机从 D 中挑选一个赝本,将其拷贝放入 D’,然后再将该样本放回初始数据集 D 中,使得该样本在下次采样时仍有可能被采到;这个过程重复执行 m 次后,就得到了包含m个样本的数据集 D’,这就是自助采样的结果。自助法在数据集较小、难以有效划分训练/测试集时很有用;此外,自助法能从初始数据集中产生多个不同的训练集,这对集成学习等方法有很大的好处。然而,自助法产生的数据集改变了初始数据集的分布,这会引入估计偏差。
编程要求
根据相关知识,按照要求完成右侧选择题任务。
测试说明
平台会对你的代码进行运行测试,如果实际输出与预期输出相同,则算通关。
选择题
第1题 (单选题)
假设,我们现在利用5折交叉验证的方法来确定模型的超参数,一共有4组超参数,我们可以知道,5折交叉验证,每一组超参数将会得到5个子模型的性能评分,假设评分如下,我们应该选择哪组超参数?
- A. 子模型1:0.8 子模型2:0.7 子模型3:0.8 子模型4:0.6 子模型5:0.5
- B. 子模型1:0.9 子模型2:0.7 子模型3:0.8 子模型4:0.6 子模型5:0.5
- C. 子模型1:0.5 子模型2:0.6 子模型3:0.7 子模型4:0.6 子模型5:0.5
- D. 子模型1:0.8 子模型2:0.8 子模型3:0.8 子模型4:0.8 子模型5:0.6
我的答案: D
第2题 (多选题)
下列说法正确的是?
- A. 相比自助法,在初始数据量较小时交叉验证更常用。
- B. 自助法对集成学习方法有很大的好处
- C. 使用交叉验证能够增加模型泛化能力
- D. 在数据难以划分训练集测试集时,可以使用自助法
我的答案: B, C, D
第5关:衡量回归的性能指标
任务描述
本关任务:根据本关卡所学知识,完成选择题。
相关知识
为了完成本关任务,你需要掌握:1.均方误差 (MSE),2.均方根误差 (RMSE),3.平均绝对误差 (MAE),4. R-Squared 。
前言
大家知道已经,机器学习通常都是将训练集上的数据对模型进行训练,然后再将测试集上的数据给训练好的模型进行预测,最后根据模型性能的好坏选择模型,对于分类问题,大家很容易想到,可以使用正确率来评估模型的性能,那么回归问题可以使用哪些指标用来评估呢?
MSE
MSE (Mean Squared Error)叫做均方误差,公式如下:
m1sumi=1m(yi−pi)2
其中yi表示第 i 个样本的真实标签,pi表示模型对第 i 个样本的预测标签。线性回归的目的就是让损失函数最小。那么模型训练出来了,我们在测试集上用损失函数来评估模型就行了。
RMSE
RMSE(Root Mean Squard Error)均方根误差,公式如下:
sqrtm1sumi=1m(yi−pi)2
RMSE 其实就是 MSE 开个根号。有什么意义呢?其实实质是一样的。只不过用于数据更好的描述。
例如:要做房价预测,每平方是万元,我们预测结果也是万元。那么差值的平方单位应该是千万级别的。那我们不太好描述自己做的模型效果。怎么说呢?我们的模型误差是多少千万?于是干脆就开个根号就好了。我们误差的结果就跟我们数据是一个级别的了,在描述模型的时候就说,我们模型的误差是多少万元。
MAE
MAE (平均绝对误差),公式如下:
m1sumi=1m∣yi−pi∣
MAE 虽然不作为损失函数,确是一个非常直观的评估指标,它表示每个样本的预测标签值与真实标签值的 L1 距离。
R-Squared
上面的几种衡量标准针对不同的模型会有不同的值。比如说预测房价 那么误差单位就是万元。数子可能是 3,4 ,5 之类的。那么预测身高就可能是 0.1,0.6 之类的。没有什么可读性,到底多少才算好呢?不知道,那要根据模型的应用场景来。 看看分类算法的衡量标准就是正确率,而正确率又在 0~1 之间,最高百分之百。最低 0 。如果是负数,则考虑非线性相关。很直观,而且不同模型一样的。那么线性回归有没有这样的衡量标准呢? R-Squared 就是这么一个指标,公式如下:
R2=1−sumi(ymeani−yi)2sumi(pi−yi)2
其中ymean表示所有测试样本标签值的均值。为什么这个指标会有刚刚我们提到的性能呢?我们分析下公式:
其实分子表示的是模型预测时产生的误差,分母表示的是对任意样本都预测为所有标签均值时产生的误差,由此可知:
-
R2leq1,当我们的模型不犯任何错误时,取最大值 1。
-
当我们的模型性能跟基模型性能相同时,取 0。
-
如果为负数,则说明我们训练出来的模型还不如基准模型,此时,很有可能我们的数据不存在任何线性关系。
编程要求
根据相关知识,按照要求完成右侧选择题任务。
测试说明
平台会对你的代码进行运行测试,如果实际输出与预期输出相同,则算通关。
选择题
第1题 (多选题)
下列说法正确的是?
- A. 相比MSE指标,MAE对噪声数据不敏感
- B. RMSE指标值越小越好
- C. R-Squared指标值越小越好
- D. 当我们的模型不犯任何错时,R-Squared值为0
我的答案: A, B
第6关:准确度的陷阱与混淆矩阵
任务描述
本关任务:填写 python 代码,完成 confusion_matrix 函数实现二分类混淆矩阵的构建。
相关知识
为了完成本关任务,你需要掌握:
-
准确度的缺陷;
-
混淆矩阵。
准确度的缺陷
准确度这个概念相信对于大家来说肯定并不陌生,就是正确率。例如模型的预测结果与数据真实结果如下表所示:
| 编号 | 预测结果 | 真实结果 |
|---|---|---|
| 1 | 1 | 2 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 4 | 1 | 1 |
| 5 | 2 | 3 |
很明显,连小朋友都能算出来该模型的准确度为 3/5。
那么准确对越高就能说明模型的分类性能越好吗?非也!举个例子,现在我开发了一套癌症检测系统,只要输入你的一些基本健康信息,就能预测出你现在是否患有癌症,并且分类的准确度为 0.999。您认为这样的系统的预测性能好不好呢?
您可能会觉得,哇,这么高的准确度!这个系统肯定很牛逼!但是我们知道,一般年轻人患癌症的概率非常低,假设患癌症的概率为 0.001,那么其实我这个癌症检测系统只要一直输出您没有患癌症,准确度也可能能够达到 0.999。
假如现在有一个人本身已经患有癌症,但是他自己不知道自己患有癌症。这个时候用我的癌症检测系统检测发现他没有得癌症,那很显然我这个系统已经把他给坑了(耽误了治疗)。
看到这里您应该已经体会到了,一个分类模型如果光看准确度是不够的,尤其是对这种样本极度不平衡的情况( 10000 条健康信息数据中,只有 1 条的类别是患有癌症,其他的类别都是健康)。
混淆矩阵
想进一步的考量分类模型的性能如何,可以使用其他的一些性能指标,例如精准率和召回率。但这些指标计算的基础是混淆矩阵。
继续以癌症检测系统为例,癌症检测系统的输出不是有癌症就是健康,这里为了方便,就用 1 表示患有癌症,0 表示健康。假设现在拿 10000 条数据来进行测试,其中有 9978 条数据的真实类别是 0,系统预测的类别也是 0,有 2 条数据的真实类别是 1 却预测成了 0,有 12 条数据的真实类别是 0 但预测成了 1,有 8 条数据的真实类别是 1,预测结果也是 1。
如果我们把这些结果组成如下矩阵,则该矩阵就成为混淆矩阵。
| 真实预测 | 0 | 1 |
|---|---|---|
| 0 | 9978 | 12 |
| 1 | 2 | 8 |
混淆矩阵中每个格子所代表的的意义也很明显,意义如下:
| 真实预测 | 0 | 1 |
|---|---|---|
| 0 | 预测0正确的数量 | 预测1错误的数量 |
| 1 | 预测0错误的数量 | 预测1正确的数量 |
如果将正确看成是 True,错误看成是 False, 0 看成是 Negtive, 1 看成是 Positive。然后将上表中的文字替换掉,混淆矩阵如下:
| 真实预测 | 0 | 1 |
|---|---|---|
| 0 | TN | FP |
| 1 | FN | TP |
因此 TN 表示真实类别是 Negtive,预测结果也是 Negtive 的数量; FP 表示真实类别是 Negtive,预测结果是 Positive 的数量; FN 表示真实类别是 Positive,预测结果是 Negtive 的数量;TP 表示真实类别是 Positive,预测结果也是 Positive 的数量。
很明显,当 FN 和 FP 都等于 0 时,模型的性能应该是最好的,因为模型并没有在预测的时候犯错误。即如下混淆矩阵:
| 真实预测 | 0 | 1 |
|---|---|---|
| 0 | 9978 | 0 |
| 1 | 0 | 22 |
所以模型分类性能越好,混淆矩阵中非对角线上的数值越小。
代码示例:
def confusion_matrix(y_true, y_predict):
def TN(y_true, y_predict):
return np.sum((y_true == 0) & (y_predict == 0))
def FP(y_true, y_predict):
return np.sum((y_true == 0) & (y_predict == 1))
def FN(y_true, y_predict):
return np.sum((y_true == 1) & (y_predict == 0))
def TP(y_true, y_predict):
return np.sum((y_true == 1) & (y_predict == 1))
return np.array([
[TN(y_true, y_predict), FP(y_true, y_predict)],
[FN(y_true, y_predict), TP(y_true, y_predict)]
])
编程要求
根据提示,在 Begin-End 区域填写 python 代码,完成 confusion_matrix 函数实现二分类混淆矩阵的构建。
confusion_matrix 函数中的参数:
-
y_true:数据的真实类别,类型为 ndarray;
-
y_predict:模型预测的类别,类型为 ndarray。
测试说明
平台会对你编写的代码进行测试,期望您的代码根据输入来输出正确的混淆矩阵,以下为其中一个测试用例(y_true 表示真实类别,y_predict 表示预测类别):
测试输入: {‘y_true’:[1, 0, 0, 1, 0, 1, 0], ‘y_predict’:[0, 1, 0, 1, 0, 1, 0]}
预期输出:
[[3 1] [1 2]]
第7关:精准率与召回率
任务描述
本关任务:填写 python 代码,完成 precision_score 函数和 recall_score 函数分别实现计算精准率和召回率。
相关知识
为了完成本关任务,你需要掌握:
-
精准率;
-
召回率。
精准率
**精准率(Precision)**指的是模型预测为 Positive 时的预测准确度,其计算公式如下:
Precisioin=TP+FPTP
假如癌症检测系统的混淆矩阵如下:
| 真实预测 | 0 | 1 |
|---|---|---|
| 0 | 9978 | 12 |
| 1 | 2 | 8 |
则该系统的精准率 =8/(8+12)=0.4。
0.4 这个值表示癌症检测系统的预测结果中如果有 100 个人被预测成患有癌症,那么其中有 40 人是真的患有癌症。也就是说,精准率越高,那么癌症检测系统预测某人患有癌症的可信度就越高。
召回率
**召回率(Recall)**指的是我们关注的事件发生了,并且模型预测正确了的比值,其计算公式如下:
Recall=FN+TPTP
假如癌症检测系统的混淆矩阵如下:
| 真实预测 | 0 | 1 |
|---|---|---|
| 0 | 9978 | 12 |
| 1 | 2 | 8 |
则该系统的召回率 =8/(8+2)=0.8。
从计算出的召回率可以看出,假设有 100 个患有癌症的病人使用这个系统进行癌症检测,系统能够检测出 80 人是患有癌症的。也就是说,召回率越高,那么我们感兴趣的对象成为漏网之鱼的可能性越低。
精准率与召回率之间的关系
假设有这么一组数据,菱形代表 Positive,圆形代表 Negtive 。
现在需要训练一个模型对数据进行分类,假如该模型非常简单,就是在数据上画一条线作为分类边界。模型认为边界的左边是 Negtive,右边是 Positive。如果该模型的分类边界向左或者向右移动的话,模型所对应的精准率和召回率如下图所示:
从上图可知,模型的精准率变高,召回率会变低,精准率变低,召回率会变高。
应该选精准率还是召回率作为性能指标?
到底应该使用精准率还是召回率作为性能指标,其实是根据具体业务来决定的。
比如我现在想要训练一个模型来预测我关心的股票是涨( Positive )还是跌( Negtive ),那么我们应该主要使用精准率作为性能指标。因为精准率高的话,则模型预测该股票要涨的可信度就高(很有可能赚钱!)。
比如现在需要训练一个模型来预测人是( Positive )否( Negtive )患有艾滋病,那么我们应该主要使用召回率作为性能指标。因为召回率太低的话,很有可能存在漏网之鱼(可能一个人本身患有艾滋病,但预测成了健康),这样就很可能导致病人错过了最佳的治疗时间,这是非常致命的。
编程要求
根据提示,在 Begin-End 区域填写 python 代码,完成 precision_score 函数和 recall_score 函数分别实现计算精准率和召回率。
precision_score函数中的参数:
-
y_true :数据的真实类别,类型为 ndarray;
-
y_predict :模型预测的类别,类型为 ndarray。
recall_score 函数中的参数:
-
y_true:数据的真实类别,类型为 ndarray;
-
y_predict:模型预测的类别,类型为 ndarray。
测试说明
平台会对你编写的代码进行测试,期望您的代码根据输入来输出正确的精准率和召回率,以下为其中一个测试用例( y_true 表示真实类别,y_predict 表示预测类别):
测试输入: {‘y_true’:[1, 0, 0, 1, 0, 1, 0], ‘y_predict’:[0, 1, 0, 1, 0, 1, 0]}
预期输出: 0.666667, 0.666667
第8关:F1 Score
任务描述
本关任务:填写 python 代码,完成 f1_score 函数实现计算 F1 Score。
相关知识
为了完成本关任务,你需要掌握:
- F1 Score。
F1 Score
上一关中提到了精准率变高,召回率会变低,精准率变低,召回率会变高。那如果想要同时兼顾精准率和召回率,这个时候就可以使用 F1 Score 来作为性能度量指标了。
F1 Score 是统计学中用来衡量二分类模型精确度的一种指标。它同时兼顾了分类模型的准确率和召回率。 F1 Score 可以看作是模型准确率和召回率的一种加权平均,它的最大值是 1,最小值是 0。其公式如下:
F1=precision+recall2∗precision∗recall
-
假设模型 A 的精准率为 0.2,召回率为 0.7,那么模型 A 的 F1 Score 为 0.31111。
-
假设模型 B 的精准率为 0.7,召回率为 0.2,那么模型 B 的 F1 Score 为 0.31111。
-
假设模型 C 的精准率为 0.8,召回率为 0.7,那么模型 C 的 F1 Score 为 0.74667。
-
假设模型 D 的精准率为 0.2,召回率为 0.3,那么模型 D 的 F1 Score 为 0.24。
从上述 4 个模型的各种性能可以看出,模型C的精准率和召回率都比较高,因此它的 F1 Score 也比较高。而其他模型的精准率和召回率要么都比较低,要么一个低一个高,所以它们的 F1 Score 比较低。
这也说明了只有当模型的精准率和召回率都比较高时 F1 Score 才会比较高。这也是 F1 Score 能够同时兼顾精准率和召回率的原因。
编程要求
根据提示,在 Begin-End 区域填写 python 代码,完成 f1_score 函数实现计算 F1 Score。
f1_score 函数中的参数:
-
precision:模型的精准率,类型为 float;
-
recall:模型的召回率,类型为 float 。
测试说明
平台会对你编写的代码进行测试,期望您的代码根据输入来返回正确的 F1 Score ,以下为其中一个测试用例(列表中的第一个数字表示精准率,第二个数字表示召回率):
测试输入: [0.7, 0.2]
预期输出: 0.311111
第9关:ROC曲线与AUC
任务描述
本关任务:填写 python 代码,完成 AUC 函数实现计算 AUC。
相关知识
为了完成本关任务,你需要掌握:
-
ROC曲线;
-
AUC。
ROC曲线
ROC曲线( Receiver Operating Cha\fracteristic Curve )描述的 TPR ( True Positive Rate )与 FPR ( False Positive Rate )之间关系的曲线。
TPR 与 FPR 的计算公式如下:
TPR=TP+FNTP
FPR=FP+TNFP
其中 TPR 的计算公式您可能有点眼熟,没错!就是召回率的计算公式。也就是说 TPR 就是召回率。所以 TPR 描述的是模型预测 Positive 并且预测正确的数量占真实类别为 Positive 样本的比例。而 FPR 描述的模型预测 Positive 并且预测错了的数量占真实类别为 Negtive 样本的比例。
和精准率与召回率一样, TPR 与 FPR 之间也存在关系。假设有这么一组数据,菱形代表 Positive,圆形代表 Negtive。
现在需要训练一个逻辑回归的模型对数据进行分类,假如将从 0 到 1 中的一些值作为模型的分类阈值。若模型认为当前数据是 Positive 的概率小于分类阈值则分类为 Negtive ,否则就分类为 Positive (**假设分类阈值为 0.8,模型认为这条数据是 Positive 的概率为 0.7, 0.7 小于 0.8,那么模型就认为这条数据是 Negtive **)。在不同的分类阈值下,模型所对应的 TPR 与 FPR 如下图所示(竖线代表分类阈值,模型会将竖线左边的数据分类成 Negtive,竖线右边的分类成 Positive ):
从图中可以看出,**当模型的 TPR 越高 FPR 也会越高, TPR 越低 FPR 也会越低。这与精准率和召回率之间的关系刚好相反。**并且,模型的分类阈值一但改变,就有一组对应的 TPR 与 FPR 。假设该模型在不同的分类阈值下其对应的 TPR 与 FPR 如下表所示:
| TPR | FPR |
|---|---|
| 0.2 | 0.08 |
| 0.35 | 0.1 |
| 0.37 | 0.111 |
| 0.51 | 0.12 |
| 0.53 | 0.13 |
| 0.56 | 0.14 |
| 0.71 | 0.21 |
| 0.82 | 0.26 |
| 0.92 | 0.41 |
| 0.93 | 0.42 |
若将 FPR 作为横轴, TPR 作为纵轴,将上面的表格以折线图的形式画出来就是 ROC曲线 。
假设现在有模型 A 和模型 B ,它们的 ROC 曲线如下图所示(其中模型 A 的 ROC曲线 为黄色,模型 B 的 ROC 曲线 为蓝色):
**那么模型 A 的性能比模型 B 的性能好,因为模型 A 当 FPR 较低时所对应的 TPR 比模型 B 的低 FPR 所对应的 TPR 更高。**由由于随着 FPR 的增大, TPR 也会增大。所以 ROC 曲线与横轴所围成的面积越大,模型的分类性能就越高。而 ROC曲线 的面积称为AUC。
AUC
很明显模型的 AUC 越高,模型的二分类性能就越强。AUC 的计算公式如下:
AUC=M∗N∑i∈positiveclassranki−2M(M+1)
其中 M 为真实类别为 Positive 的样本数量,N 为真实类别为 Negtive 的样本数量。ranki 代表了真实类别为 Positive 的样本点额预测概率从小到大排序后,该预测概率排在第几。
举个例子,现有预测概率与真实类别的表格如下所示(其中 0 表示 Negtive, 1 表示 Positive ):
| 编号 | 预测概率 | 真实类别 |
|---|---|---|
| 1 | 0.1 | 0 |
| 2 | 0.4 | 0 |
| 3 | 0.3 | 1 |
| 4 | 0.8 | 1 |
想要得到公式中的 rank,就需要将预测概率从小到大排序,排序后如下:
| 编号 | 预测概率 | 真实类别 |
|---|---|---|
| 1 | 0.1 | 0 |
| 3 | 0.3 | 1 |
| 2 | 0.4 | 0 |
| 4 | 0.8 | 1 |
排序后的表格中,真实类别为 Positive 只有编号为 3 和编号为 4 的数据,并且编号为 3 的数据排在第 2 ,编号为 4 的数据排在第 4。所以 rank=[2, 4] 。又因表格中真是类别为 Positive 的数据有 2 条, Negtive 的数据有 2 条。因此 M 为2, N 为2。所以根据 AUC 的计算公式可知:
AUC=2∗2(2+4)−22(2+1)=0.75。
编程要求
根据提示,在 Begin-End 区域填写 python 代码,完成 calAUC 函数实现计算 AUC 并返回。
calAUC 函数中的参数:
-
prob:模型预测样本为 Positive 的概率列表,类型为 ndarray;
-
labels:样本的真实类别列表,其中 1 表示 Positive ,0 表示 Negtive ,类型为 ndarray 。
测试说明
平台会对你编写的代码进行测试,期望您的代码根据输入来返回正确的 AUC,以下为其中一个测试用例(字典中的 probs 部分代表模型认为样本是 Positive 的概率,labels 部分代表样本的真实类别,1 表示 Positive, 0 表示 Negtive ):
测试输入: {‘probs’:[0.1, 0.4, 0.3, 0.8], ‘labels’:[0, 0, 1, 1]}
预期输出: 0.75
第10关:sklearn中的分类性能指标
任务描述
本关任务:使用 sklearn 完成对模型分类性能的评估。
相关知识
为了完成本关任务,你需要掌握如何使用 sklearn 提供的以下接口。
-
accu\fracy_score;
-
precision_score;
-
recall_score;
-
f1_score;
-
roc_auc_score。
accu\fracy_score
sklearn 提供了计算准确度的接口 accu\fracy_score。其中参数如下:
-
y_true:为样本真实标签,类型为一维的 ndarray 或者 list;
-
y_pred:为模型预测标签,类型为一维的 ndarray 或者 list。
示例代码如下:
from sklearn.metrics import accu\fracy_score
precision_score
sklearn 提供了计算精准率的接口 precision_score 。其中参数如下:
-
y_true:为样本真实标签,类型为一维的 ndarray 或者 list;
-
y_pred:为模型预测标签,类型为一维的 ndarray 或者 list;
-
pos_label:用什么值表示 Positive,默认为 1。
示例代码如下:
from sklearn.metrics import precision_score
recall_score
sklearn 提供了计算召回率的接口 recall_score 。其中参数如下:
-
y_true:为样本真实标签,类型为一维的 ndarray 或者 list;
-
y_pred:为模型预测标签,类型为一维的 ndarray 或者 list;
-
pos_label:用什么值表示 Positive ,默认为 1。
示例代码如下:
from sklearn.metrics import recall_score
f1_score
sklearn 提供了计算 F1 Score 的接口 f1_score 。其中参数如下:
-
y_true:为样本真实标签,类型为一维的 ndarray 或者 list;
-
y_pred:为模型预测标签,类型为一维的 ndarray 或者 list;
-
pos_label:用什么值表示 Positive ,默认为 1。
示例代码如下:
from sklearn.metrics import f1_score
roc_auc_score
sklearn 提供了计算 AUC 的接口 roc_auc_score 。其中参数如下:
-
y_true:为样本真实标签,类型为一维的 ndarray 或者 list;
-
y_score:为模型预测样本为 Positive 的概率,类型为一维的 ndarray 或者 list。
示例代码如下:
import numpy as np
from sklearn.metrics import roc_auc_score
#y_true为真实标签,y_predict为预测标签
y_true = [1, 0, 0, 1]
y_predict = [1, 0, 1, 0]
print(accu\fracy_score(y_true, y_predict))
编程要求
在 Begin-End 区域填写classification_performance(y_true, y_pred, y_prob)函数分别计算模型的准确度、精准率、召回率、F1-Score 和 AUC 并将其返回,其中:
-
y_true :样本的真实类别,类型为 ndarray;
-
y_pred :模型预测出的类别,类型为 ndarray;
-
y_prob :模型预测样本为 Positive 的概率,类型为 ndarray。
测试说明
平台会对你编写的代码进行测试,期望您的代码根据输入来按顺序返回正确的准确度、精准率、召回率、 F1-Score 和 AUC,以下为其中一个测试用例(字典中的 y_prob 部分代表模型认为样本是 Positive 的概率;y_true 部分代表样本的真实类别,1 表示 Positive, 0 表示 Negtive;y_pred 部分代表模型预测的类别):
测试输入: {‘y_prob’:[0.7, 0.2, 0.9, 0.8],‘y_true’:[0, 0, 1, 1],‘y_pred’:[1, 0, 1, 1]}
预期输出: 0.750000, 0.666667, 1.000000, 0.800000, 1.000000
机器学习 --- 神经网络
第1关:神经网络基本概念
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握:1.神经网络基本概念。
神经网络基本概念
-
神经网络由输入层、隐藏层、输出层组成;
-
层与层之间的神经元有连接,而层内之间的神经元没有连接。连接的神经元都有对应的权重;
-
最左边的层叫做输入层,这层负责接收输入数据;
-
最右边的层叫输出层,我们可以从这层获取神经网络输出数据;
-
输入层和输出层之间的层叫做隐藏层。
-
表示相邻两层不同神经元连接的强度叫权重。如果神经元1到神经元2有较大的值,则意味着神经元1对神经元2有较大影响。权重减小了输入值的重要性,对于接近于0的权重,输入的改变不会影响输出的变化;负权重意味着,增加输入而输出会减小。权重决定了输入对输出影响的大小。
上图中的网络一共由3层神经元组成,但实质上只有2层权重,因此我们通常将输入层当做第0层网络,上图我们称其为2层网络(根据输入层、隐藏层、输出层的总数减去1后的数量来命名网络)。
编程要求
请仔细阅读题目,结合相关知识,完成本关的选择题任务。
测试说明
平台会对你的代码进行运行测试,如果实际输出结果与预期结果相同,则通关;反之,则 GameOver。
选择题
第1题 (单选题)
上图中的神经网络一共有多少个权重?
- A. 8
- B. 12
- C. 20
- D. 24
我的答案: C
第2关:激活函数
任务描述
本关任务:用Python实现常用激活函数。
相关知识
为了完成本关任务,你需要掌握:1.什么是激活函数,2.激活函数作用,3.常用激活函数。
什么是激活函数
我们已经知道神经网络是由一个个神经元也就是感知机组成,感知机数学模型如下:
f(x)=sign(w1x1+w2x2+…+wnxn+b)
sign={−1+1x<0xgeq0
其中的sign函数被称为阶跃函数,是用来引入非线性因素的。而在神经网络里,我们使用一些其它的函数来代替,并称其为激活函数。
激活函数作用
如果不用激活函数,每一层输出都是上层输入的线性函数,无论神经网络有多少层,输出都是输入的线性组合,这种情况就是最原始的感知机。只能对线性数据进行分类:
如果使用的话,激活函数给神经元引入了非线性因素,使得神经网络可以任意逼近任何非线性函数,这样神经网络就可以应用到众多的非线性模型中,对非线性数据进行分类:
常用激活函数
最开始,神经网络中经常使用的一个激活函数就是sigmoid函数,函数公式如下:
sign={−1+1x<0xgeq0
函数图像如下图所示:
sigmoid函数是一条平滑的曲线,输出随着输入发生连续的变化。而阶跃函数以0为界,输出发生急剧兴的变化。sigmoid函数的平滑性对神经网络的学习具有重要意义。
sigmoid函数在x过大或过小时,函数变化非常小,即梯度非常接近0,随着神经网络的加深,在使用梯度下降方法的时候,由于梯度接近0,参数更新接近0,网络开始学不到东西,即梯度消失。所以现在常使用relu激活函数,函数公式如下:
relu(x)={0xx<0xgeq0
函数图像如下图所示:
relu函数在x大于等于0时,输出的是x本身,函数变化率恒为1,这样就避免了梯度消失的情况。当x小于0时,输出为0,即神经元不被激活,这样也符合人脑内并不是所有神经元同时被激活的情况。并且,relu函数计算成本非常低,所以在神经网络过深时常使用relu函数作为激活函数。
编程要求
根据提示,在右侧编辑器补充Python代码,实现relu激活函数,底层代码会调用您实现的relu激活函数来进行测试。
测试说明
测试用例:
输入:9
预期输出:9
输入:-1
预期输出:0
第3关:反向传播算法
任务描述
本关任务:用sklearn构建神经网络模型,并通过鸢尾花数据集中鸢尾花的4种属性与种类对神经网络模型进行训练。我们会调用你训练好的神经网络模型,来对未知的鸢尾花进行分类。
相关知识
为了完成本关任务,你需要掌握:1.神经网络是如何训练,2.前向传播,3.反向传播,4.sklearn中的神经网络。
数据集介绍
鸢尾花数据集是一类多重变量分析的数据集。通过花萼长度,花萼宽度,花瓣长度,花瓣宽度4个属性预测鸢尾花卉属于(Setosa,Versicolour,Virginica)三个种类中的哪一类。
想要使用该数据集可以使用如下代码:
#获取训练数据
train_data = pd.read_csv('./step2/train_data.csv')
#获取训练标签
train_label = pd.read_csv('./step2/train_label.csv')
train_label = train_label['target']
#获取测试数据
test_data = pd.read_csv('./step2/test_data.csv')
数据集中部分数据与标签如下图所示:
神经网络是如何训练
神经网络的训练方法跟逻辑回归相似:
也是使用梯度下降算法来更新模型的参数,既然要使用梯度下降算法,就要知道损失函数对参数的梯度。在神经网络中,由于有多层的网络,所以使得我们的网络非常不好训练,这么多参数的梯度求起来非常麻烦。反向传播算法出现,为我们解决了这一个问题,它能够快速的计算这些梯度。反向传播算法一共分为两部分:前向传播与反向传播。
前向传播
前向传播指的是数据x从神经网络输入层,与当层的权重相乘,再加上当层的偏置,所得到的值经过激活函数激活后,再输入到下一层。最后,在输出层所得到的值经过softmax函数转化为网络对数据的预测。
Z[1]=XW[1]+B[1]
A[1]=f(Z[1])
Z[2]=A[1]W[2]+B[2]
A=softmax(Z[2])
其中,输出层的Z值要经过softmax函数,转化为预测值。softmax函数公式如下:
ak=sumi=1nexp(zi)exp(zk)
输出层的A为预测值,是一个向量。有多少类别,A就有多长。隐藏层的A[L]为激活值,L代表是第L层隐藏层。W为权重,是一个矩阵,上一层神经网络有多少个神经元,它就有多少行,当层神经网络有多少神经元,它就有多少列。B为偏置,是一个向量,长度与当层神经元个数一样。神经网络使用的损失函数为交叉熵损失函数:
其中ai代表样本被预测为第i个类别的可能性,yi代表样本为第i个类别的真实可能性。交叉熵损失函数公式如下:
L(y,a)=−sumi=1nyilnai
前向传播的主要目的就是得到预测值,再算出交叉熵损失函数。
交叉熵
交叉熵(cross entropy)是深度学习中常用的一个概念,一般用来求目标与预测值之间的差距。机器学习是用网络训练出来的分布q来表示真实分布p,此时当两者的交叉熵越小时,模型训练的结果越接近样本的真实分布,这也是交叉熵被用来作为损失函数的原因。
在机器学习中,P往往用来表示样本的真实分布,比如[1,0,0]表示当前样本属于第一类。Q用来表示模型所预测的分布,比如[0.7,0.2,0.1]直观的理解就是如果用P来描述样本,那么就非常完美。而用Q来描述样本,虽然可以大致描述,但是不是那么的完美,信息量不足,需要额外的一些“信息增量”才能达到和P一样完美的描述。如果我们的Q通过反复训练,也能完美的描述样本,那么就不再需要额外的“信息增量”,Q等价于P。
反向传播
我们通过前向传播能够求出损失函数,而反向传播就是利用前向传播得到的损失函数对参数求梯度,即每个参数的偏导。
之所以称为反向传播,是因为我们在利用链式法则的时候对各个参数求偏导的传播顺序跟前向传播相反,如我们要求loss对w1的偏导,则要先求出loss对a的偏导,再求出a对z2的偏导,再求出z2对a1的偏导,再求出a1对z1的偏导,再求出z1对w1的偏导,然后全部相乘就得到loss对w1的偏导了。公式如下:
partialw[1]partialloss=partiala[2]partialloss.partialz[2]partiala[2].partiala[1]partialz[2].partialz[1]partiala[1].partialw[1]partialz[1]
所以反向传播的目的就是求出损失函数对各个参数的梯度。最后我们就可以用梯度下降算法来训练我们的神经网络模型了。
sklearn中的神经网络
MLPClassifier的构造函数中有四个常用的参数可以设置:
-
solver:MLP的求解方法lbfs在小数据上表现较好,adam较为鲁棒,sgd在参数调整较优时会有最佳表现(分类效果与迭代次数);sgd标识随机梯度下降; -
alpha:正则项系数,默认为L2正则化,具体参数需要调整; -
hidden_layer_sizes:hidden_layer_sizes=(3, 2)设置隐藏层size为2层隐藏层,第一层3个神经元,第二层2个神经元。 -
max_iter:最大训练轮数。
和sklearn中其他分类器一样,MLPClassifier类中的fit函数用于训练模型,fit函数有两个向量输入:
-
X:大小为**[样本数量,特征数量]**的ndarray,存放训练样本; -
Y:值为整型,大小为**[样本数量]**的ndarray,存放训练样本的分类标签。
MLPClassifier类中的predict函数用于预测,返回预测标签,predict函数有一个向量输入:
X:大小为**[样本数量,特征数量]**的ndarray,存放预测样本。
MLPClassifier的使用代码如下:
from sklearn.neural_network import MLPClassifier
mlp = MLPClassifier(solver='lbfgs',max_iter =10,
alpha=1e-5,hidden_layer_sizes=(3,2))
mlp.fit(X_train, Y_train)
result = mlp.predict(X_test)
编程要求
使用sklearn构建神经网络模型,利用训练集数据与训练标签对模型进行训练,然后使用训练好的模型对测试集数据进行预测,并将预测结果保存到./step2/result.csv中。保存格式如下:
测试说明
我们会获取你的预测结果与真实标签对比,预测正确率高于95%视为过关。
机器学习 --- 线性回归
第1关:简单线性回归与多元线性回归
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握:1.简单线性回归,2.多元线性回归。
您的浏览器不支持 video 标签。
课程视频《简单线性回归》
您的浏览器不支持 video 标签。
课程视频《多元线性回归》
简单线性回归
在生活中,我们常常能碰到这么一种情况,一个变量会跟着另一个变量的变化而变化,如圆的周长与半径的关系,当圆的半径确定了,那么周长也就确定了。还有一种情况就是,两个变量之间看似存在某种关系,但又没那么确定,如青少年的身高与体重,他们存在一种近似的线性关系:
身高/cm = 体重/kg +105
但是,并不是每个青少年都符合这个公式,只能说每个青少年的身高体重都存在这么一种近似的线性关系。这就是其实就是简单的线性回归,那么,到底什么是线性回归呢?假如我们将青少年的身高和体重值作为坐标,不同人的身高体重就会在平面上构成不同的坐标点,然后用一条直线,尽可能的去拟合这些点,这就是简单的线性回归。
简单的线性回归模型如下:
y=wx+b
其中x表示特征值(如:体重值),w表示权重,b表示偏置,y表示标签(如:身高值)。
多元线性回归
简单线性回归中,一个变量跟另一个变量的变化而变化,但是生活中,还有很多变量,可能由多个变量的变化决定着它的变化,比如房价,影响它的因素可能有:房屋面积、地理位置等等。如果我们要给它们建立出近似的线性关系,这就是多元线性回归,多元线性回归模型如下:
y=b+w1x1+w2x2+…+wnxn
其中xi表示第i个特征值,wi表示第i个特征对应的权重,b表示偏置,y表示标签。
编程要求
根据相关知识,按照要求完成右侧选择题任务,包含单选题和多选题。
测试说明
平台会对你选择的答案进行判断,全对则通过测试。
选择题
第1题 (多选题)
下面属于多元线性回归的是?
- A. 求得正方形面积与对角线之间的关系。
- B. 建立股票价格与成交量、换手率等因素之间的线性关系。
- C. 建立西瓜价格与西瓜大小、西瓜产地、甜度等因素之间的线性关系。
- D. 建立西瓜书销量与时间之间的线性关系。
我的答案: B, C
第2题 (多选题)
若线性回归方程得到多个解,下面哪些方法能够解决此问题?
- A. 获取更多的训练样本
- B. 选取样本有效的特征,使样本数量大于特征数
- C. 加入正则化项
- D. 不考虑偏置项b
我的答案: A, B, C
第3题 (单选题)
下列关于线性回归分析中的残差(预测值减去真实值)说法正确的是?
- A. 残差均值总是为零
- B. 残差均值总是小于零
- C. 残差均值总是大于零
- D. 以上说法都不对
我的答案: A
第2关:线性回归的正规方程解
任务描述
本关任务:根据本关卡所学知识,构建线性回归算法,并利用波斯顿房价数据对模型进行训练,然后对未知的房价数据进行预测。
相关知识
为了完成本关任务,你需要掌握:1.线性回归训练流程,2.线性回归的正规方程解。
数据集介绍
波斯顿房价数据集共有506条波斯顿房价的数据,每条数据包括对指定房屋的13项数值型特征和目标房价组成。用数据集的80%作为训练集,数据集的20%作为测试集,训练集和测试集中都包括特征和目标房价。
sklearn中已经提供了波斯顿房价数据集的相关接口,想要使用该数据集可以使用如下代码:
from sklearn import datasets
#加载波斯顿房价数据集
boston = datasets.load_boston()
#X表示特征,y表示目标房价
X = boston.data
y = boston.target
数据集中部分数据与标签如下图所示:
线性回归训练流程
由数据集可以知道,每一个样本有13个特征与目标房价,而我们要做的事就是通过这13个特征来预测房价,我们可以构建一个多元线性回归模型,来对房价进行预测。模型如下:
y=b+w1x1+w2x2+…+wnxn
其中xi表示第i个特征值,wi表示第i个特征对应的权重,b表示偏置,y表示目标房价。
为了方便,我们稍微将模型进行变换:
y=w0x0+w1x1+w2x2+…+wnxn
其中x0等于1。
Y=heta.X
heta=(w0,w1,…,wn)
X=(1,x1,…,xn)
而我们的目的就是找出能够正确预测的多元线性回归模型,即找出正确的参数heta。那么如何寻找呢?通常在监督学习里面都会使用这么一个套路,构造一个损失函数,用来衡量真实值与预测值之间的差异,然后将问题转化为最优化损失函数。既然损失函数是用来衡量真实值与预测值之间的差异那么很多人自然而然的想到了用所有真实值与预测值的差的绝对值来表示损失函数。不过带绝对值的函数不容易求导,所以采用MSE(均方误差)作为损失函数,公式如下:
loss=m1sumi=1m(yi−pi)2
其中p表示预测值,y表示真实值,m为样本总个数,i表示第i个样本。最后,我们再使用正规方程解来求得我们所需要的参数。
线性回归模型训练流程如下:
线性回归的正规方程解
对线性回归模型,假设训练集中m个训练样本,每个训练样本中有n个特征,可以使用矩阵的表示方法,预测函数可以写为:
Y=hetaX
其损失函数可以表示为
(Y−hetaX)T(Y−hetaX)
其中,标签Y为mx1的矩阵,训练特征X为mx(n+1)的矩阵,回归系数heta为(n+1)x1的矩阵,对heta求导,并令其导数等于0,可以得到XT(Y−hetaX)=0。所以,最优解为:
heta=(XTX)−1XTY
这个就是正规方程解,我们可以通过最优方程解直接求得我们所需要的参数。
编程要求
根据提示,在右侧编辑器补充 Python 代码,实现线性回归算法与MSE损失函数计算方法,并利用房价数据对模型进行训练,然后对未知的房价数据进行预测。
函数说明
- numpy方法: numpy.mean(array, axis) 指定轴上数组元素计算算术平均数。
numpy.mean([ [1,2,3],
[4,5,6],
[7,8,9]],axis=0)
[4. 5. 6.]
numpy.ones(shape) 返回一个包含给定形状和数据类型的新数组。
numpy.ones([3, 3])
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]]
numpy.hstack((a, b)) 按水平方向(列顺序)堆叠数组构成一个新的数组。
numpy.hstack(([1,2,3],[4,5,6]))
[1 2 3 4 5 6]
numpy.vstack((a, b)) 按垂直方向(行顺序)堆叠数组构成一个新的数组。
numpy.vstack(([1,2,3],[4,5,6]))
[[1 2 3]
[4 5 6]]
- numpy线性代数方法: numpy.linalg.inv(m) 返回 m 的逆矩阵
numpy.linalg.inv([[2,5],[1,3]])
[[ 3. -5.]
[-1. 2.]]
numpy.dot(m1, m2) 矩阵 m1 与矩阵 m2 点乘。
numpy.dot([[2,5],[1,3]], [[3,-5],[-1,2]])
[[1 0]
[0 1]]
m.T 矩阵 m 的转置矩阵。
m = np.array([[2,5],[1,3]])
m.T
[[2 1]
[5 3]]
测试说明
只需返回预测结果即可,程序内部会检测您的代码,MSE低于30则视为过关。
第3关:衡量线性回归的性能指标
任务描述
本关任务:根据本关卡所学知识,用Python实现线性回归常用评估指标,并对构造的线性回归模型进行评估。
相关知识
为了完成本关任务,你需要掌握:1.均方误差(MSE),2.均方根误差(RMSE),3.平均绝对误差(MAE),4.R-Squared。
前言
大家知道已经,机器学习通常都是将训练集上的数据对模型进行训练,然后再将测试集上的数据给训练好的模型进行预测,最后根据模型性能的好坏选择模型,对于分类问题,大家很容易想到,可以使用正确率来评估模型的性能,那么回归问题可以使用哪些指标用来评估呢?
MSE
MSE (Mean Squared Error)叫做均方误差,公式如下:
m1sumi=1m(yi−pi)2
其中yi表示第i个样本的真实标签,pi表示模型对第i个样本的预测标签。线性回归的目的就是让损失函数最小。那么模型训练出来了,我们在测试集上用损失函数来评估模型就行了。
RMSE
RMSE(Root Mean Squard Error)均方根误差,公式如下:
sqrtm1sumi=1m(yi−pi)2
RMSE其实就是MSE开个根号。有什么意义呢?其实实质是一样的。只不过用于数据更好的描述。
例如:要做房价预测,每平方是万元,我们预测结果也是万元。那么差值的平方单位应该是千万级别的。那我们不太好描述自己做的模型效果。怎么说呢?我们的模型误差是多少千万?于是干脆就开个根号就好了。我们误差的结果就跟我们数据是一个级别的了,在描述模型的时候就说,我们模型的误差是多少万元。
MAE
MAE(平均绝对误差),公式如下:
m1sumi=1m∣yi−pi∣
MAE虽然不作为损失函数,确是一个非常直观的评估指标,它表示每个样本的预测标签值与真实标签值的L1距离。
R-Squared
上面的几种衡量标准针对不同的模型会有不同的值。比如说预测房价 那么误差单位就是万元。数子可能是3,4,5之类的。那么预测身高就可能是0.1,0.6之类的。没有什么可读性,到底多少才算好呢?不知道,那要根据模型的应用场景来。 看看分类算法的衡量标准就是正确率,而正确率又在0~1之间,最高百分之百。最低0。如果是负数,则考虑非线性相关。很直观,而且不同模型一样的。那么线性回归有没有这样的衡量标准呢?
R-Squared就是这么一个指标,公式如下:
R2=1−sumi(ymeani−yi)2sumi(pi−yi)2
其中ymean表示所有测试样本标签值的均值。为什么这个指标会有刚刚我们提到的性能呢?我们分析下公式:
其实分子表示的是模型预测时产生的误差,分母表示的是对任意样本都预测为所有标签均值时产生的误差,由此可知:
-
R2leq1,当我们的模型不犯任何错误时,取最大值
1; -
当我们的模型性能跟基模型性能相同时,取
0; -
如果为负数,则说明我们训练出来的模型还不如基准模型,此时,很有可能我们的数据不存在任何线性关系。
编程要求
根据提示,在右侧编辑器Begin-End处补充代码,用Python实现R-Squared指标,并用实现的R-Squared指标来评估上一关的线性回归模型。
函数说明
- numpy方法: numpy.mean(array, axis) 指定轴上数组元素计算算术平均数。
numpy.mean([ [1,2,3],
[4,5,6],
[7,8,9]],axis=0)
[4. 5. 6.]
numpy.var(array, axis) 指定轴上数组元素计算方差。
numpy.var([ [1,2,3],
[4,5,6],
[7,8,9]],axis=0)
[6. 6. 6.]
numpy.ones(shape) 返回一个包含给定形状和数据类型的新数组。
numpy.ones([3, 3])
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]]
numpy.hstack((a, b)) 按水平方向(列顺序)堆叠数组构成一个新的数组。
numpy.hstack(([1,2,3],[4,5,6]))
[1 2 3 4 5 6]
numpy.vstack((a, b)) 按垂直方向(行顺序)堆叠数组构成一个新的数组。
numpy.vstack(([1,2,3],[4,5,6]))
[[1 2 3]
[4 5 6]]
- numpy线性代数方法: numpy.linalg.inv(m) 返回 m 的逆矩阵
numpy.linalg.inv([[2,5],[1,3]])
[[ 3. -5.]
[-1. 2.]]
numpy.dot(m1, m2) 矩阵 m1 与矩阵 m2 点乘。
numpy.dot([[2,5],[1,3]], [[3,-5],[-1,2]])
[[1 0]
[0 1]]
m.T 矩阵 m 的转置矩阵。
m = np.array([[2,5],[1,3]])
m.T
[[2 1]
[5 3]]
测试说明
只需返回预测结果即可,程序内部会检测您的代码,R-Squared指标高于0.6视为过关。
第4关:scikit-learn线性回归实践 - 波斯顿房价预测
任务描述
本关任务:你需要调用 sklearn 中的线性回归模型,并通过波斯顿房价数据集中房价的13种属性与目标房价对线性回归模型进行训练。我们会调用你训练好的线性回归模型,来对房价进行预测。
相关知识
为了完成本关任务,你需要掌握:1.LinearRegression。
数据集介绍
波斯顿房价数据集共有506条波斯顿房价的数据,每条数据包括对指定房屋的13项数值型特征和目标房价组成。用数据集的80%作为训练集,数据集的20%作为测试集,训练集和测试集中都包括特征和目标房价。
想要使用该数据集可以使用如下代码:
import pandas as pd
#获取训练数据
train_data = pd.read_csv('./step3/train_data.csv')
#获取训练标签
train_label = pd.read_csv('./step3/train_label.csv')
train_label = train_label['target']
#获取测试数据
test_data = pd.read_csv('./step3/test_data.csv')
数据集中部分数据与标签如下图所示:
LinearRegression
LinearRegression的构造函数中有两个常用的参数可以设置:
-
fit_intercept:是否有截据,如果没有则直线过原点,默认为Ture。 -
normalize:是否将数据归一化,默认为False。
LinearRegression类中的fit函数用于训练模型,fit函数有两个向量输入:
-
X:大小为**[样本数量,特征数量]**的ndarray,存放训练样本 -
Y:值为整型,大小为**[样本数量]**的ndarray,存放训练样本的标签值
LinearRegression类中的predict函数用于预测,返回预测值,predict函数有一个向量输入:
X:大小为**[样本数量,特征数量]**的ndarray,存放预测样本
LinearRegression的使用代码如下:
lr = LinearRegression()
lr.fit(X_train, Y_train)
predict = lr.predict(X_test)
编程要求
测试说明
我们会获取你的预测结果与真实标签对比,R2指标高于0.6视为过关。
机器学习 --- 绪论
第1关:什么是机器学习
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握:
- 什么是机器学习。
什么是机器学习
相信大家一定都非常喜欢吃西瓜,有经验的同学都知道如果一个西瓜色泽青绿、根蒂蜷缩、敲声浊响,那么就能判断这是一个正熟的好瓜。那么,为什么通过色泽、根蒂、敲声,这几个特征就能帮我们做出相当好的判断呢?因为我们吃过,看过很多好瓜,累积了这方面很多的经验,而通过对经验的利用,就能对新的情况做出有效的决策。
上面对经验的利用是靠我们人类自身来完成的,计算机能帮忙吗?
机器学习正是这么一门学科,它致力于研究如何通过计算的手段,利用经验来改善系统自身的性能。在计算机系统中,“经验”通常以“数据”的形式存在,因此,机器学习所研究的主要内容,是关于在计算机上从数据中产生的“模型”的算法,即“学习算法”。有了学习算法,我们就把经验数据提供给它,它就能基于这些数据产生模型,在面对新的情况时,模型会给我们提供相应的判断。
编程要求
略
测试说明
根据所学完成右侧选择题。
选择题
第1题 (多选题)
下面哪种方法属于机器学习?
- A. 在猫狗分类问题中,先将猫与狗的特点总结出来,再告诉机器,如果符合猫的特点,则判定为猫,如果符合狗的特点,则判定为狗。
- B. 将大量名画的真品与赝品输入计算机,让计算机自己从数据中学习出一个模型用来判断是真品还是赝品。
- C. 让计算机通过对以往的房价数据进行分析,预测未来房价走势。
- D. 通过人为编写好代码,符合条件则判定为人脸,否则不是人脸,从而制作出人脸识别系统。
我的答案: B, C
第2关:机器学习的常见术语
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握:
-
机器学习常见术语;
-
假设空间;
-
归纳偏好。
机器学习常见术语
我们已经知道了,机器学习是利用数据,从数据中归纳出规律,并用来对新事物进行预测。所以,机器学习首先要有数据,假设我们收集了一份关于西瓜的数据:
-
我们把数据中的每一行称为一个示例或样本;
-
反映事件或对象在某方面的表现或性质的事项,如:色泽、根蒂、敲声,称为属性或特征;
-
属性上的取值,例如:青绿、乌黑。称为属性值或特征值;
-
我们把一个示例(样本)称为一个特征向量。
一般地,令 D={x1,x2,..,xm} 表示包含 m 个示例的数据集,每个示例由 d 个属性描述(例如上面的西瓜数据使用了三个属性),则每个示例:
xi=(xi1;xi2;…;xid)
是 d 维样本空间X中的一个向量,xi∈X,其中xij是xi在第 j 个属性上的取值。d 称为样本xi的维数。
从数据中学得模型的过程称为“学习”或“训练”,这个过程通过执行某个学习算法来完成。训练过程中使用的数据称为“训练数据”,其中每个样本称为一个“训练样本”,训练样本组成的集合称为“训练集”,学习过程就是为了找出或逼近真相。
假设空间
假设空间在已知属性和属性可能取值的情况下,对所有可能满足目标的情况的一种毫无遗漏的假设集合。
接下来举个例子来说明什么是假设空间。在选择配偶时我们可能有以下几个指标:
-
体型 : 肥胖,匀称,过瘦;
-
财富 : 富有,一般,贫穷;
-
性子 : 急,不急不慢,慢。
现在我们要构建一个合适的假设空间来构建一个择偶观:
对于体型来说有肥胖、均匀和过瘦 3 种,也有可能价值观里认为这个无关紧要,所以有4种可能。
对于财富来说有富有、一般以及贫穷 3 种可能,也有可能价值观里认为这个无关紧要,所以有4种可能。
对于性子来说有急、不急不慢以及慢 3 种可能,也有可能价值观里认为这个无关紧要,所以有4种可能。
最后再加上一个极端的情况,也就是体型、财富以及性子这 3 个评判准则选出来的都不是想要的配偶。
所以假设空间的规模大小为4*4*4+1=65。
归纳偏好
归纳偏好是机器学习算法在学习过程中对某种类型假设的偏好。说白了就是“什么样的模型更好”这一问题。
以韦小宝的 7 个老婆为例,这 7 个老婆均满足小宝的要求,因此构成了大小为 7 的假设空间。(实际上,假设空间的大小一定是无穷大的。为了说明问题,我们暂时以 7 为大小)。那么,如何衡量哪一个假设空间中哪一个假设函数(老婆)最好呢?如果以温柔体贴为偏好来选,当然是小双;如果以小宝的迷恋为偏好来讲,假设函数就是阿珂。说白了,归纳偏好就是一个用于挑选假设函数的基准。
因此归纳偏好可看作学习算法自身在一个可能很庞大的假设空间中对假设进行选择的启发式或“价值观”。
而在具体的现实问题中,学习算法本身所做的假设是否成立,也即算法的归纳偏好是否与问题本身匹配,大多数时候直接决定了算法能否取得好的性能。
编程要求
略
测试说明
根据所学完成选择题。
选择题
第1题 (单选题)
以下是我们的一份数据集,则x32表示的是?
- A. 青绿
- B. 硬挺
- C. 清脆
- D. 浊响
我的答案: B
第3关:机器学习的主要任务
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握:1.机器学习主要任务,2.分类,3.回归,4.聚类。
机器学习主要任务
分类是机器学习的一项主要任务,主要是将实例数据划分到合适的分类中。
机器学习的另外一项任务是回归,主要是预测数值型的数据,比如通过数据值拟合曲线等。
分类和回归属于监督学习,这类算法必须知道预测什么,即目标变量的分类信息。与监督学习相对应的是无监督学习,此时数据没有类别信息,也不会给定目标值。在无监督学习中,将数据集合分成由类似的对象组成的多个类的过程称为“聚类”。
接下来,我们来看看,什么是分类、回归与聚类。
分类
这是一系列关于西瓜的数据,这里的每个实体,或者每一行被称为一个样本或数据点,而每一列(用来描述这些实体的属性)则被称为特征。假如说,我们现在想通过色泽、根蒂、敲声这几个特征来区分一个西瓜是好瓜与不是好瓜,这就是一个分类问题。分类问题的目标是预测类别标签。在这个例子中,“是”与“否”则是预测类别的两个不同的标签。分类问题有时可分为二分类和多分类,西瓜的例子则是一个二分类问题,多分类指的是数据不止两个类别,它有多个类别。
回归
回归任务的目标是预测一个连续值,编程术语叫作浮点数。假如说我们现在手里得到的是如下数据:
我们要通过色泽、根蒂、敲声来预测西瓜的价格,这就是一个回归问题。区分分类任务和回归任务有一个简单方法,就是看输出是否具有某种连续性。如果在可能的结果之间具有连续性,那么它就是一个回归问题,比如说价格。
聚类
聚类属于无监督学习,它是指我们的数据只有输入,没有输出,并需要从这些数据中提取知识。聚类算法将数据划分成不同的组,每组包含相似的样本。比如说:
我们现在手里的数据只有色泽、根蒂、敲声这几个特征,我们通过这三个特征,把性状相似的西瓜分到一个组,这就是一个聚类问题。聚类问题与分类问题的本质区别就是有没有标签。
编程要求
略
测试说明
根据所学完成右侧选择题。
选择题
第1题 (单选题)
我们现在手头上有大量的猫与狗的图片,我现在想训练出一个模型,能够区别出这张图片是猫还是狗,这是一个什么问题?
- A. 回归
- B. 分类
- C. 聚类
我的答案: B
第2题 (多选题)
我们现在手头上有大量的动物的图片,为了方便处理,我们想让同一种动物的图片放到同一个文件夹,这是一个什么问题?
- A. 聚类
- B. 回归
- C. 分类
- D. 无监督学习
我的答案: A, D
第3题 (单选题)
在无人驾驶时,希望程序能够根据路况决策汽车的方向盘的旋转角度,那么该任务是?
- A. 分类
- B. 回归
- C. 聚类
- D. 降维
我的答案: B
机器学习之支持向量回归(SVR)
第1关:线性可分支持向量机
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握:1.线性二分类问题,2.基本思想,3.间隔与支持向量,4.对偶问题。
线性二分类问题
经过前面的学习,我相信大家对线性二分类问题应该非常熟悉了,其本质上就是找到一条决策边界,将我们的数据分成两类。如下图:
图中的绿线与黄线都能很好的将图中的红点与蓝点给区分开。但是,哪条线的泛化性更好呢?可能你不太了解泛化性,也就是说,我们的这条直线,不仅需要在训练集(已知的数据) 上能够很好的将红点跟蓝点区分开来,还要在测试集(未知的数据) 上将红点跟蓝点给区分开来。
假如经过训练,我们得到了黄色的这条决策边界用来区分我们的数据,这个时候又来了一个数据,即黑色的点,那么你觉得黑色的点是属于红的这一类,还是蓝色的这一类呢?
如上图,根据黄线的划分标准,黑色的点应该属于红色这一类。可是,我们肉眼很容易发现,黑点离蓝色的点更近,它应该是属于蓝色的点。这就说明,黄色的这条直线它的泛化性并不好,它对于未知的数据并不能很好的进行分类。那么,如何得到一条泛化性好的直线呢?这个就是支持向量机考虑的问题。
基本思想
支持向量机的思想认为,一条决策边界它如果要有很好的泛化性,它需要满足一下以下两个条件:
能够很好的将样本划分
离最近的样本点最远
比如下图中的黑线
它能够正确的将红点跟蓝点区分开来,而且,它还保证了对未知样本的容错率,因为它离最近的红点跟蓝点都很远,这个时候,再来一个数据,就不会出现之前黄色决策边界的错误了。
无论新的数据出现在哪个位置,黑色的决策边界都能够很好的给它进行分类,这个就是支持向量机的基本思想。
间隔与支持向量
在样本空间中,决策边界可以通过如下线性方程来描述:
wTx+b=0
其中w=(w1,w2,..,wd)为法向量,决定了决策边界的方向。b为位移项,决定了决策边界与原点之间的距离。显然,决策边界可被法向量和位移确定,我们将其表示为(w,b)。样本空间中的任意一个点x,到决策边界(w,b)的距离可写为:
r=∣∣w∣∣∣wTx+b∣
假设决策边界(w,b)能够将训练样本正确分类,即对于任何一个样本点(xi,yi),若它为正类,即yi=+1时,wTx+b≥+1。若它为负类,即yi=−1时,wTx+b≤−1。
如图中,距离最近的几个点使两个不等式的等号成立,它们就被称为支持向量,即图中两条黄色的线。两个异类支持向量到超平面的距离之和为:
r=∣∣w∣∣2
它被称为间隔,即蓝线的长度。欲找到具有“最大间隔”的决策边界,即黑色的线,也就是要找到能够同时满足如下式子的w与b:
编程要求
请仔细阅读相关知识,完成本关所设置的选择题任务。
测试说明
平台会对你的代码进行运行测试,如果实际输出结果与预期结果相同,则通关;反之,则 GameOver。
选择题
第1题 (单选题)
按照支持向量机的思想,下图哪条决策边界的泛化性最好?
- A. 绿线
- B. 黑线
- C. 黄线
我的答案: B
第2题 (单选题)
假设支持向量分别为 {3x1+4x2+5=+13x1+4x2+5=−1如下图:
则最大间隔r的值为?
- A. 0.3
- B. 0.4
- C. 0.5
- D. 2
我的答案: B
第3题 (单选题)
假设有两个样本点:(V,+1),(-V,-1)。其中,V=(3,2),则使得间隔最大的决策边界为: (ps:x为横坐标轴,y为纵坐标轴)
- A. x=0
- B. y=0
- C. 3x+2y=0
- D. 2x+3y=0
我的答案: C
第4题 (单选题)
有三个样本点:(x,+1),(y,+1),(z,-1),超平面为:a+b=1。 其中,x=(3,0),y=(0,4),z=(0,0),则以下说法错误的为:
- A. 超平面能够将三个样本点按类别分隔开来
- B. 样本y到超平面的距离为3
- C. 样本z到超平面的距离的平方为0.5
- D. 离超平面距离最近的样本为z
我的答案: B
第5题 (单选题)
图中,最大间隔决策边界为:
- A. x+y+1=0
- B. x-y+1=0
- C. -x-y+1=0
- D. -x+y+1=0
我的答案: D
第6题 (多选题)
下面说法正确的是?
- A. 支持向量机的最终模型仅仅与支持向量有关。
- B. 支持向量机的最终模型由所有的训练样本共同决定。
- C. 支持向量机的最终模型由离决策边界最近的几个点决定。
- D. 训练集越大,支持向量机的模型就一定越准确。
我的答案: A, C
第2关:线性支持向量机
任务描述
本关任务:使用sklearn实现线性支持向量机,并通过癌细胞数据中训练集对模型进行训练,再对测试集癌细胞数据进行识别。
相关知识
为了完成本关任务,你需要掌握:1.软间隔,2.LinearSVC。
数据集介绍
乳腺癌数据集,其实例数量是569,实例中包括诊断类和属性,帮助预测的属性一共30个,各属性包括为radius 半径(从中心到边缘上点的距离的平均值),texture 纹理(灰度值的标准偏差)等等,类包括:WDBC-Malignant 恶性和 WDBC-Benign 良性。用数据集的80%作为训练集,数据集的20%作为测试集,训练集和测试集中都包括特征和诊断类。
想要使用该数据集可以使用如下代码:
import pandas as pd
#获取训练数据
train_data = pd.read_csv('./step1/train_data.csv')
#获取训练标签
train_label = pd.read_csv('./step1/train_label.csv')
train_label = train_label['target']
#获取测试数据
test_data = pd.read_csv('./step1/test_data.csv')
数据集中部分数据与标签如下图所示:
软间隔
假如现在有一份数据分布如下图:
按照线性可分支持向量机的思想,黄色的线就是最佳的决策边界。很明显,这条线的泛化性不是很好,造成这样结果的原因就是数据中存在着异常点,那么如何解决这个问题呢,支持向量机引入了软间隔最大化的方法来解决。
所谓的软间隔,是相对于硬间隔说的,即之前我们所讲的支持向量机学习方法。回顾下硬间隔最大化的条件:
min21∣∣w∣∣2
s.t.yi(wTx+b)≥1
接着我们再看如何可以软间隔最大化呢?SVM对训练集里面的每个样本(xi,yi)引入了一个松弛变量xi≥0,使函数间隔加上松弛变量大于等于1,也就是说:
yi(wTx+b)≥1−xi
对比硬间隔最大化,可以看到我们对样本到超平面的函数距离的要求放松了,之前是一定要大于等于1,现在只需要加上一个大于等于0的松弛变量能大于等于1就可以了。也就是允许支持向量机在一些样本上出错,如下图:
编程要求
请仔细阅读右侧代码,结合相关知识,在Begin-End 区域内进行代码补充,完成使用sklearn实现线性支持向量机的任务。
测试说明
平台会对你的代码进行运行测试,如果实际输出结果与预期结果相同,则通关;反之,则 GameOver。
第3关:非线性支持向量机
任务描述
本关任务:使用sklearn实现非线性支持向量机,并通过鸢尾花数据中训练集对模型进行训练,再对测试集鸢尾花数据进行分类。
相关知识
为了完成本关任务,你需要掌握:1.核技巧,2.SVC。
数据集介绍
数据集为鸢尾花数据,一共有三个类别150个样本,每个样本有4个特征,由于支持向量机是一个二分类模型,这里我们只利用其中两个特征与两种类别(共100个样本)训练模型,且支持向量机算法返回的值为1与-1,所以要将标签为0的数据改为-1部分数据如下图:
数据获取代码:
#获取并处理鸢尾花数据
def create_data():
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['label'] = iris.target
df.columns = ['sepal length', 'sepal width', 'petal length', 'petal width', 'label']
data = np.array(df.iloc[:100, [0, 1, -1]])
#将标签为0的数据标签改为-1
for i in range(len(data)):
if data[i,-1] == 0:
data[i,-1] = -1
return data[:,:2], data[:,-1]
核技巧
我们的数据集有时候是非线性可分的情况,如下图:
对于非线性的情况,SVM的处理方式就是选择一个核函数。简而言之:在线性不可分的情况下,SVM通过某种事先选择的非线性映射**(核函数)**将输入变量映到一个高维特征空间,将其变成在高维空间线性可分,在这个高维空间中构造最优分类超平面。如将本关上图数据集映射成如下情况:
编程要求
请仔细阅读右侧代码,结合相关知识,在Begin-End 区域内进行代码补充,完成使用sklearn实现非线性支持向量机的任务。
测试说明
平台会对你的代码进行运行测试,如果实际输出结果与预期结果相同,则通关;反之,则 GameOver。
第4关:支持向量回归
任务描述
本关任务:使用sklearn实现线性支持向量机,并通过癌细胞数据中训练集对模型进行训练,再对测试集癌细胞数据进行识别。
相关知识
为了完成本关任务,你需要掌握:1.软间隔,2.LinearSVC。
数据集介绍
乳腺癌数据集,其实例数量是569,实例中包括诊断类和属性,帮助预测的属性一共30个,各属性包括为radius 半径(从中心到边缘上点的距离的平均值),texture 纹理(灰度值的标准偏差)等等,类包括:WDBC-Malignant 恶性和 WDBC-Benign 良性。用数据集的80%作为训练集,数据集的20%作为测试集,训练集和测试集中都包括特征和诊断类。
想要使用该数据集可以使用如下代码:
import pandas as pd
#获取训练数据
train_data = pd.read_csv('./step1/train_data.csv')
#获取训练标签
train_label = pd.read_csv('./step1/train_label.csv')
train_label = train_label['target']
#获取测试数据
test_data = pd.read_csv('./step1/test_data.csv')
数据集中部分数据与标签如下图所示:
软间隔
假如现在有一份数据分布如下图:
按照线性可分支持向量机的思想,黄色的线就是最佳的决策边界。很明显,这条线的泛化性不是很好,造成这样结果的原因就是数据中存在着异常点,那么如何解决这个问题呢,支持向量机引入了软间隔最大化的方法来解决。
所谓的软间隔,是相对于硬间隔说的,即之前我们所讲的支持向量机学习方法。回顾下硬间隔最大化的条件:
min21∣∣w∣∣2
s.t.yi(wTx+b)geq1
接着我们再看如何可以软间隔最大化呢?SVM对训练集里面的每个样本(xi,yi)引入了一个松弛变量xiigeq0,使函数间隔加上松弛变量大于等于1,也就是说:
yi(wTx+b)geq1−xi
对比硬间隔最大化,可以看到我们对样本到超平面的函数距离的要求放松了,之前是一定要大于等于1,现在只需要加上一个大于等于0的松弛变量能大于等于1就可以了。也就是允许支持向量机在一些样本上出错,如下图:
编程要求
请仔细阅读右侧代码,结合相关知识,在Begin-End 区域内进行代码补充,完成使用sklearn实现线性支持向量机的任务。
测试说明
平台会对你的代码进行运行测试,如果实际输出结果与预期结果相同,则通关;反之,则 GameOver。
逻辑回归
第1关:逻辑回归算法大体思想
任务描述
本关任务:根据本节课所学知识完成本关所设置的编程题。
相关知识
为了完成本关任务,你需要掌握:1.什么是逻辑回归,2.sigmoid函数。
什么是逻辑回归
当一看到“回归”这两个字,可能会认为逻辑回归是一种解决回归问题的算法,然而逻辑回归是通过回归的思想来解决二分类问题的算法。
那么问题来了,回归的算法怎样解决分类问题呢?其实很简单,逻辑回归是将样本特征和样本所属类别的概率联系在一起,假设现在已经训练好了一个逻辑回归的模型为f(x),模型的输出是样本x的标签是1的概率,则该模型可以表示成p^=f(x)。若得到了样本x属于标签1的概率后,很自然的就能想到当p^>0.5时x属于标签1,否则属于标签0。所以就有为样本x根据模型预测出的标签结果,标签0和标签1所代表的含义是根据业务决定的,比如在癌细胞识别中可以使0代表良性肿瘤,1代表恶性肿瘤)。
由于概率是0到1的实数,所以逻辑回归若只需要计算出样本所属标签的概率就是一种回归算法,若需要计算出样本所属标签,则就是一种二分类算法。
那么逻辑回归中样本所属标签的概率怎样计算呢?其实和线性回归有关系,学习了线性回归的同学肯定知道线性回归无非就是训练出一组参数WT和b来拟合样本数据,线性回归的输出为y^=WTx+b。不过y^的值域是(−∞,+∞),如果能够将值域为(−∞,+∞)的实数转换成(0,1)的概率值的话问题就解决了。要解决这个问题很自然地就能想到将线性回归的输出作为输入,输入到另一个函数中,这个函数能够进行转换工作,假设函数为σ,转换后的概率为p^,则逻辑回归在预测时可以看成p^=σ(WTx+b)。 σ其实就是接下来要介绍的sigmoid函数。
sigmoid 函数
sigmoid函数的公式为:
σ(t)=1/1+e−t
函数图像如下图所示:
从sigmoid函数的图像可以看出当t趋近于−∞时函数值趋近于0,当t趋近于+∞时函数值趋近于1。可见sigmoid函数的值域是(0,1),满足我们要将(−∞,+∞)的实数转换成(0,1)的概率值的需求。因此逻辑回归在预测时可以看成
p^=1/(1+e−WTx+b)
编程要求
根据提示,在右侧编辑器补充 python 代码,实现sigmoid函数。底层代码会调用您实现的sigmoid函数来进行测试。(提示: numpy.exp() 函数可以实现e的幂运算)
测试说明
测试用例:
输入:1
预期输出:0.73105857863
输入:-2
预期输出:0.119202922022
第2关:逻辑回归的损失函数
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为什么需要损失函数
训练逻辑回归模型的过程其实与之前学习的线性回归一样,就是去寻找合适的WT和b使得模型的预测结果与真实结果尽可能一致。所以就需要一个函数能够衡量模型拟合程度的好坏,也就是说当模型拟合误差越大的时候,函数值应该比较大,反之应该比较小,这就是损失函数。
逻辑回归的损失函数
根据上一节实训中所学习到的知识,我们已经知道了逻辑回归计算出的样本所属类别的概率p^=σ(WTx+b),样本所属列表的判定条件为有关。
当然逻辑回归的损失函数不仅仅与p^有关,它还与真实类别有关。假设现在有两种情况,情况A:现在有个样本的真实类别是0,但是模型预测出来该样本是类别1的概率是0.7(也就是说类别0的概率为0.3);情况B:现在有个样本的真实类别是0,但是模型预测出来该样本是类别1的概率是0.6(也就是说类别0的概率为0.4);请你思考2秒钟,AB两种情况哪种情况的误差更大?很显然,情况A的误差更大!因为情况A中模型认为样本是类别0的可能性只有30%,而B有40%。
假设现在又有两种情况,情况A:现在有个样本的真实类别是0,但是模型预测出来该样本是类别1的概率是0.7(也就是说类别0的概率为0.3);情况B:现在有个样本的真实类别是1,但是模型预测出来该样本是类别1的概率是0.3(也就是说类别0的概率为0.7);请你再思考2秒钟,AB两种情况哪种情况的误差更大?很想然,一样大!
所以逻辑回归的损失函数如下,其中cost表示损失函数的值,y表示样本的真实类别:
cost=−ylog(p^)−(1−y)log(1−p^)
这个式子其实很好理解,当样本的真实类别为1时,式子就变成了cost=−log(p^)。此时函数图像如下:
从图像能看出当样本的真实类别为1的前提下,p^越大,损失函数值就越小。因为p^越大就越说明模型越认为该样本的类别为1。
当样本的真实类别为0时,式子就变成了cost=−log(1−p^)。此时函数图像如下:
从图像能看出当样本的真实类别为0的前提下,p^越大,损失函数值就越大。因为p^越大就越说明模型越认为该样本的类别为1。
cost=−ylog(p^)−(1−y)log(1−p^)是一个样本的损失计算公式,但是在一般情况下需要计算的是m条样本数据的平均损失值,所以损失函数的最终形态如下,其中m表示数据集中样本的数量,i表示数据集中第i个样本:
cost=−m1i=0∑my(i)log(p^(i))−(1−y(i))log(1−p^(i))
知道了逻辑回归的损失函数之后,逻辑回归的训练流程就很明显了,就是寻找一组合适的WT和b,使得损失值最小。找到这组参数后模型就确定下来了。
选择题
第1题 (单选题)
逻辑回归的损失函数可以写成如下形式 cost={−log(p^)−log(1−p^)y=1y=0
- A. 对
- B. 错
我的答案: A
第2题 (多选题)
下列说法正确的是
- A. 损失值能够衡量模型在训练数据集上的拟合程度
- B. sigmoid函数不可导
- C. sigmoid函数的输入越大,输出就越大
- D. 训练的过程,就是寻找合适的参数使得损失函数值最小的过程
我的答案: A, C, D
第3关:梯度下降
任务描述
本关任务:用python构建梯度下降算法,并求取目标函数最小值。
相关知识
为了完成本关任务,你需要掌握:1.梯度下降算法。
什么是梯度
梯度下降算法原理
算法思想:梯度下降是一种非常通用的优化算法,能够为大范围的问题找到最优解。梯度下降的中心思想就是迭代地调整参数从而使损失函数最小化。假设你迷失在山上的迷雾中,你能感觉到的只有你脚下路面的坡度。快速到达山脚的一个策略就是沿着最陡的方向下坡。这就是梯度下降的做法:通过测量参数向量θ相关的损失函数的局部梯度,并不断沿着降低梯度的方向调整,直到梯度降为0,达到最小值。
其中η为学习率,是0到1之间的值,是个超参数,需要我们自己来确定大小。
-
随机初始参数
-
确定学习率
-
求出损失函数对参数梯度
-
按照公式更新参数
-
重复3、4直到满足终止条件(如:损失函数或参数更新变化值小于某个阈值,或者训练次数达到设定阈值)
编程要求
根据提示,使用 python 搭建梯度下降算法,并损失函数最小值时对应的参数theta,theta会返回给外部代码,由外部代码来判断theta是否正确。
测试说明
损失函数为:loss=(theta−3)2
最优参数为:3.0
你的答案跟最优参数的误差低于0.0001才能通关。
第4关:逻辑回归算法流程
任务描述
本关任务:使用逻辑回归算法建立一个模型,并通过梯度下降算法进行训练,得到一个能够准确对癌细胞进行识别的模型。
相关知识
为了完成本关任务,你需要掌握:1.逻辑回归,2.逻辑回归中的梯度下降。
数据集介绍
乳腺癌数据集,其实例数量是569,实例中包括诊断类和属性,帮助预测的属性一共30个,各属性包括为radius 半径(从中心到边缘上点的距离的平均值),texture 纹理(灰度值的标准偏差)等等,类包括:WDBC-Malignant 恶性和 WDBC-Benign 良性。用数据集的80%作为训练集,数据集的20%作为测试集,训练集和测试集中都包括特征和诊断类。
sklearn中已经提供了乳腺癌数据集的相关接口,想要使用该数据集可以使用如下代码:
from sklearn import datasets
#加载乳腺癌数据集
cancer = datasets.load_breast_cancer()
#X表示特征,y表示标签
X = cancer.data
y = cancer.target
数据集中部分数据与标签如下图所示:
构建逻辑回归模型
由数据集可以知道,每一个样本有30个特征和1个标签,而我们要做的事就是通过这30个特征来分析细胞是良性还是恶性,其中标签y=0表示是良性,y=1表示是恶性。逻辑回归算法正好是一个二分类模型,我们可以构建一个逻辑回归模型,来对癌细胞进行识别。模型如下:
z=b+w1x1+w2x2+…+wnxn
y=1+e−z1
其中xi表示第i个特征,wi表示第i个特征对应的权重,b表示偏置。
为了方便,我们稍微将模型进行变换:
z=w0x0+w1x1+w2x2+…+wnxn
其中x0等于1。
Z=θ.X
θ=(w0,w1,…,wn)
X=(1,x1,…,xn)
y=1+e−θ.X1
我们将一个样本输入模型,如果预测值大于等于0.5则判定为1类别,如果小于0.5则判定为0类别。
训练逻辑回归模型
我们已经知道如何构建一个逻辑回归模型,但是如何得到一个能正确对癌细胞进行识别的模型呢?通常,我们先将数据输入到模型,从而得到一个预测值,再将预测值与真实值结合,得到一个损失函数,最后用梯度下降的方法来优化损失函数,从而不断的更新模型的参数 θ,最后得到一个能够正确对良性细胞和癌细胞进行分类的模型。
在上一节中,我们知道要使用梯度下降算法首先要知道损失函数对参数的梯度,即损失函数对每个参数的偏导,求解步骤如下:
loss=−ylna−(1−y)ln(1−a)
∂w∂loss=∂a∂loss.∂z∂a.∂w∂z
∂a∂loss=−ay−1−a1−y(−1)=a(1−a)a−y
∂z∂a=(1+e−z)2e−z=a.(1−a)
∂w∂z=x
∂w∂loss=(a−y)x
其中a为预测值,y为真实值。
于是,在逻辑回归中的梯度下降公式如下:
wi=wi−η(a−y)xi
训练流程:
同梯度下降算法流程
编程要求
根据提示,在右侧编辑器补充 python 代码,构建一个逻辑回归模型,并对其进行训练,最后将得到的逻辑回归模型对癌细胞进行识别。
测试说明
只需返回预测结果即可,程序内部会检测您的代码,预测正确率高于95%视为过关。
第5关:sklearn中的逻辑回归
任务描述
本关任务:你需要调用 sklearn 中的逻辑回归模型,并通过癌细胞数据集中癌细胞的30种属性与类别对逻辑回归模型进行训练。我们会调用你训练好的逻辑回归模型,来对癌细胞进行识别。
相关知识
为了完成本关任务,你需要掌握:1.LogisticRegression。
数据介绍
乳腺癌数据集,其实例数量是569,实例中包括诊断类和属性,帮助预测的属性一共30个,各属性包括为radius 半径(从中心到边缘上点的距离的平均值),texture 纹理(灰度值的标准偏差)等等,类包括:WDBC-Malignant 恶性和 WDBC-Benign 良性。用数据集的80%作为训练集,数据集的20%作为测试集,训练集和测试集中都包括特征和诊断类。
sklearn中已经提供了乳腺癌数据集的相关接口,想要使用该数据集可以使用如下代码:
from sklearn import datasets
#加载乳腺癌数据集
cancer = datasets.load_breast_cancer()
#X表示特征,y表示标签
X = cancer.data
y = cancer.target
数据集中部分数据与标签如下图所示:
LogisticRegression
LogisticRegression的构造函数中有三个常用的参数可以设置:
-
solver:{'newton-cg' , 'lbfgs', 'liblinear', 'sag', 'saga'}, 分别为几种优化算法。默认为liblinear。 -
C:正则化系数的倒数,默认为1.0,越小代表正则化越强。 -
max_iter:最大训练轮数,默认为100。
和 sklearn 中其他分类器一样,LogisticRegression类中的fit函数用于训练模型,fit函数有两个向量输入:
-
X:大小为 [样本数量,特征数量] 的ndarray,存放训练样本 -
Y:值为整型,大小为 [样本数量] 的ndarray,存放训练样本的分类标签
LogisticRegression类中的predict函数用于预测,返回预测标签,predict函数有一个向量输入:
X:大小为[样本数量,特征数量]的ndarray,存放预测样本
LogisticRegression的使用代码如下:
logreg = LogisticRegression(solver='lbfgs',max_iter =10,C=10)
logreg.fit(X_train, Y_train)
result = logreg.predict(X_test)
编程要求
填写cancer_predict(train_sample, train_label, test_sample)函数完成癌细胞识别任务,其中:
-
train_sample:训练样本 -
train_label:训练标签 -
test_sample:测试样本
测试说明
只需返回预测结果即可,程序内部会检测您的代码,预测正确率高于95%视为过关。
机器学习 --- 朴素贝叶斯分类器
第1关:条件概率
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握条件概率。
条件概率
朴素贝叶斯分类算法是基于贝叶斯定理与特征条件独立假设的分类方法,因此想要了解朴素贝叶斯分类算法背后的算法原理,就不得不用到概率论的一些知识,首当其冲就是条件概率。接下来就开启我们的条件概率之旅吧。
什么是条件概率
概率指的是某一事件A发生的可能性,表示为P(A)。而条件概率指的是某一事件A已经发生了条件下,另一事件B发生的可能性,表示为P(B|A),举个例子:
今天有25%的可能性下雨,即P(下雨)=0.25;
今天75%的可能性是晴天,即P(晴天)=0.75;
如果下雨,我有75%的可能性穿外套,即P(穿外套|下雨)=0.75;
如果下雨,我有25%的可能性穿T恤,即P(穿T恤|下雨)=0.25;
从上述例子可以看出,条件概率描述的是|右边的事件已经发生之后,左边的事件发生的可能性,而不是两个事件同时发生的可能性!
怎样计算条件概率
设A,B是两个事件,且P(A)>0,称P(B|A)=P(AB)/P(A)为在事件A发生的条件下,事件B发生的条件概率。(其中P(AB)表示事件A和事件B同时发生的概率)
举个例子,现在有一个表格,表格中统计了甲乙两个厂生产的产品中合格品数量、次品数量的数据。数据如下:
| 甲厂 | 乙厂 | 合计 | |
|---|---|---|---|
| 合格品 | 475 | 644 | 1119 |
| 次品 | 25 | 56 | 81 |
| 合计 | 500 | 700 | 1200 |
现在想要算一下已知产品是甲厂生产的,那么产品是次品的概率是多少。这个时候其实就是在算条件概率,计算非常简单。
假设事件A为产品是甲厂生产的,事件B为产品是次品。则根据表中数据可知P(AB)=25/1200,P(A)=500/1200。则P(B|A)=P(AB)/P(A)=25/500。
乘法定理
将条件概率的公式两边同时乘以P(A),就变成了乘法定理,即P(AB)=P(B|A)*P(A)。那么乘法定理怎么用呢?举个例子:
现在有一批产品共100件,次品有10件,从中不放回地抽取2次,每次取1件。现在想要算一下第一次为次品,第二次为正品的概率。
从问题来看,这个问题问的是第一次为次品,第二次为正品这两个事件同时发生的概率。所以可以用乘法定理来解决这个问题。
假设事件A为第一次为次品,事件B为第二次为正品。则P(AB)=P(A)*P(B|A)=(10/100)*(90/99)=0.091。
编程要求
根据本关所学习到的知识,完成所有选择题。
测试说明
平台会对你填写的答案进行运行测试,如果实际输出结果与预期结果相同,则通关。
选择题
第1题 (单选题)
P(AB)表示的是事件A与事件B同时发生的概率,P(A|B)表示的是事件B已经发生的条件下,事件A发生的概率。
- A. 对
- B. 错
我的答案: A
第2题 (单选题)
从1,2,…,15中小明和小红两人各任取一个数字,现已知小明取到的数字是5的倍数,请问小明取到的数大于小红取到的数的概率是多少?
- A. 7/14
- B. 8/14
- C. 9/14
- D. 10/14
我的答案: C
第2关:贝叶斯公式
任务描述
本关任务:根据本节课所学知识完成本关所设置的选择题。
相关知识
为了完成本关任务,你需要掌握:
-
全概率公式;
-
贝叶斯公式。
全概率公式
贝叶斯公式是朴素贝叶斯分类算法的核心数学理论,在了解贝叶斯公式之前,我们需要先了解全概率公式的相关知识。
引例
小明从家到公司上班总共有三条路可以直达,如下图:
但是每条路每天拥堵的可能性不太一样,由于路的远近不同,选择每条路的概率如下表所示:
| L1 | L2 | L3 |
|---|---|---|
| 0.5 | 0.3 | 0.2 |
每天从上述三条路去公司时不堵车的概率如下表所示:
| L1不堵车 | L2不堵车 | L3不堵车 |
|---|---|---|
| 0.2 | 0.4 | 0.7 |
如果不堵车就不会迟到,现在小明想要算一算去公司上班不会迟到的概率是多少,应该怎么办呢?
其实很简单,假设事件C为小明不迟到,事件A1为小明选L1这条路并且不堵车,事件A2为小明选L2这条路并且不堵车,事件A3为小明选L3这条路并且不堵车。那么很显然P(C)=P(A1)+P(A2)+P(A3)。
那么问题来了,P(A1)、P(A2)和P(A3)怎么算呢?其实只要会算P(A1)其他的就都会算了。我们同样可以假设事件D1为小明选择L1路,事件E1为不堵车。那么P(A1)=P(D1)*P(E1)。但是在从表格中我们只知道P(D1)=0.5,怎么办呢?
回忆一下上一关介绍的乘法定理,不难想到P(A1)=P(D1)*P(E1|D1)。从表格中可以看出P(E1|D1)=0.2。因此P(A1)=0.5*0.2=0.1。
然后依葫芦画瓢可以很快算出,P(A2)=0.3*0.4=0.12,P(A3)=0.2*0.7=0.14。所以P(C)=0.1+0.12+0.14=0.36。
全概率公式
当为了达到某种目的,但是达到目的有很多种方式,如果想知道通过所有方式能够达到目的的概率是多少的话,就需要用到全概率公式(上面的例子就是这种情况!)。全概率公式的定义如下:
若事件B1,B2,…,Bn两两互不相容,并且其概率和为1。那么对于任意一个事件C都满足:
P(C)=P(B1)P(C∣B1)+…+P(Bn)P(C∣Bn)=sumi=1nP(Bi)P(C∣Bi)
引例中小明选择哪条路去公司的概率是 两两互不相容的 (只能选其中一条路去公司), 并且和为1 。所以小明不迟到的概率可以通过全概率公式来计算,而引例中的计算过程就是用的全概率公式。
贝叶斯公式
当已知引发事件发生的各种原因的概率,想要算该事件发生的概率时,我们可以用全概率公式。但如果现在反过来,已知事件已经发生了,但想要计算引发该事件的各种原因的概率时,我们就需要用到贝叶斯公式了。
贝叶斯公式定义如下,其中A表示已经发生的事件,Bi为导致事件A发生的第i个原因:
P(Bi∣A)=sumi=1nP(A∣Bi)P(Bi)P(A∣Bi)P(Bi)
贝叶斯公式看起来比较复杂,其实非常简单,分子部分是乘法定理,分母部分是全概率公式(分母等于P(A))。
如果我们对贝叶斯公式进行一个简单的数学变换(两边同时乘以分母,再两边同时除以P(Bi))。就能够得到如下公式:
P(A∣Bi)=P(Bi)P(Bi∣A)P(A)
这个公式是朴素贝叶斯分类算法的核心数学公式,至于为什么,下一关实训将会详细介绍。
编程要求
根据本关所学习到的知识,完成所有选择题。
测试说明
平台会对你填写的答案进行运行测试,如果实际输出结果与预期结果相同,则通关。
选择题
第1题 (单选题)
对以往数据分析结果表明,当机器调整得良好时,产品的合格率为98%,而当机器发生某种故障时,产品的合格率为55%。每天早上机器开动时,机器调整得良好的概率为95%。计算已知某日早上第一件产品是合格时,机器调整得良好的概率是多少?
- A. 0.94
- B. 0.95
- C. 0.96
- D. 0.97
我的答案: D
第2题 (单选题)
一批产品共8件,其中正品6件,次品2件。现不放回地从中取产品两次,每次一件,求第二次取得正品的概率。
- A. 1/4
- B. 1/2
- C. 3/4
- D. 1
我的答案: C
第3关:朴素贝叶斯分类算法流程
任务描述
本关任务:填写python代码,完成fit与predict函数,分别实现模型的训练与预测。
相关知识
为了完成本关任务,你需要掌握:
-
朴素贝叶斯分类算法的训练流程;
-
朴素贝叶斯分类算法的预测流程。
引例
在炎热的夏天你可能需要买一个大西瓜来解暑,但虽然你的挑西瓜的经验很老道,但还是会有挑错的时候。尽管如此,你可能还是更愿意相信自己经验。假设现在在你面前有一个纹路清晰,拍打西瓜后声音浑厚,按照你的经验来看这个西瓜是好瓜的概率有80%,不是好瓜的概率有20%。那么在这个时候你下意识会认为这个西瓜是好瓜,因为它是好瓜的概率大于不是好瓜的概率。
朴素贝叶斯分类算法的预测流程
朴素贝叶斯分类算法的预测思想和引例中挑西瓜的思想一样,会根据以往的经验计算出待预测数据分别为所有类别的概率,然后挑选其中概率最高的类别作为分类结果。
假如现在一个西瓜的数据如下表所示:
| 颜色 | 声音 | 纹理 | 是否为好瓜 |
|---|---|---|---|
| 绿 | 清脆 | 清晰 | ? |
若想使用朴素贝叶斯分类算法的思想,根据这条数据中颜色、声音和纹理这三个特征来推断是不是好瓜,我们需要计算出这个西瓜是好瓜的概率和不是好瓜的概率。
假设事件A1为好瓜,事件B为绿,事件C为清脆,事件D为清晰,则这个西瓜是好瓜的概率为P(A1|BCD)。根据上一关中最后提到的公式可知:
P(A1∣BCD)=P(BCD)P(A1)P(B∣A1)P(C∣A1)P(D∣A1)
同样,假设事件A2为好瓜,事件B为绿,事件C为清脆,事件D为清晰,则这个西瓜不是好瓜的概率为P(A2|BCD)。根据上一关中最后提到的公式可知:
P(A2∣BCD)=P(BCD)P(A2)P(B∣A2)P(C∣A2)P(D∣A2)
朴素贝叶斯分类算法的思想是取概率最大的类别作为预测结果,所以如果满足下面的式子,则认为这个西瓜是好瓜,否则就不是好瓜:
P(BCD)P(A1)P(B∣A1)P(C∣A1)P(D∣A1)>P(BCD)P(A2)P(B∣A2)P(C∣A2)P(D∣A2)
从上面的式子可以看出,P(BCD)是多少对于判断哪个类别的概率高没有影响,所以式子可以简化成如下形式:
P(A1)P(B∣A1)P(C∣A1)P(D∣A1)>P(A2)P(B∣A2)P(C∣A2)P(D∣A2)
所以在预测时,需要知道P(A1),P(A2),P(B|A_1),P(C|A_1),P(D|A_1)等于多少。而这些概率在训练阶段可以计算出来。
朴素贝叶斯分类算法的训练流程
训练的流程非常简单,主要是计算各种条件概率。假设现在有一组西瓜的数据,如下表所示:
| 编号 | 颜色 | 声音 | 纹理 | 是否为好瓜 |
|---|---|---|---|---|
| 1 | 绿 | 清脆 | 清晰 | 是 |
| 2 | 黄 | 浑厚 | 模糊 | 否 |
| 3 | 绿 | 浑厚 | 模糊 | 是 |
| 4 | 绿 | 清脆 | 清晰 | 是 |
| 5 | 黄 | 浑厚 | 模糊 | 是 |
| 6 | 绿 | 清脆 | 清晰 | 否 |
从表中数据可以看出:
P(是好瓜)=4/6,
P(颜色绿|是好瓜)=3/4,
P(颜色黄|是好瓜)=1/4,
P(声音清脆|是好瓜)=1/2,
P(声音浑厚|是好瓜)=1/2,
P(纹理清晰|是好瓜)=1/2,
P(纹理模糊|是好瓜)=1/2,
P(不是好瓜)=2/6,
P(颜色绿|不是好瓜)=1/2,
P(颜色黄|是好瓜)=1/2,
P(声音清脆|不是好瓜)=1/2,
P(声音浑厚|不是好瓜)=1/2,
P(纹理清晰|不是好瓜)=1/2,
P(纹理模糊|不是好瓜)=1/2。
当得到以上概率后,训练阶段的任务就已经完成了。我们不妨再回过头来预测一下这个西瓜是不是好瓜。
| 颜色 | 声音 | 纹理 | 是否为好瓜 |
|---|---|---|---|
| 绿 | 清脆 | 清晰 | ? |
假设事件A1为好瓜,事件B为绿,事件C为清脆,事件D为清晰。则有:
P(A1)P(B∣A1)P(C∣A1)P(D∣A1)=64∗43∗21∗21=81
假设事件A2为不是瓜,事件B为绿,事件C为清脆,事件D为清晰。则有:
P(A2)P(B∣A2)P(C∣A2)P(D∣A2)=62∗21∗21∗21=241
由于81>241,所以这个西瓜是好瓜。
编程要求
根据提示,完成fit与predict函数,分别实现模型的训练与预测。(PS:在fit函数中需要将预测时需要的概率保存到self.label_prob和self.condition_prob这两个变量中)
其中fit函数参数解释如下:
-
feature:训练集数据,类型为ndarray; -
label:训练集标签,类型为ndarray; -
return:无返回。
predict函数参数解释如下:
-
feature:测试数据集所有特征组成的ndarray。(PS:feature中有多条数据); -
return:模型预测的结果。(PS:feature中有多少条数据,就需要返回长度为多少的list或者ndarry)。
测试说明
部分训练数据如下 (PS:数据以ndarray的方式存储,不包含表头。其中颜色这一列用1表示绿色,2表示黄色;声音这一列用1表示清脆,2表示浑厚。纹理这一列用1表示清晰,2表示模糊,3表示一般) :
| 颜色 | 声音 | 纹理 | 是否为好瓜 |
|---|---|---|---|
| 2 | 1 | 1 | 1 |
| 1 | 2 | 2 | 0 |
| 2 | 2 | 2 | 1 |
| 2 | 1 | 2 | 1 |
| 1 | 2 | 3 | 1 |
| 2 | 1 | 1 | 0 |
只需完成fit与predict函数即可,程序内部会调用您所完成的fit函数构建模型并调用predict函数来对数据进行预测。预测的准确率高于0.8视为过关。
第4关:拉普拉斯平滑
任务描述
本关任务:填写python代码,完成fit函数,实现模型训练功能。 (PS:fit函数中没有平滑处理的话是过不了关的哦)
相关知识
为了完成本关任务,你需要掌握拉普拉斯平滑。
拉普拉斯平滑
假设现在有这样一批西瓜的数据,如果根据上一关中所提到的知识您应该能很快的知道应该怎样训练模型。
| 编号 | 颜色 | 声音 | 纹理 | 是否为好瓜 |
|---|---|---|---|---|
| 1 | 绿 | 清脆 | 清晰 | 是 |
| 2 | 黄 | 浑厚 | 清晰 | 否 |
| 3 | 绿 | 浑厚 | 模糊 | 是 |
| 4 | 绿 | 清脆 | 清晰 | 是 |
| 5 | 黄 | 浑厚 | 模糊 | 是 |
| 6 | 绿 | 清脆 | 清晰 | 否 |
但是需要注意的是,在不是好瓜的数据中没有一条数据中纹理是模糊的,也就是说P(模糊|否)=0。很显然,如果不做任何处理,那么在预测时,只要预测数据中的纹理的值是模糊,模型预测出不是好瓜的概率就一定是0(概率是连乘的,只要有一项是0那么结果就是0)。这显然是不合理的,所以我们要进行平滑处理,而最常用的方法就是拉普拉斯平滑。
拉普拉斯平滑指的是,假设N表示训练数据集总共有多少种类别,Ni表示训练数据集中第i列总共有多少种取值。则训练过程中在算类别的概率时分子加1,分母加N,算条件概率时分子加1,分母加Ni。
接下来用上面的西瓜数据来模拟一下,从表格知N=2,N1=2, N2=2, N3=2。P(是好瓜)=(4+1)/(6+2),P(颜色绿|是好瓜)=(3+1)/(4+2),P(颜色黄|是好瓜)=(1+1)/(4+2),P(声音清脆|是好瓜)=(1+1)/(2+2),P(声音浑厚|是好瓜)=(1+1)/(2+2),P(纹理清晰|是好瓜)=(1+1)/(2+2),P(纹理模糊|是好瓜)=(1+1)/(2+2),P(不是好瓜)=(2+1)/(6+2),P(颜色绿|不是好瓜)=(1+1)/(2+2),P(颜色黄|是好瓜)=(1+1)/(2+2),P(声音清脆|不是好瓜)=(1+1)/(2+2),P(声音浑厚|不是好瓜)=(1+1)/(2+2),P(纹理清晰|不是好瓜)=(1+1)/(2+2),P(纹理模糊|不是好瓜)=(0+1)/(2+2)。
可以看出,经过拉普拉斯平滑后,P(模糊|否)平滑成了1/4,使得模型更加合理。
编程要求
根据提示,完成fit函数,实现模型的训练功能。(PS:在fit函数中需要将预测时需要的概率保存到self.label_prob和self.condition_prob这两个变量中)
其中fit函数参数解释如下:
-
feature:训练集数据,类型为ndarray; -
label:训练集标签,类型为ndarray; -
return:无返回。
测试说明
部分训练数据如下 (PS:数据以ndarray的方式存储,不包含表头。其中颜色这一列用1表示绿色,2表示黄色;声音这一列用1表示清脆,2表示浑厚。纹理这一列用1表示清晰,2表示模糊,3表示一般) :
| 颜色 | 声音 | 纹理 | 是否为好瓜 |
|---|---|---|---|
| 2 | 1 | 1 | 1 |
| 1 | 2 | 2 | 0 |
| 2 | 2 | 2 | 1 |
| 2 | 1 | 2 | 1 |
| 1 | 2 | 3 | 1 |
| 2 | 1 | 2 | 0 |
只需完成fit函数即可,程序内部会调用您所完成的fit函数构建模型并进行预测。预测的准确率高于0.9视为过关。
第5关:新闻文本主题分类
任务描述
本关任务:使用sklearn完成新闻文本主题分类任务。
相关知识
为了完成本关任务,你需要掌握如何使用sklearn提供的MultinomialNB类与文本向量化。
数据简介
本关使用的是20newsgroups数据集,20newsgroups数据集是用于文本分类、文本挖据和信息检索研究的国际标准数据集之一。数据集收集了18846篇新闻组文档,均匀分为20个不同主题(比如电脑硬件、中东等主题)的新闻组集合。
部分数据如下:
From: Mamatha Devineni Ratnam <mr47+@andrew.cmu.edu>
Subject: Pens fans reactions
Organization: Post Office, Carnegie Mellon, Pittsburgh, PA
Lines: 12
NNTP-Posting-Host: po4.andrew.cmu.edu
I am sure some bashers of Pens fans are pretty confused about the lack
of any kind of posts about the recent Pens massacre of the Devils. Actually,
I am bit puzzled too and a bit relieved. However, I am going to put an end
to non-PIttsburghers relief with a bit of praise for the Pens. Man, they
are killing those Devils worse than I thought. Jagr just showed you why
he is much better than his regular season stats. He is also a lot
fo fun to watch in the playoffs. Bowman should let JAgr have a lot of
fun in the next couple of games since the Pens are going to beat the pulp out of Jersey anyway. I was very disappointed not to see the Islanders lose the final
regular season game. PENS RULE!!!
其中新闻文本对应的主题标签,已经用0-19这20个数字表示。
文本向量化
由于数据集中每一条数据都是很长的一个字符串,所以我们需要对数据进行向量化的处理。例如,I have a apple! I have a pen!可能需要将该字符串转换成向量如[10, 7, 0, 1, 2, 6, 22, 100, 8, 0, 1, 0]。
sklearn提供了实现词频向量化功能的CountVectorizer类。想要对数据进行向量化,代码如下:
from sklearn.feature_ext\fraction.text import CountVectorizer
#实例化向量化对象
vec = CountVectorizer()
#将训练集中的新闻向量化
X_train = vec.fit_transform(X_train)
#将测试集中的新闻向量化
X_test = vec.transform(X_test)
但是仅仅通过统计词频的方式来将文本转换成向量会出现一个问题:长的文章词语出现的次数会比短的文章要多,而实际上两篇文章可能谈论的都是同一个主题。
为了解决这个问题,我们可以使用tf-idf来构建文本向量,sklearn中已经提供了tf-idf的接口,示例代码如下:
from sklearn.feature_ext\fraction.text import TfidfTransformer
#实例化tf-idf对象
tfidf = TfidfTransformer()
#将训练集中的词频向量用tf-idf进行转换
X_train = tfidf.fit_transform(X_train_count_vectorizer)
#将测试集中的词频向量用tf-idf进行转换
X_test = vec.transform(X_test_count_vectorizer)
MultinomialNB
MultinomialNB是sklearn中多项分布数据的朴素贝叶斯算法的实现,并且是用于文本分类的经典朴素贝叶斯算法。在本关中建议使用MultinomialNB来实现文本分类功能。
在MultinomialNB实例化时alpha是一个常用的参数。
alpha: 平滑因子。当等于1时,做的是拉普拉斯平滑;当小于1时做的是Lidstone平滑;当等于0时,不做任何平滑处理。
MultinomialNB类中的fit函数实现了朴素贝叶斯分类算法训练模型的功能,predict函数实现了法模型预测的功能。
其中fit函数的参数如下:
-
X:大小为[样本数量,特征数量]的ndarry,存放训练样本 -
Y:值为整型,大小为[样本数量]的ndarray,存放训练样本的分类标签
而predict函数有一个向量输入:
X:大小为[样本数量,特征数量]的ndarry,存放预测样本
MultinomialNB的使用代码如下:
clf = MultinomialNB()
clf.fit(X_train, Y_train)
result = clf.predict(X_test)
编程要求
填写news_predict(train_sample, train_label, test_sample)函数完成新闻文本主题分类任务,其中:
-
train_sample:原始训练样本,类型为ndarray; -
train_label:训练标签,类型为ndarray; -
test_sample:原始测试样本,类型为ndarray。
测试说明
只需返回预测结果即可,程序内部会检测您的代码,预测正确率高于0.8视为过关。













