0%

[toc]

@[toc]
我们看下spark是怎么针对master、worker、executor的异常情况做处理的。

容错机制-exeuctor退出#

首先可以假设worker中的executor执行任务时,发送了莫名其妙的异常或者错误,然后对应线程消失了。
我们看这个时候会做什么事情
在这里插入图片描述
上图总结下来就是:
executor由backend进程包着,如果抛异常,他会感知到,并调用executorRunner.exitStatus(), 通知worker

看下通知worker之后发生了什么:
在这里插入图片描述

  • worker会通知master,master会将exectorInfo清除,然后调度worker让他重新创建
  • 这里可以看到worker创建executor的指令仍然是让master来调度和管理的,不是自己想创建就创建。
    接下来就是重建executor,然后重新开始执行这个地方的任务了(因此数据也会重新拉,之前发送端缓存的数据就能够派上用场了)
    在这里插入图片描述
    完整流程图如下:
    在这里插入图片描述

worker异常退出#

假设此时是worker挂掉了, 那么正在执行任务的exeuctor和master会怎么做呢?如下:
在这里插入图片描述
可以看到worker有一个shutdownHook,会帮忙关闭正在执行的executor。
但是此时worker挂了,因此没法往master发送消息了,怎么办?
上一节有讲到master和worker之间存在心跳,因此就会有如下处理:
在这里插入图片描述
可以看到当master发现worker的心跳丢失时,会进行:

  • 删除执行列表里的worker信息
  • 重新下发创建worker的操作给对应spark节点
  • 通知driver这个worker里面的exector都已经lost了

看下此时worker重建和driver分别做了什么:
在这里插入图片描述
这里还可以看到1个很重要的概念:

  • master关心worker状态
  • driver会关心executor进展
  • exeuctor重建后需要注册到driver上

完整流程图如下:
在这里插入图片描述

master异常#

由于master不参与任务的计算,只是对worker做管理,因此对于master的异常,分两种情况:

1:任务正常运行时master异常退出#

则流程如下:
在这里插入图片描述
从这里可以看到当任务正常运行时,只会在结束时,由driver去触发master的清理资源操作,但是master进程已经挂掉了,所以也没关系。

2:当任务执行过程中,master挂掉后,worker和executor也异常了#

在这里插入图片描述
可以看到这时候时没办法重启exeuctor的
此时driver那边就会看起来任务一直没进展了。

为了避免这种情况,master可以做成无状态化,然后做主备容灾。当然master节点做的时候比较少,一般不容易崩溃,除非认为kill或者部署节点故障。

[toc]

简述spark的任务运行流程#

先是在写spark代码的时候,背后做一些RDD的转换,写完后构建DAG,划分stage, 然后提交到资源管理器分配计算资源, 并在worker上执行。
在这里插入图片描述

首先写spark代码时离不开对RDD的调用,那么:

为什么需要RDD#

  1. 数据处理模型统一:
    RDD是1个数据结构, 能够获取数据的分区。
    不区分流式还是批式,只理解为1个数学模型。

  2. 依赖划分原则:
    RDD之间通过窄依赖(仅1个依赖)和宽依赖(多依赖)进行关联。
    为什么要划分依赖?
    依赖数量不同,决定是否能在1个stage和节点中执行。
    同时也决定了容灾策略,是否需要保存所有父RDD

  3. 数据处理效率:
    1个RDD,同时可在多个节点并发执行。

  4. 容错处理:
    RDD本身是不可变的数据集,这样可保证数据恢复在这里插入图片描述

wordCount代码的背后#

以wordCount代码为例

textFile#

第一步是读文件数据。

1
2
JavaSparkContext ctx = new JavaSparkContext(sparkConf);
ctx.textFile(args[0],1)

这一步会生成HadoopRDD
在这里插入图片描述
这里注意下, 里面有一个清理序列化的操作, 分布式传输数据时,序列化很重要,而序列化时有些成员是无法被序列化的,在java中的关键字是transien.

MappedRDD是什么?
如下:
在这里插入图片描述
即我们的RDD,会被包装到一个单点依赖的对象里,并指明这是单点依赖。
并且textFile这个过程, 其实是生成了2个RDD, 1个是HadoopRDD,还有一个是读取数据转成字符串的mapRDD。 他们各自被塞进dependecy对象中,并通过依赖建立连接。

  • 注意,一般分布式计算设计DAG图时, 都是只有input指针(即用输入对象做连接), 利用input来确定DAG关系。 在spark里就是依赖dependency的概念

第二步做FlatMap#

接着我们调用flatMap

1
2
3
4
5
JavaRDD<String> words = lines.flatMap(new FlatMapFunction<String, String>(){
@Override
public Iterable<String> call(String s){
return Arrays.asList(SPACE.split(s));
})

背后的RDD和依赖i情况变成如下:
在这里插入图片描述

第三步mapToPair#

懒得敲了,这里省略java代码。
在这里插入图片描述
看一下dag。
在这里插入图片描述

第四步聚合#

需要分组,然后进行合并相同的单词数量
在这里插入图片描述
此时dag如下:
在这里插入图片描述

  • 注意, 并不是shuffle这个RDD被包装进了shuffle依赖, 而是它的前置RDD被包进了shuffle依赖。
  • 即dependency确实是只包装依赖的, 你如果是属于某个shuffle过程的依赖,那么就会被包装成shuffleDepnecy。

最后一步collect#

当写完后,执行collet,进行计算执行和提交。
在这里插入图片描述

完整流程如下:
在这里插入图片描述

Collect的时候发生了什么#

collect后, 会通过dagScheduler进行runJob, submitJob的时候会返回一个waiter,在client端主程序中就会进行等待。
即client端提交任务时其实是异步的,会返回一个waiter进行等待,
在这里插入图片描述

看一下submitJob的时候发生了什么
在这里插入图片描述
前面看起来都是一些业务处理, 关键在handleJobSumitted的时候,会做一个newStage的操作,正好可以看一下spark里的stage是怎么确定和生成的。
在这里插入图片描述
父(依赖)stage列表是怎么获取的?
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200701234813809.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2E3OTk1ODE
上图里的关键信息在于, 当遇到shuffle的时候,就会隔离出一个stage。

可以看一下之前提到的RDD拼成的DAG图,如下:
在这里插入图片描述

newStage后,有如下情况:
在这里插入图片描述
可以看到又给stage里有一个rdds的数组, 里面放了该stage的所有RDD, 并建立了依赖关系。
然后每个stage又通过parent去确定依赖关系。

stage提交#

newStage之后,会进行stage的提交
在这里插入图片描述

看一下submitStage的时候做了什么,注意此时是先从finalStage开始提交的。
在这里插入图片描述
这里可以看到, 虽然我们做了finalStage的提交, 但是会优先提交它所依赖的前置stage, 一直等待stage 完成了再真正提交自己这个stage。

这里看一下 stage是怎么发送的
在这里插入图片描述
上图可以看到stae座位task时,也是区分shuffle类型和map类型。
在这里插入图片描述

  • 这句话重点: 有多少个未计算的分区,决定了有多少个task, 即stage中的分区和task一一对应

完成的stage创建和提交流程图如下:
在这里插入图片描述

[toc]

假设此时已经构建好DAG划分好stage,接着就是要分发task了。
当运行submitTask时,有如下的过程:

在这里插入图片描述
上图可以看到,每次都会新建一个专门的taskManager,都运行ok后就会消失,并不是独立持续存在的一个角色。
reviveOffers具体做什么的呢?看一下
在这里插入图片描述

  • 可以看到reciveOffer主要是做worker资源分配的。
  • workerOffer列表一般需要做随机处理,避免一直分给同一个
  • 各机器上的CPU核数在分配的考虑范围之内。
  • spark每次可能会有多个TaskSetManager提交到rootPool中, 此时会根据FIO做分配, 先给抵押给TaskSetManager做worker分配,再给第二个分配。

看一下之后做了什么:
在这里插入图片描述

可以看到经过分配后, 各task都绑定到了对应的worker上,生成一个列表,很明显后面就会的、根据这个列表,进行task的发送。

看一下具体的资源的分配过程在做什么:
在这里插入图片描述
可以看到发送前,会依次检查对应节点的task是否够,如果够就分配一些task给这个几点,并进行序列化。

分配已经完成,回到之前的地方
在这里插入图片描述

看一下刚才这几个过程在各模块间怎么运行的
在这里插入图片描述
注意每次都是一个新的executor
因此当executor给taskScheduler发消息时
会进行如下操作, 即告诉全局的管理者,我有新的执行者加入了。
在这里插入图片描述
接着DAGScheduer确认到有executor加入后,说明没问题了,于是通知TaskSchduler,去告诉对应的executor,可以运行任务了
在这里插入图片描述
为什么分了那么多角色
我认为是为了解耦。
即DAGScheduler不知道task具体分给了哪个host上。 也不持有exeuctor, 必须通过TaskScheduler来统一调度和通知。

executor执行任务#

看一下真正执行任务时发生了啥。
在这里插入图片描述
可以看到每个task都是独立一个线程,并放到一个map中做管理。
看一下线程run的时候做了什么
在这里插入图片描述
task的反序列化是在task线程中去执行的,即进入线程时,executor根本不知道这是什么任务。
运行的中间结果会做保存。

task线程运行结果后,会进行内存的回收
在这里插入图片描述

回收内存后开始做最后结果的处理
在这里插入图片描述

注意任务分成了resultTask和ShuffleMapTask
最终结果任务完成后就不需要再跑stage了
而如果是shuffleMapTask,则需要跑后续的stage,并且会检查一下他的outputLocs分区(这个分区的数据用于给后面的task做拉取), 如果有问题为null,则重新运行再考虑是否通知后续的stak执行。

完整流图#

上面提到的完整图如下:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

[toc]

spark的cacheManager#

在这里插入图片描述
这张图能知道什么?
Q: spark对RDD的缓存是通过谁去做的?
A: 通过BlockManager去缓存, 并且根据配置选项,决定缓存在文件还是内存中。


driver、executor和BlockManager的关系#

在这里插入图片描述
从中可以看到

  1. blockManagerMaster在driver端生成
  2. executor中生成blockManager,并负责向BMM注册。
  3. spark中注册消息通过ActorSystem进行发送

blockManager包含什么#

在这里插入图片描述

  • BlockManager的作用?我理解是负责做RDD的存储,如何存下来给后续任务去使用。
  • memoryStore和DiskStore,说明把block做存储时,有内存和磁盘2种方式,存储后就都i通过这个Store去管理。
  • 存储时以Block为单位,所以会有个映射用的数组
  • 有一个负责和Driver的BlockManagerMaster通信的引用接口
  • 还有个shuffClient,负责做 备份下载

把块block 存入blockManager的流程#

在这里插入图片描述
需要注意的一个地方: 当内存不足以放入Block时, 他会先释放一下,再判断是否满足!

从blockManager中删除块#

在这里插入图片描述
红色方框写错了, 应该是如果只支持磁盘存储,则从DiskStore中调用方法取出block。

shuffClient 下载block操作#

在这里插入图片描述
BMMAC就是BlockManagerMasterActor,我当初瞎写的简称

  • 注意点:当要取的块来自好几个BlockManager时, 把它打乱顺序,避免好几个BM同时从某一个BM上下载数据!

shuffeClinet的备份操作#

在这里插入图片描述

  • BM为什么要备份他的block?这个书里没提!真坑。我的理解是为了防止节点崩溃或者丢失,导致中间任务无法继续执行?
  • 因为其他的BlockManager能接收的block可能有限,所以备份时可能会涉及多个block, 每次我们一样,从BMmaster那里拿一个 随机的blockManager做备份,避免都往同一个上备份。

完整笔记图#

在这里插入图片描述

[toc]

数据相关概念#

数据集dataset#

一堆西瓜以及西瓜描述的集合
(色泽=青绿,根=蜷缩)、(色泽=乌黑,根=粗糙)

样本sample/示例instance#

指数据集中的某条记录
即是集合中的某个对象(即某个西瓜)

属性attribute/特征feature#

对象在某方面的表现或者性质名称
例如色泽、根

属性值attribute value#

青绿、乌黑都是属性值

样本空间sample space#

把属性当作坐标轴, 属性值作为坐标点,则构成了样本空间。
(维度比较多的话,不太适合称为坐标系类比,所以叫做样本空间)

维数dimensionality#

指属性个数

特征向量feature vector#

样本空间中的某个点,就叫特征向量。
特征向量 = 样本 = 示例

以上概念的数学公式表示#

D={x1,x2,…,xm}
这个D就是数据集
X1、xm指示例

xi = {xi1;xi2;xi3}
这个xi就是某个示例或者样本
xij 指 xi的j属性的值。

学习相关的数据概念#

学习learning/训练training#

指从数据中得到模型的这个过程
这个过程通过执行某个学习算法来得到(即怎么根据数据,一步步迭代计算,去得到预测模型)

训练数据training data#

上面训练过程中使用的数据

训练样本training sample#

每个样本

训练集training set#

训练样本组成的集合

  • (还没用于训练的数据,不能叫做训练xxx)

假设hypothesis#

学习得到的模型, 能够反应数据的规律, 这个反应规律的情况称为“假设”

真相/真实ground-truth#

上面提到的潜在规律, 叫做真相/真实
比如颜色黑的西瓜一般比较难吃,这个就是潜在规律

学习器learner#

学习得到的模型 也可以叫做学习器
可以看作是学习算法在给定数据和参数空间上的实例化。

标记(label)#

各训练样本的实际结果信息
例如 (色泽=青绿,根=蜷缩)->好瓜、(色泽=乌黑,根=粗糙)->坏瓜

好坏瓜这个名词,则称为标记

样例(example)#

样本 + 标记 = 样例
一般用(xi,yi)来表示某个样例

标记空间label space/输出空间#

样例的1个集合,也称为标记空间。
注意, 样本空间和 标记是区分开的, 不可以把y合并到x中。 完全不同的1个空间维度

学习过程概念#

模型model#

指给模型1个西瓜, 模型能判断它是否是好瓜。
类似1个f(x)的函数

学习算法learing algorithm#

指根据 数据 得到模型的 计算方法。

分类classification#

如果预测的结果(即标记) 都是离散值或者枚举值,则叫做分类
例如好瓜/坏瓜 就是一种类

二分类(binary classification)#

只涉及2个类别的分类,一般会叫作正反类。

  • 正类positive class
  • 反类negative class

多分类 multi-class classification#

涉及多个分类的任务

回归regression#

指得到的结果是一个不明确的数值。
例如0.95,0.37…之类的

空间映射#

指任务预测结果的数学表达
X->Y
Y = {-1.1}, 指二分类
|Y| > 2 , 即个数大于2,指多分类
Y = R, R为实数集

测试testing#

得到模型后, 使用模型进行预测的过程, 叫做测试

测试样本testing sample#

被用来预测的样本
即已经算得模型的情况下, 用来做测试的。
y = f(x)
f是模型, x是测试样本, Y是你所预测期望的标记

聚类(clustering)#

指西瓜可能被分为很多类, 但是这个分类我们事先并不知道的
我们希望让学习算法帮我们找出这个分类。

监督学习supervised learning#

指训练数据拥有标记信息

无监督学习unsupervised learning#

指训练数据没有标记信息, 希望依靠学习过程帮我们得到标记或聚类

泛化generalization#

把训练得到的模型, 用到之前没出现过的样本里去预测, 这个过程叫泛化(类似于上其他真实数据了)

分布distribution#

指样本属于某种分布(例如正态分布啥的), 即属性啥的可能是平均可能是不平均。
但至少有1个分布公式。

独立同分布i.i.d#

我们希望所有样本, 取出来时是满足样本的分布规律, 是独立随机取的。
而不是单独从某个值里取一大批类似的。

归纳induction#

从特殊归纳出一般的泛化过程
从具体事实推出一般规律

广义归纳学习#

从样例中学习规律

狭义归纳学习#

从数据集中得到概念。 概念学习研究比较少,太难了

演绎deduction#

从一般规律推导出具体的其他事实。

假设空间hypothesis space#

以好瓜的假设空间为例
我们要得到好瓜的所有可选假设
例如
色泽=绿,根=硬,敲声=响
或者 色泽=,根=硬,敲声=
或者 无(即无一种情况是好瓜)

版本空间version space#

假设空间非常大,就是所有情况的枚举,但肯定存在1个和训练集匹配的好瓜假设空间,我们叫做版本空间

可以理解为是满足当前训练集正例的的所有假设空间

例如好瓜的色泽有青和绿
那么版本空间一定有存在色泽=*,
不可以是色泽=青, 因为这样的假设没有包含绿色。

要求这个假设必须包含所有正例

在假设空间中搜索包含正例且不包含反例的所有假设

如果存在多种相反的假设, 算法会择优选择某些特定的假设。这就是归纳偏好

可以理解为算法认为 西瓜的颜色更重要,于是基于颜色的假设会先优先于其他属性。

可以是训练集有限定个, 当我们决定在坐标轴上画1个曲线时, 可以有不同的曲线,有的人可以偏陡峭, 有的可以平滑。或者某些点其实就是特例,画出线时就变成了尖尖角。


奥卡姆剃刀原则: 选择最简单的那个


假设有2种设置了不同偏好的学习算法a和b, 能证明a比b好吗?

不行。
根据NLT定理(天下没有免费的午餐, No Free Lunch Theorem)
如果样本空间足够大,且所有问题出现的机会相同,所有情况同等重要,那么任何偏好的算法,得出的实际样本总误差其实是一样的。

但是我们解决1个问题, 一定是有自己的场景的, 比如虽然颜色=黄色的西瓜好吃, 但是这种颜色的西瓜很少,不应当分配足够多的偏好给他。

c964b49087cf9f8d9cf522b856fee4e6.png


提问:试述机器学习能在互联网搜索的哪些环节起作用

  1. 在向搜索引擎提交信息的阶段,能够从提交文本中进行信息提取,进行语义分析。
  2. 在搜索引擎进行信息匹配的阶段,能够提高问题与各个信息的匹配程度。
  3. 在向用户展示搜索结果的阶段,能够根据用户对结果感兴趣的程度进行排序。

6b91078551ecb319e24e1683c0dd9c21.png

[toc]

2.1 经验误差和过拟合#

  • 错误率(error rate) = 样本分类错误个数a/ 样本总数b

  • 精度(accuracy)= 1 - 错误率

  • 训练误差(training error): 训练集上的误差。 也叫经验误差(empirical error)

  • 在新样本上的误差称为 泛化误差(generalization error)

  • 过拟合(overfitting): 把训练样本的所有特点当作必要条件。 例如训练集中的树叶都有锯齿, 于是看到不带锯齿的树叶,它就认为一定不是树叶。

  • 欠拟合(underfitting) : 训练样本的一般性质尚未学好

过拟合无法避免,因为我们无法解决NP=P问题

训练集和测试集的划分(评估方法)#

即如何把手头的数据集划分成训练集和测试集, 测试集用来评估泛化误差。

留出法#

把数据集划分为2个互斥的集合
结果的比例(例如好瓜坏瓜),在2个集中应该一样

使用留出法时,一般要采用若干次随机划分, 重复进行实验评估后,取随机值作为评估结果。
例如进行100次随机二分, 得到100个评估结果,这个平均值才是实际评估值。

缺点:
训练集和测试集 因为分成2块了,可能导致集合之间差别非常大。而我们还无法控制

交叉验证法(cross validation)#

把数据分成m份
每次取1份作为测试集, 其他m-1份都是训练集,做训练
同样操作进行m次,每次取1份不同的作为测试集。

最后对结果求平均

也叫k折交叉验证

留一法:
数据正好只有m个,于是每一份只有1个。 因为测试集很小, 训练集很大, 所以留一法会比较准确。
缺点: 开销太大, 如果一百万个样本, 留一法的训练时间指数级增加。

自助法#

每次从m个样本中随机取1个样本,复制1份之后,放入训练集中。 进行m次。

m如果足够大, 求极限之后, (1-1/m)^m的极限概率为36.8%

大概1/3的数据会被选为训练集。
那么剩下的就是测试集。

好处是训练集和测试机存在共有数据
如果数据量比较小, 可以使用自助法,避免数据太少没法分。

最终模型#

当使用数据集D 划分训练和测试, 进行各种训练后, 得到模型时, 还不是最终模型。
我们需要最后用D再做1次训练, 这时候才是我们准备提交给用户的最终模型。

2.2 性能度量#

回归任务中, 最常用的性能度量, 就是均方误差
如果是数据分布,则是求积分。

错误率#

分类错误的总概率

精度#

分类正确的总概率

查准率、查重率#

二分类问题,有
真正例TP true positive(预测是好瓜,实际也是好瓜)
假正例FP false positive(预测是好瓜,实际时坏瓜)
真反例TN true negative(预测是坏瓜,实际也是坏瓜)
假反例FN false negative

查准率P= TP/ (TP+FP)
即等于我选出的好瓜准不准

查全率R=TP/(TP+FN)
即等于我选出的所有瓜中,好瓜多不多

二者并不平衡,比如为了好瓜多,就会加大数量,这样可能造成查准率低。

P-R曲线:#

查全率为横坐标,查冲率为纵坐标
按照好瓜概率,把样本排序
则第一个好瓜必定查准率100%。
接着慢慢按我预测的概率顺序放入瓜
慢慢查准率会下降,而查全率会上升。

如果1个P-R曲线完全包住另一个曲线, 则前者是好的模型。

BEP:P-R曲线平衡点:
查全率=查冲率时的值
越高越好

F1度量:
F1 = 2* P * R / (P + R)

带查准或者查重偏好的
b = 查全率重要性/查准率重要性
Fb = (1+b^2)* P * R/(b^2 * P) + R
b<1, 则查准率更中鞥要

如果是经过多次训练得到的模型, 则可以把TP、FN之类的都取平均,再去计算 micro-P \micro-R还有micro-F1

ROC曲线#

学习器会给每个样本划定一个概率
在我们规定了正例的概率阈值时, 才能把每个样本是否是正例给预测出来。
而这个阈值(截断点)是通过人工来设置的。

如果这个阈值舍得很高(即0.9以上才是正例),则被预测准确的正例就会很少, 而预测准确的反例就会变多

预测准确的正例概率,叫做TPR曲线(True postive rate), 即全部真实正例中,被我预测准的正例。 作为纵轴

预测错误的正例概率,叫做FPR曲线(false postive rate),即明明是反例,被我当作正例了。作为横轴

假设学习器给每个样本都做了概率预测。
那么接着我们就要划定阈值。
阈值从样本中选取。样本按照概率从大到小排列。

假设概率最高的样本是0.99
则认为0.99以上的才是正例,0.99以下的是反例。
那么我们很大概率TRP会很小(即很少能有正例能中), 而FPR也很小(即很少有正例会被误判)

接着逐步减小阈值,慢慢就得到一个ROC曲线。
ROC包围的面积AUC越大,则我们认为这个学习器越好(即对与我们标定的概率,他能综合表现最佳)。

代价敏感错误率和代价曲线#

判别错误的代价有所不同
如果把好的判别成坏的, 代价为cost10
把坏的判别成好的,代价为cost01

大部分情况下,把坏的判别成好的,都是很严重的。代价会高一点

  • 代价敏感错误率:
    把样本中判别错误的情况出现的概率分别乘上代价。

代价曲线:
把ROC曲线的每一点, 都得到该点(该阈值)对应的FPR和FNR, 分别以(正例概率代价为0, FPR) 和(正例概率为1, FNR) 画直线,然后得到一个被一堆直线包起来的下界。。。

2.3比较校验#

当上头给我们的指标是要求 实际错误率是10%。

但我们只有测试样本,怎么去假设我们很接近实际错误率了呢?
即我们有1000个样本, 那么测试错误率至少为多少时,我们觉得实际错误率<10%才是可信的?

我们指定可接受误差α为0.05
使用二项检验临界值公式, 算出一个临界值
当测试样本小于临界值时, 在0.0.5的误差范围内,可以假设学习器的实际错误率不会大于10%
如果大于临界值,则认为这个假设大概率不成立。

实际上会做多次训练测试, 最终得到的概率分布服从t分布。

t分布概念:

交叉验证t检验#

怎么使用假设检验, 确认2个不同的学习器之间的性能是否一致?

把2个学习器做k折交叉验证的差值, 分别求个平均和方差, 然后判断某个计算式是否小于临界值txx。。

为了避免不同轮次的训练,会有一定程度重叠,采用
5x2交叉验证, 每次2折交叉验证之前,把数据打乱, 是的5次交叉验证中的数据划分不重复。。 从而得到的差值是包含了第一折和第二折的。
这时候在t分布的假设下做检验。

McNemar检验#

二分类问题中, 通过“A算法错误,B算法正确”和“A算法正确 ,B算法错误” 这2个集合之间的差值, 判断是否服从某分布, 来假设A算法和B算法的性能是否相同

Friedman检验#

如果数据集有很多组(前面的检验都是针对一组数据集的),则怎么利用这么多组数据集,来验证A\B\C算法的性能呢?

把每个数据集的ABC训练结果排序
D1数据集中, A排第1, B排第2,C排第3

D2数据集中, B排第1, A排第2.5,C排第2.5(排名相等的话就平分这个排名,5/2=2.5)

然后可以得到每个算法的平均序值。
使用Frieddman公式来判断性能是否一致。

如果Friedman公式判断 所有算法的性能不一致, 则使用Nemenyi做后续检验。

Nemenyi可以判断2个算法之间的性能是否一致

偏差和方差#

偏差——方差分解, 解释学习算法性能的重要工具。

偏差(bias)指 预测输出与真实标记的差别
度量了学习算法的期望预测与真实结果的偏离程度。刻画了算法本身的拟合能力

方差就是 一堆预测输出数据的方差。
方差度量了同样大小的训练集的变动所导致的性能变化。刻画了数据扰动所造成的影响。

噪声是 真实标记自身的方差(为了区分,叫做噪声)
表达了当前任务上,任何学习算法所能达到的最好期望误差(即实际的都有这么多误差),刻画了学习问题本身的难度。

泛化误差分解 偏差、方差、噪声之和。

偏差和方差之间是由冲突的。

训练不足时,学习器的拟合能力不强,扰动不足, 则主要是偏差比较大。

随着训练变多,偏差变小, 而方差之间就体现出来了。

如果训练数据全部被学习器拟合(偏差为0), 则为过拟合。