机器学习和数据挖掘算法面试知识点

机器学习算法


决策树(DT)

ID3: 基于信息增益的大小来逐层确定分类的特征。我们知道信息量的增加能消除对事件的不确定性,因此我们每次选择信息增益大的特征作为分类特征, 表示引入此特征后,信息量增加最多,能把对事件的不确定性降为最低,墒最低。信息增益g(D,A)(互信息)由熵H(D)与条件熵H(D|A)之差算出, 条件墒H(D|A)表示在引入A特征后,D的不确定度,也就是墒的大小,我们需要找到条件熵H(D|A)较小的特征,表示当前确定的特征A可以使数据集D在此分类下的不确定性(熵)达到最低, 也就是分类后的数据的“纯度”最高.

C4.5: 以信息增益作为划分标准的模型ID3, 存在偏向选择取值较多的特征,例如ID3会更容易选择样本编号作为划分特征, 这样每个分支只包含一个样本, 此时这些分支的纯度已经达到最大, 信息增益最大. 但是这样的模型显然不具有泛化能力, 因此我们使用改进的C4.5模型, C4.5使用信息增益比, 即用信息增益除以这个特征的固有特性(熵)来作为划分准则. 随着特征A的取值数量增加, A的熵值通常会增加, 因为A的纯度降低了, 这样能够校正特征A取值数量的影响.

CART: 既能完成分类又能完成回归任务,对分类问树用基尼指数最小化准则,对回归树用平方误差最小化准则。最小二乘回归树的构建过程就是不断寻找最优切分特征 j 和切分点 s ,使以下最小平方误差最小:

min j , s [ min c 1 x i R 1 ( j , s ) ( y i c 1 ) 2 + min c 2 x i R 2 ( j , s ) ( y i c 2 ) 2 ]

其中 R 1 ( j , s ) R 2 ( j , s ) 分别表示在特征 j 下样本值小于和大于切分点 s 的划分区域,而 c 1 c 2 代表这种划分下两个区域中样本真实值 y 的平均值,也就是模型在这一节点(划分区域)的输出值(回归值)。直观上,回归树在每一层的构建中,遍历了所有输入变量 j 和每个变量下的切分对 ( j , s ) ,来找到两个固定的平均值 c 1 c 2 分别以最小的误差来代表划分后的两个节点上所有的样本 y 值。

优点:

  • 树结构模型, 非线性, 易于理解和可解释性强
  • 能同时处理数值型和类别型离散数据, 对于类别变量, 无需one-hot编码处理
  • 能处理缺失数据(C4.5)。对于计算有缺失值特征A的信息增益:只计算其未缺失样本的信息增益,并乘以未缺失样本的占比来得到最终的信息增益。若选择A作为划分特征时,让A中缺失值的样本以不同的权重(概率)同时进入不同的子节点中去,而权重根据各个子节点中的样本占比来获得。

缺点:

  • 决策树往往能够对训练数据有很好的分类能力, 甚至达到百分之百预测, 但对未出现过的数据未必有很好的预测能力, 很有可能发生过拟合, 因此需要剪枝, 将树变得简单, 保持其泛化能力

剪枝

预剪枝:在生长的过程中,就估计当前节点的分裂能不能带来决策树的性能提升,若不能,则停止划分。基于贪心的思想,虽然当前划分不能提升其泛化性能,甚至可能导致暂时性能的下降,但是后续划分却有可能提高性能,而预剪枝只考虑当前这一步,禁止对未来可能性的探索,可能给决策树带来欠拟合的风险

  1. 达到树的最大深度
  2. 最优划分的信息增益小于阈值,停止生长
  3. 计算划分前和划分后验证集的精度,若划分后精读提高,则继续生长

后剪枝:先生成一颗完整的树,然后从下往上比较每个节点剪和不剪在验证集中的精度,若剪后精度大于或者等于不减,那么剪枝。一般情况下,后剪枝的欠拟合风险小,最后剪出来的树比预剪枝的大,但是需要先生成树再剪枝,事件开销大。

决策树如何处理连续型数据:

首先, 将连续特征A的值按照递增排序, 每两个相邻值的中点被看做可能的分裂点. 例如A有n个值, 则有n-1个划分点, 对于每个划分点, 数据集被划分为两个分区D1和D2, 其中D1小于划分点而D2大于此划分点, 在这两个分区中计算这个划分点的信息增益, 选择信息增益最大的划分作为最佳分裂点.


GDBT(梯度提升决策树)

GBDT(梯度提升决策树)是一种基于Boosting提升思想的机器学习方法, 这种Boosting思想体现在将一组弱学习器提升为强学习器的过程, GBDT中的基学习器通常是非线性的CART决策树, 无论是回归还是分类任务, 这里的CART决策树都是用的它的回归树来实现. 每次迭代的过程中, 会用一棵回归树拟合真实值与之前所有树的结果的”残差”, 随着迭代的进行,这个”残差”越来越小, 表示模型对数据的拟合能力越来越强.

抽象地说,模型的训练过程是对一任意可导目标函数的优化过程,用回归树拟合目标函数的负梯度,让目标函数(损失函数)越来越小, 该算法可被看作在函数空间里对目标函数进行优化。

算法过程(回归任务)

  1. 初始化一个只有根节点的树 f 0 , 用一个常数 c 0 作为这个节点的值, 这个常数通过估计损失函数的极小化得到
  2. 对每次迭代 m = 1 , 2 . . . M :

    a) 计算损失函数 L ( y i , f m 1 ) 在上一个回归树模型 f m 1 的负梯度,将它作为当前回归树 f m 残差 r m 的估计
    b)训练一棵最小二乘回归树CART来拟合残差 r m ,所有样本被划分到这棵树的不同叶节点区域 R m j j 表示叶节点编号
    c)对每个节点 R m j 中的所有样本值估计出一个常数 c m j 用来代表这个叶节点的输出值, 这个常数能使损失函数极小化,通常满足 c m j = arg min c x i R m j L ( y i , f m 1 ( x i ) + c )
    d)以一定的步长 α 更新当前回归树 f m ( x ) = f m 1 ( x ) + j α × c m j I ( x R m j ) ,检查精度要求是否满足,否则进行下一步迭代

  3. 得到输出的最终模型 f m ( x ) .

有几点需要强调一下:

  • 当损失函数为均方误差时,c步骤中各个节点值的 c m j 实际上为节点中所有样本值的平均值,与最小二乘回归树的节点值计算一致,而且此时负梯度的值就为残差值 y i f m 1 ( x i ) ,由损失函数求一次导数得到,可以说残差是负梯度的特例
  • 当损失函数为其他时,如分类任务中的交叉熵,负梯度和 c m j 则需要根据损失函数来计算,负梯度比较好求,问题在于 c m j ,通用一点来讲,我们可以利用多次线性搜索估计出 c m j ,但是也可以一步到位,利用损失函数的二阶导数来求极小值,类似于牛顿法(将 f m 1 x i 点二阶展开),不展开
  • 由于每棵树是在上一棵树的基础上拟合残差, 每次迭代构建的二叉树回归树要求泛化能力强, 这样才不会导致过拟合严重. 因此只需要深度很浅, 结构简单的树即可, 此时每个基学习器的方差小, 偏差大.

与提升回归树(Boosting Tree)比较

可以说基于梯度的提升回归树GBDT是提升回归树BDT的升级和扩展,普通的提升回归树BDT每次迭代中都是只去拟合残差,因此损失函数只能是均方差,而GBDT将残差的表示扩展到了梯度,允许了更多丰富的损失函数,因此让GBDT能够被用在分类任务上.还有一点重要的区别是,GBDT引用了学习率 α ,也就是每次只沿着梯度方向改变一点点,这样,每次划分只是局部小修改,随着迭代层数增多,整个模型精度提高.网上说,残差是全局的优化,而梯度是局部的优化,这句话并不完全正确,梯度确实代表着函数值局部的变化方向,但是如果步长为1,梯度与残差此时效果是一样的,都是全局优化. 例如学习率为1和损失函数为均方差 1 2 ( y i f ( x i ) ) 2 的GBDT其实就是BDT, 两者没有区别.

如何应用在分类问题:

对于分类问题,与众多机器学习方法一样, GBDT仍然是把它转化为回归问题, 对于二分类任务来说, 就像逻辑回归一样,每个叶节点输出的值代表着对数几率, 也可以认为每个叶节点回归目标为正样本的概率, 通过比较概率大小获得最终样本的类别. 多分类则是在每次迭代中同时生成k棵回归树,k为类别个数,每棵树的叶节点则表示着某一类样本的得分, 样本最终对各个类的概率由softmax对每个得分做归一化处理得到. 分类问题的损失函数一般为交叉熵.

Xgboost与GBDT的区别

  • 分类器更丰富: 传统GBDT以非线性的CART决策树作为基分类器,xgboost还支持线性分类器。
  • 基分类器节点分裂准则不同: 传统GBDT的CART树只能以均方差衡量分裂前后的误差, xgboost则构造一个误差函数,对其进行二阶泰勒展开, 同时利用了一阶和二阶导数直接求误差函数的极小值, 而且这个误差函数是可以自定义的.
  • 增加正则项: xgboost在损失函数里加入了正则项,用于控制模型的复杂度。正则项里包含了树的叶子节点个数、每个叶子节点上输出值的L2模的平方和, 降低了模型的方差,使学习出来的模型更加简单,防止过拟合
  • 特征抽样: xgboost借鉴了随机森林的做法,对特征进行抽样再拟合, 不仅能降低过拟合,还能减少计算
  • 并行计算: xgboost在特征粒度上开多个线程同时计算它们各自的最佳信息增益.
  • 近似分割点: 对于每个特征,传统的GBDT需要对所有的分割点计算信息增益, 而xgboost预先对数据进行了排序, 只考虑分位点,降低了计算复杂度

KNN

懒惰算法,在训练的时候只是把数据存起来,预测的时候才开始计算与测试样本距离最近的K个样本,然后用数量多的样本类别作为最后的分类类别,对于回归问题来说,均值作为最后的回归值。但是每搜索一个样本都需要花费O(n)时间遍历整个训练集,解决的方案是在存数据的时候就构造一个kd树,用来快速检索相邻的点。

kd树在构建时,依次选择k维空间的坐标轴进行切分,每次选择此坐标轴上中位数的训练样本为切分点,然后其他样本被分到这两个子区域中,直到子区域中没有样本,此时切分点为叶子节点。

检索的时候先找到一个最近的叶节点,然后才用回溯的做法去找该叶节点的兄弟节点,有没有比当前节点更近的,如果有就更新,然后继续回溯,直到根节点,最后的最近点即为所求(最邻近k=1)。时间复杂度O(logn),k的取值也会影响最终的预测结果


K-means

  1. 随机选取一些k个样本点作为k个类别的中心
  2. 计算每个样本距离这k个中心的距离,将每个样本划分到距离自己最近的中心,形成k个簇,然后再更新这k个簇的中心,即簇中每个样本坐标的均值
  3. 重复2,直到中心的坐标不发生更新

非监督算法,但需要使用先验知识确定其类别个数k值,另外不同的初始化可能导致最后分类的结果完全不同


CTR点击率预测解决方案 GBDT+FFM

14年kaggle比赛criteo第一名台大解决方案: 有连续特征L1-L13, 有离散特征C1-C26.

  1. 用L1-L13特征和部分离散特征训练GBDT模型, 部分离散特征训练指的是出现频率高于4百万次的值, 如C1-4, C2-5…表示C1特征的4这个值在整个数据集中出现频率高于4百万次. 对于一个样本来说, 如果在C1特征下有出现4这个值, 那么这一位就编码为1, 以此类推, 一共可以得到26维的部分离散特征.
  2. 训练出30棵GBDT树, 每棵树深度为7, 那么一棵树最多有2^7个叶节点, 对于生成的特征, 用树的编号和叶节点的编号表示, 如 [1:4 2:7 3:6] 表示此样本落在了树1的叶节点4上, 树2的叶节点7上和树3的叶节点6上. 最后会生成30维的向量, 每一位表示样本落在当前树叶节点的编号, 如果用onehot编码展开这30维向量, 最终会获得30* 2^7长度
  3. FFM特征准备: 对于连续特征L1-L13, 若数值大于2, 则用log(v)^2变换, 对于原始C1-C26特征, 将所有的出现频率低于10次的值用特殊值代替, 对于GBDT生成的特征保持不变. 然后用Hash对这三类特征的所有值进行Hash编码, 对于一个数值value, 最终变换后为value’=hashCode(value) mod 10^6, 其中,6为编码空间, 根据数据集的大小来定.
  4. 用以上三类特征用FFM模型训练, 然后对训练出来的结果进行矫正Calibration, 如: 在线上表现为0.2632, 而在线下的平均表现为0.2663, 因此有一个0.003的差距gap, 所以每次预测的数据都需要减去0.003

FM与FFM的区别

FM只考虑不同特征下某个值与某个值的组合, FFM加上了某个特征下某个值与另外特征下某个值的组合, 更加细化, 这里field-aware是指特征级别的field:

ϕ ( w , x ) = j 1 , j 2 C 2 w j 1 , f 2 , w j 2 , f 1 x j 1 x j 2

其中 j 1 , j 2 分别为特征域, f 1 , f 2 代表着所有特征下的每个非零特征值,详见


SVM和LR的区别及应用场景

SVM和LR区别:

  • 都是二分类, LR可以直接推广至多分类任务,SVM则不行
  • LR的输出具有自然的概率意义,在给出预测标记的同时也给出了概率,SVM则不具有概率意义
  • SVM使用hinge损失函数,这个损失函数的特点是使解具有稀疏性 (因为这个损失有一大块零区域,当数落在某个范围内才计算Loss值,其他情况都为零),也就是最终决定决策面的只是少数几个支持向量, 而对于离决策面远的大多数点不给予考虑, 这也就导致SVM对噪声(异常值)敏感. LR的损失函数则是光滑的单调递减函数, 它的损失随着真实样本与预测值的距离减小而减小,并不像SVM那么”一刀切”,因此每个样本点都对决策面有贡献, 也就是具有全局性, 因此噪音对LR的影响可以被这种全局性所抑制.

应用场景(来自Andrew Ng的机器学习课程):

1)如果特征数n相对于样本数m更大,比如 n = 10,000,m = 1,000,则使用LR和线性核函数SVM

理由:特征数相对于训练样本数已经够大了,使用线性模型就能取得不错的效果,不需要过于复杂的模型;

2)如果特征数n较小,样本数m比较大,比如n = 10,m = 10,000,则使用SVM(高斯核函数)

理由:在训练样本数量足够大而特征数较小的情况下,可以通过使用复杂核函数的SVM来获得更好的预测性能,而且因为训练样本数量并没有达到百万级,使用复杂核函数的SVM也不会导致运算过慢;

3)如果特征数n较小,样本数m非常大,比如n = 100, m = 500,000,则应该引入/创造更多的特征,然后使用lr或者线性核函数SVM

理由:因为训练样本数量特别大,使用复杂核函数的SVM会导致运算很慢,因此应该考虑通过引入更多特征,然后使用线性核函数的SVM或者lr来构建预测性更好的模型。

SVM如何应用在多分类问题

  • 一对多法(one-vs-rest). 训练时依次把某个类别的样本归为一类,其他剩余的样本归为另一类,这样k个类别的样本就构造出了k个SVM。分类时将未知样本分类为具有最大分类函数值的那类。假如我有四类A,B,C,D 要划分, 训练的时候, 对于A所对应的向量作为正集,B,C,D所对应的向量作为负集, 训练出一个关于A正例的模型, 以此类推, 再训练出另外3个模型. 预测时, 一个样本在四个模型中得分最高的即为最终类别.
  • 一对一法(one-versus-one,简称1-v-1, pairwise) 其做法是在任意两类样本之间设计一个SVM,因此k个类别的样本就需要设计k(k-1)/2个SVM。当对一个未知样本进行分类时,最后得票最多的类别即为该未知样本的类别。Libsvm中的多类分类就是根据这个方法实现的。

SVD分解过程

http://www.cnblogs.com/LeftNotEasy/archive/2011/01/19/svd-and-applications.html

https://charleshm.github.io/2016/03/Singularly-Valuable-Decomposition/


数据挖掘

相关性分析

标称数据(离散变量)用卡方检验来判断相关性: 卡方统计检验假设A和B是独立的,对于一定自由度,一定的置信水平下,拒绝假设的值为常数C(由查表得),若算出来的卡方值大于C,那么就拒绝相互独立的假设,认为两个A和B是(强)相关的

数值数据(连续变量)的相关系数: 相关系数r用来估计连续数据A和B的相关度,-1<=r<=1,若r大于0,则A和B是正相关的,表示A随着B的增加而增加,而且r越接近1,A和B的正相关性越强

数值数据(连续变量)的协方差: 也是用来计算连续数据A和B的相关性,A和B的协方差与相关系数r关系为: C o v ( A , B ) = r A , B × σ A σ B 其中 σ A , σ B 为A和B的标准差。协方差还可以由期望计算得到: C o v ( A , B ) = E ( A B ) E ( A ) E ( B ) ,此时若A和B相互独立,则 E ( A B ) = E ( A ) E ( B ) ,而且协方差为0,然而,反之不成立,即使协方差等于0,A和B不一定独立,只能说他们不相关,数值上A不随着B的变化而变化,但是有可能A和B的影响体现在其他方面,比如方差。

深度学习


Dropout

把神经元以p的概率被激活,p值越高,随机失活越弱,可以有效防止神经网络的过拟合,类似于随机森林。在预测的时候,一般是关掉随机失活,但是这个时候的输出需要乘以p,因为训练的时候,输出为 p x + ( 1 p ) 0 ,有 1 p 的概率输出0,而预测的时候全部都是激活的,因此输出全为 x ,那么就需要 x p x 来保持同样的输出。

以上方法需要在predict的时候特意乘以p,实际上我们更倾向于反向随机失活,就是在训练的过程中就调整输出的数值范围,也就是在随机失活后除以p,这样的好处是无论使用随机失活与否,都不需要修改predict的代码,详情

解释残差网络H(X)=F(X)+X

普通的神经网络H(X)=F(X), F(X)为本层的输出,H(X)为下一层的输入,输入输出直接串联。若现在有个映射把输入5映射到5.1,对与普通神经网络有H(5)=F(5)=5.1,而对于残差网络则是H(5)=F(5)+5=5.1,F(5)=0.1,即本层的F(X)只考虑输入与输出之间的残差;若是将F(5)的输出改为5.2,对于普通神经网络,它需要H(5)=5.2, 改变比例为(5.2-5.1)/5.1=2%,而对于残差网络,它只需要让F(5)=0.2, 改变比例为(0.2-0.1)/0.1=100%,说明残差网络对于输出的变化更敏感,对与权值的调整更明显,因此效果好。残差的思想是,去掉主体部分而突出微小的差别,差分放大器。详见

L1正则和L2正则的区别

L2对大数,outliers更加敏感,对于大数值的权重向量进行严厉惩罚,倾向于使权值以小数的形式比较均匀分散在参数空间中,使网络倾向使用所有的特征,而不是依赖那些重要的部分特征

L1正则没有L2对大数那么敏感,但是L1在优化过程中倾向于让权值更加稀疏,也就是大部分值非常接近于0,少部分重要特征对应的权值有值存在,因此网络依赖于稀疏的重要部分特征。但是L1正则在原点不可求导,需要特殊处理,一般情况下L2正则比L1要好

Max pooling反向传播过程的梯度

如果pooling的size为2*2,那么正向传播过程中,取最大的那个数如 a i j 作为最后池化的结果;反向传播过程中 a i j 梯度为1乘以上一层的传回的梯度(根据链式法则),其他位置的梯度为0

激活函数

Sigmoid:

  1. 梯度弥散:导数为 σ ( x ) ( 1 σ ( x ) ) ,当x落在正饱和区时, σ ( x ) 1 ,此时梯度值约等于0;当x落在负饱和区时, σ ( x ) 0 ,此时梯度也约等于0,也就是说只有当x值分布在0周围时,才有梯度回传,不然梯度弥散。在权值初始化时应该特别注意,如果初始化的权值比较大,那么大部分的神经元将会饱和,导致没有梯度回传。

  2. sigmoid函数输出不是零中心的,而是以0.5为中心的。我们一般比较喜欢零中心的输入数据,比如我们会对输入图像数据做减均值除方差工作,目的就是让输入保持均值为0的标准分布,但是现在经过了一层sigmoid函数后,下一层的输入全部都大于零了,导致下一层的权值在更新的梯度要不就是全小于0,要不就是全大于0,取决于传回的梯度正负,用mini-batch可以让抑制这个问题,因为现在每个样本梯度有正有负,相加可以抵消,实际上还是tanh比较好,它是一种放大的sigmoid函数,取值在-1到1之间

Relu:无论是正向传播还是反向传播,最大的优点就是计算简单,收敛速度快于sigmoid和tanh,但是缺点是会让神经元比较脆弱,一旦有个较大的负梯度让权值w更新到一个很小的负值,而偏移b不足与将wx+b的值加上0的话,这个神经元就会死掉,也就是说无论进来什么数据,输出为零,梯度也为零,无法更新。通常由学习率设置太大导致。

Leaky Relu: 为解决Relu死亡的问题,在x<0的时候给了一个很小的梯度值,函数如 f ( x ) = 1 ( x < 0 ) α x + 1 ( x > 0 ) x ,其中 α 为很小的常数

Maxout: Relu和Leaky Relu的一般形式 max ( w 1 x + b 1 , w 2 x + b 2 ) ,当 w 1 b 1 都为0时,就变成了Relu。具有Relu线性和不饱和优点,但是参数数量增加一倍

梯度下降优化方法

SGD:

# learning_rate 一般是要衰减的
x+=-learning_rate * dx

动量SGD:

# mu动量常数,0.5-0.99之间,开始设为0.5, 后期增加到0.99, 能够稳定在最优点的震荡
v=mu*v-learning_rate * dx
x+=v

Adagrad: 根据权值的模大小调整learning_rate

cache=dx**2 
x+=-learning_rate * dx / sqrt(cache+eps)

Rmsprop: 滑动平均版Adagrad

cache=decay_rate * cache + (1-decay_rate) * dx **2 
x+=-learning_rate * dx / sqrt(cache+eps)

Adam: 动量版SGD+Rmsprop

## beta1, beta2 = 0.99 
m=beta1 * m + (1-beta1) * dx 
v=beta2 * v + (1-beta2) * dx **2  
x+=-learning_rate * m / sqrt(v+eps)

猜你喜欢

转载自blog.csdn.net/ppp8300885/article/details/79824376