一、逻辑回归(解释性强,易于实现)
1.逻辑回归简介——寻找最佳回归系数
**
2.推导过程——梯度上升法寻找最大的概率P
我们该如何寻找这个最佳回归系数呢,这也是我们接下来要讲的,这里我们先通过公式推导下来一步步理解如何寻求最佳回归系数。
我们知道,概率是属于[0,1]区间。但是线性模型:
值域是
为了将线性模型的值域限制在[0,1]我们需要找到一个模型的值域刚好在[0,1]区间,同时要足够好用。于是,选择了我们的sigmoid函数。
它的表达式为:
图像如下所示:
现在我们需要将线性模型与sigmoid结合起来,于是就变成了我们的逻辑回归模型:
假设我们已经训练好了一组权值 。只要把我们需要预测的 代入到上面的方程,输出的y值就是这个标签为A的概率,我们就能够判断输入数据是属于哪个类别。
我们的模型y的值等于标签为1的概率也就是p,
因为标签不是1就是0,因此标签为0的概率就是:
如果我们采集到了一组数据一共N个,
这个组合在一起的合事件发生的总概率怎么求呢?其实就是将每一个样本发生的概率相乘就可以了,即采集到这组样本的概率:
注意 是一个函数,并且未知的量只有 (在p里面),可以看下这个
对于这种连乘看起来不是很直观我们对两边直接取对数:
为了使某个样本最大概率的被正确分配到标签中,所以我们要最大化,那我们该如何最大化呢,这里我们需要引入最大似然估计(MLE)
所以,我们此时就问题就转化成了需要对求极大值了,接下来我们就需要求导了。
已知,那么
p是一个关于变量 的函数,我们对p求导,通过链式求导法则,慢慢展开可以得:
同理我们也可以相应的求出:
到了这一步我们可以对开始求偏导了
整理下公式:
这样我们通过求偏导找到了dw(dw等价于上面的),然后通过梯度上升的方法就可以找到最佳回归系数:w = w + lr * dw
对于这段代码的理解,其实就相当于我们公式推导的结果:
1.观察sigmoid公式得知只需求Z这个未知值
2.Z=W0X0+W1X1+W2X2+…+WnXn (Wi:最佳回归系数 Xi:特征值) :表示将两个对应数值相乘后求和得到Z
3.每个特征对应的最佳回归系数我们使用梯度上升的优化方法来求(梯度即函数单调方向,也是函数变化最快的方向)
4.梯度只是方向,而α是步长,两者相乘来求移动距离
5.最后使用梯度算法迭代公式,来不断更新W
6.其中的梯度也就是损失函数在此处的导数
我们通过迭代不断去更新w,然后求得一个最佳的回归系数。
import numpy as np
import matplotlib.pyplot as plt
# 读取文本数据,返回数据集和目标值
def loadDataSet():
dataMat = []
labelMat = []
fr = open('testSet.txt')
for line in fr.readlines():
lineArr = line.strip().split()
# 该数据集中,添加了一列并初始化为1,便于后续的计算,但是在其他数据集中,一般没有必要添加
dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
# 运算的核心函数Sigmoid
def sigmoid(inX):
return 1.0 / (1+np.exp(-inX))
# 核心函数alpha*gradient更新回归系数
def gradAscent(dataMatIn, classLabels):
# 为了便于计算,mat将两个列表数据转换为numpy的数组
dataMatrix = np.mat(dataMatIn)
labelMat = np.mat(classLabels).transpose() # transpose矩阵转置
m,n = np.shape(dataMatrix)
alpha = 0.001 # 设置步长
maxCycles = 500 # 设置循环次数
weights = np.ones((n,1)) # 初始化每个特征的回归系数为1
for k in range(maxCycles):
# 得到每一行的sigmoid值 (两个相乘得到z值)
h = sigmoid(dataMatrix*weights) # 矩阵相乘 sigmoid(sum(每个特征*每个系数)) 行*列,由于是矩阵相乘,所以在相乘时便求和了
# 用一直更新的回归系数求预测值,然后与真实值之间求误差,误差越来越小,则系数更新变化也越来越小,最后趋于稳定
error = (labelMat - h) # 每行分类与对应sigmoid相减 误差值越来越小了
# 数据集转置*误差 每条样本*该样本的误差值
weights = weights + alpha * dataMatrix.transpose() * error
return weights
dataArr,labelMat = loadDataSet()
weights = gradAscent(dataArr,labelMat)
print(weights)
# 梯度上升法本质是通过梯度联系自变量与因变量,使得自变量的变化能定向的改变因变量。
# 这里我们讨论error的大小与回归系数weights的关系,自变量事实上是weights,因变量是error,我们将自变量weights结合error的大小进行变化(error的作用与梯度类似)可以使得因变量error绝对值最小化;
# 例如,若error>0,则weights变大,由于error与weights成反比,所以error变小,即趋近于0,绝对值变小;若error<0,则weights变小,导致下次迭代后error变大,即error绝对值变小。
# ∴该迭代结果是使error的绝对值最小化。
# 【优化一】
# 改进:梯度上升算法在每次更新回归系数时都需要遍历整个数据集,该方法在处理100个左右的数据集时尚可,但是如果由数十亿样本和大量特征,那么该方法的计算复杂度就太高了。
# 一种改进方法是一次仅用一个样本点来更新回归系数,该方法成为随机梯度上升算法
# 用stoGradAscent0函数替代gradAscent函数
def stocGradAscent0(dataMatrix, classLabels):
dataMatrix = np.array(dataMatrix) #将列表转换格式
m,n = np.shape(dataMatrix)
alpha = 0.01
weights = np.ones(n)
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h
weights = weights + alpha * error * dataMatrix[i]
return weights
# 随机梯度上升算法与梯度上升算法很相似,区别在于:第一,后者的h和error都是向量,前者全是数值;第二,前者没有矩阵转换的过程,所有变量的数据类型都是Numpy数组。所以可以根据随机梯度上升的运算来理解系数的更新过程。
# 【优化二】
# 用stoGradAscent1函数替代gradAscent函数
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
dataMatrix = np.array(dataMatrix) #将列表转换格式
m,n = np.shape(dataMatrix)
weights = np.ones(n)
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4/(1.0+j+i)+0.0001 #变化的alpha
randIndex = int(np.random.uniform(0,len(dataIndex))) #随机样本下标
h = sigmoid(sum(dataMatrix[randIndex]*weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
del(dataIndex[randIndex]) #从整个数据中去除已经使用过的样本
return weights
# 第二次优化有两点:第一,alpha每次迭代都会调整,这会缓解数据波动或高频波动,此外alpha可能减小,但有一个常数项,所以该值会一直存在影响力;第二,通过随机取样来更新回归系数,减少周期性的波动。
3.推导过程——梯度下降法寻找最小的损失函数
损失函数:
最后可以通过梯度下降法,求出使损失函数最小的θ \thetaθ,求得的损失函数梯度如下:
4.书本中介绍
5.优缺点
优点
- 实现简单,广泛的应用于工业问题上;
- 分类时计算量非常小,速度很快,存储资源低;
- 便利的观测样本概率分数;
- 对逻辑回归而言,多重共线性并不是问题,它可以结合L2正则化来解决该问题;
-
缺点
当特征空间很大时,逻辑回归的性能不是很好;
- 容易欠拟合,一般准确度不太高
- 不能很好地处理大量多类特征或变量;
- 只能处理两分类问题(在此基础上衍生出来的softmax可以用于多分类),且必须线性可分;
- 对于非线性特征,需要进行转换;
二、决策树(适合制定规则)
1.决策树算法简介
python机器学习笔记:深入学习决策树算法原理 - 战争热诚 - 博客园
2.书中介绍
3.优缺点
优点
- 决策树易于理解和解释,可以可视化分析,容易提取出规则;
- 可以同时处理标称型和数值型数据;
- 比较适合处理有缺失属性的样本;
- 能够处理不相关的特征;
- 测试数据集时,运行速度比较快;
- 在相对短的时间内能够对大型数据源做出可行且效果良好的结果;
缺点
- 容易发生过拟合(随机森林可以很大程度上减少过拟合);
- 容易忽略数据集中属性的相互关联;
- 对于那些各类别样本数量不一致的数据,在决策树中,进行属性划分时,不同的判定准则会带来不同的属性选择倾向;信息增益准则对可取数目较多的属性有所偏好(典型代表ID3算法),而增益率准则(CART)则对可取数目较少的属性有所偏好,但CART进行属性划分时候不再简单地直接利用增益率尽心划分,而是采用一种启发式规则)(只要是使用了信息增益,都有这个缺点,如RF);
- ID3算法计算信息增益时结果偏向数值比较多的特征;
三、随机森林(不用处理变量,泛化能力强)
1.随机森林简介
机器学习中有一种大类叫集成学习(Ensemble Learning),集成学习的基本思想就是将多个分类器组合,从而实现一个预测效果更好的集成分类器。集成算法可以说从一方面验证了中国的一句老话:三个臭皮匠,赛过诸葛亮。集成算法大致可以分为:Bagging,Boosting 和 Stacking 三大类型。
随机森林既可以胜任分类任务又可以胜任回归任务。
机器学习中有两种任务,回归和分类,而随机森林可以同时胜任这两种任务。其中分类任务是对离散值进行预测(比如将一景图像中的植被,建筑,水体等地物类型分类);回归任务是对连续值进行预测(比如根据已有的数据预测明天的气温是多少度,预测明天某基金的价格)。
随机森林是属于集成学习,其核心思想就是集成多个弱分类器以达到三个臭皮匠赛过诸葛亮的效果。随机森林采用Bagging的思想,所谓的Bagging就是:
(1)每次有放回地从训练集中取出 n 个训练样本,组成新的训练集;
(2)利用新的训练集,训练得到M个子模型;
(3)对于分类问题,采用投票的方法,得票最多子模型的分类类别为最终的类别;对于回归问题,采用简单的平均方法得到预测值。
随机森林以决策树为基本单元,通过集成大量的决策树,就构成了随机森林。其构造过程如下:
(1)构建单棵决策树。
随机森林是多棵决策树的集成。
众多决策树构成了随机森林,每棵决策树都会有一个投票结果,最终投票结果最多的类别,就是最终的模型预测结果。
2.书本介绍
3.优缺点
优点
- 表现性能好,与其他算法相比有着很大优势。
- 随机森林能处理很高维度的数据(也就是很多特征的数据),并且不用做特征选择。
- 在训练完之后,随机森林能给出哪些特征比较重要。
- 训练速度快,容易做成并行化方法(训练时,树与树之间是相互独立的)。
- 在训练过程中,能够检测到feature之间的影响。
- 对于不平衡数据集来说,随机森林可以平衡误差。当存在分类不平衡的情况时,随机森林能提供平衡数据集误差的有效方法。
- 如果有很大一部分的特征遗失,用RF算法仍然可以维持准确度。
- 随机森林算法有很强的抗干扰能力(具体体现在6,7点)。所以当数据存在大量的数据缺失,用RF也是不错的。
- 随机森林抗过拟合能力比较强(虽然理论上说随机森林不会产生过拟合现象,但是在现实中噪声是不能忽略的,增加树虽然能够减小过拟合,但没有办法完全消除过拟合,无论怎么增加树都不行,再说树的数目也不可能无限增加的。)
- 随机森林能够解决分类与回归两种类型的问题,并在这两方面都有相当好的估计表现。(虽然RF能做回归问题,但通常都用RF来解决分类问题)。
- 在创建随机森林时候,对generlization error(泛化误差)使用的是无偏估计模型,泛化能力强。
- 随机森林在解决回归问题时,并没有像它在分类中表现的那么好,这是因为它并不能给出一个连续的输出。当进行回归时,随机森林不能够做出超越训练集数据范围的预测,这可能导致在某些特定噪声的数据进行建模时出现过度拟合。(PS:随机森林已经被证明在某些噪音较大的分类或者回归问题上回过拟合)。
- 对于许多统计建模者来说,随机森林给人的感觉就像一个黑盒子,你无法控制模型内部的运行。只能在不同的参数和随机种子之间进行尝试。
- 可能有很多相似的决策树,掩盖了真实的结果。
- 对于小数据或者低维数据(特征较少的数据),可能不能产生很好的分类。(处理高维数据,处理特征遗失数据,处理不平衡数据是随机森林的长处)。
- 执行数据虽然比boosting等快(随机森林属于bagging),但比单只决策树慢多了。