机器学习实战【4】(逻辑回归)

来源:互联网 发布:熊片数据库kfb 编辑:程序博客网 时间:2024/05/16 14:14

本博客记录《机器学习实战》(MachineLearningInAction)的学习过程,包括算法介绍和python实现。

逻辑回归

对于一个数据集中的样本,将其每个特征乘上一个对应的系数,然后输入sigmoid函数中把结果映射到0-1区间内,用这个结果作为分类依据,这种方式称为逻辑回归。

sigmoid函数

sigmoid函数公式及图像如下:

σ(z)=11+ez

sigmoid函数图像

可以看出在x为0时,函数值为0.5,x>0时逐渐趋向1,x<0时逐渐趋向0。这个性质使得sigmoid函数可以把实数域内的数据映射到0-1范围内,从而完成分类的任务。

回归参数确定

逻辑回归中最重要的一部就是参数的确定,如何选择最优的参数使得模型分类时能够达到更高的准确率。这里用到的寻找最优参数的方法是一种最优化方法——梯度上升法。

在二分类问题中,把样本数据的每个特征乘以回归系数θ 并求和,将结果输入到sigmoid函数中,把得到的结果作为分到1类的概率。这样,结果大于0.5的样本就分到1类,小于0.5的样本就分到0类。构造预测函数如下:

hθ(x)=g(θTx)=11+eθTx

这个hθ(x) 就代表了样本分到1类的概率,θTx 代表参数与输入样本的特征向量x的加权和,于是有:

p(y=1|x;θ)=hθ(x)

p(y=0|x;θ)=1hθ(x)

综合起来写就是对于样本x,在参数为θ 时,分到y类的概率为:

p(y|x;θ)=hθ(x)y(1hθ(x))1y

假设输入的样本特征为x1...xn,对应的分类结果为y1...yn,那么最优的参数应该使L(θ) 最大:

L(θ)=i=1np(yi|xi;θ)=i=1nhθ(xi)yi(1hθ(xi))1yi

这里用到了最大似然法,引用百度百科的定义:

最大似然法(Maximum Likelihood,ML)也称为最大概似估计,也叫极大似然估计,是一种具有理论性的点估计法,此方法的基本思想是:当从模型总体随机抽取n组样本观测值后,最合理的参数估计量应该使得从模型中抽取该n组样本观测值的概率最大

L(θ) 表示模型分类结果与n个样本数据都符合的概率,称为似然函数,根据最大似然法,我们以L(θ) 的值最大作为标准确定模型参数θ 。为了找到函数的最大值,采用的方法就是梯度上升法。

所谓梯度就是指函数值在任意点递增最快的方向,用 表示。梯度上升法是一种参数更新的方法,初始时给参数θ 赋初值,计算L(θ) 在参数点的梯度,把梯度乘以步长后加到参数上来更新参数,这样参数的每次更新都会朝着使得L(θ) 增加最快的方向进行,参数更新公式如下:

θ=θ+αL(θ)

对于每一个参数:

θj=θj+αθjL(θ)

为了便于计算,将L(θ) 取对数,即改为求l(θ)=logL(θ) 的最大值:

θjl(θ)=θilog(i=1nhθ(xi)yi(1hθ(xi))1yi)=θji=1nyilog(hθ(xi))+(1yi)log((1hθ(xi)))=i=1n(yihθ(xi)1yi1hθ(xi))θjhθ(xi)=i=1n(yihθ(xi)1yi1hθ(xi))(hθ(xi)(1hθ(xi))xji=i=1n(yi(1hθ(xi))(1yi)hθ(xi))xji=i=1n(yihθ(xi))xji

结果中的xji 表示第i个样本的第j个特征,这样就得出了更新参数的方法,更新第j个参数时,遍历每个样本计算出类标签yi 与当前模型的分类结果hθ(xi) 之差,即分类误差,乘以该样本中的第j个特征值,最后求和,再乘以步长,就得到参数更新量。

当然,在python中通过矩阵运算可以使这个运算过程看上去简单地多,通过矩阵乘法就能够优雅地计算加权和。需要注意的是,在特征与参数一一对应的情况下,我们还需要增加一个参数作为常数项,这时候,通常的做法是在数据集上增加一个值为1的特征,这个特征与常数项参数对应,以方便进行矩阵运算,代码如下:

# 梯度上升算法def gradAscent(dataMat, classLabels):    # 把输入数据转换为矩阵类型    dataMatrix = mat(dataMat)    labelMatrix = mat(classLabels).transpose()    m, n = shape(dataMatrix)    # 步长    alpha = 0.001    # 迭代次数    maxCycles = 500    # 参数矩阵    weights = ones((n, 1))    for k in range(maxCycles):        # 计算实际分类结果        h = sigmoid(dataMatrix * weights)        # 计算误差        error = (labelMatrix - h)        # 更新参数        weights = weights + alpha * dataMatrix.transpose() * error    return weights

画出决策边界

在具有两个特征的一组数据集中,通过梯度上升方法计算出分类边界,通过python中的matplotlib画出边界:

可以看出分类的效果还是比较理想的。

随机梯度上升算法

上述梯度算法的缺点显而易见,在每次迭代更新参数时,都要遍历整个数据集,在数据集很大时,这个时间开销是无法接受的。一种改进的算法——随机梯度上升法,可以在不失太多精度的情况下极大地减小计算量。

在梯度上升法中,每次迭代都遍历整个数据集来更新参数,这使得在每次迭代中参数都朝着全局最优的方向更新。随机梯度上升算法则是每次迭代时只选取一个样本进行参数的更新,可以想象成梯度上升法在样本集只有一个样本情况下的特例,这时候每一次的更新会朝着使得这个样本的正确率增加最快的方向,即对于某个样本的局部最优方向进行。即使这样,在经过多次迭代之后也能够达到跟梯度上升法相近的准确率,但是计算量却大大降低。

另外一点可以优化的是步长的大小,大的步长使得参数能够更快的达到最优值,却可能在最优值附近不断徘徊;小的步长能够更精确地达到最优值,却使得参数更新的更慢。这时候可以取这两者的长处,使用动态步长的方法:在初始时给定较大的步长,在迭代的过程中,随着参数不断趋于稳定,逐渐减小步长。这种方法使得开始时参数能够较快地接近最优值,同时又能够增加参数更新的精确度。下面给出优化的随机梯度上升法的python代码:

# 随机梯度上升法def stocGradAscent1(dataMatrix, classLabel, numIter=150):    m, n = shape(dataMatrix)    weights = ones(n)    for j in range(numIter):        dataIndex = list(range(m))        for i in range(m):            alpha = 4 / (1.0 + j + i) + 0.01            # 随机选取样本            randIndex = int(random.uniform(0, len(dataIndex)))            h = sigmoid(sum(dataMatrix[dataIndex[randIndex]] * weights))            error = classLabel[dataIndex[randIndex]] - h            weights += alpha * error * dataMatrix[dataIndex[randIndex]]            # 删除使用过的样本            del(dataIndex[randIndex])    return weights

最后,有了最佳参数的模型,就可以用来分类了:

# 分类函数def classifyVec(inX, weights):    prob = sigmoid(sum(inX * weights))    if prob > 0.5:        return 1    else:        return 0

总结

逻辑回归是在线性回归的基础上增加了一个非线性函数sigmoid,并通过最优化方法(常用的是梯度上升算法)来得到最佳拟合参数。而随机梯度上升算法则是梯度上升的一种优化,减小了时间复杂度。

在计算参数更新方法时,似然函数的选择使用了最大似然法,使得从模型中抽取出样本集的概率最大。对似然函数求取每个参数方向上的梯度,并经过一些数学推导得到了参数更新的方法。

多数情况下,逻辑回归可以用来估计事件的概率,例如某广告被点击的概率,某个人患某种疾病的概率等。

原创粉丝点击