【统计学习方法】 逻辑斯谛回归(Logistic Regression) Python实现

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/tudaodiaozhale/article/details/77532135

前言

代码可在Github上下载:代码下载
今天看了一下《统计学习方法》里的逻辑斯谛回归,结合下《机器学习实战》里面的代码,很精炼。公式如下:
模型:

P ( Y = 1 x ) = e x p ( w x + b ) 1 + e x p ( w x + b ) P(Y=1|x)=\frac {exp(w\cdot x+b)}{1+exp(w\cdot x+b)}
P ( Y = 0 x ) = 1 P ( Y = 1 x ) = 1 1 + e x p ( w x + b ) P(Y=0|x)=1-P(Y=1|x)=\frac {1}{1+exp(w\cdot x+b)}

策略:对数损失函数
算法:梯度下降算法

算法理论

假设 P ( Y = 1 x ) = π ( x ) , P ( Y = 0 x ) = 1 π ( x ) P(Y = 1|x){\rm{ = }}\pi \left( x \right),P(Y = 0|x){\rm{ = 1 - }}\pi \left( x \right) ,那么则服从的是贝努利分布,结合贝努利分布的概率密度函数 [ π ( x i ) ] y i [ 1 π ( x i ) ] y i {\left[ {\pi \left( {{x_i}} \right)} \right]^{{y_i}}}{\left[ {1 - \pi \left( {{x_i}} \right)} \right]^{{y_i}}} ,进而得到似然函数 i = 1 N [ π ( x i ) ] y i [ 1 π ( x i ) ] y i \prod\limits_{i = 1}^N {{{\left[ {\pi \left( {{x_i}} \right)} \right]}^{{y_i}}}{{\left[ {1 - \pi \left( {{x_i}} \right)} \right]}^{{y_i}}}} ,为了减少计算量,再进一步得到替代品对数似然函数 L ( w ) = i = 1 N [ y i log π ( x i ) + ( 1 y i ) log ( 1 π ( x i ) ) ] L\left( w \right) = \sum\limits_{i = 1}^N {\left[ {{y_i}\log \pi \left( {{x_i}} \right) + \left( {1 - {y_i}} \right)\log \left( {1 - \pi \left( {{x_i}} \right)} \right)} \right]} ,便是逻辑斯蒂回归的损失函数了。

算法实现

首先需要加载数据,加载数据的函数。

def loadDataSet(self, fileName = 'testSet.txt'):   #加载数据
        dataMat = []
        labelMat = []
        fr = open(fileName)
        for line in fr.readlines(): #遍历文件
            lineArr = line.strip().split()
            dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) #数据集
            labelMat.append(int(lineArr[-1]))   #类别标签
        return dataMat, labelMat

其中dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])这句代码使将输入向量做了一个扩充,将1放在输入向量的末尾,变成 x = ( 1 , x ( 1 ) , x ( 2 ) , x ( 3 )   , x ( n ) ) x = ({\rm{1,}}{x^{(1)}},{x^{(2)}},{x^{(3)}} \cdots ,{x^{(n)}}) ,然后将权值向量写成 w = ( b , w ( 1 ) , w ( 2 ) , w ( 3 )   , w ( n ) ) w = (b,{w^{(1)}},{w^{(2)}},{w^{(3)}} \cdots ,{w^{(n)}}) ,这样可以方便计算。
接下来看sigmoid函数,它的值域是[0, 1]。对应的就是刚才上面的第一个公式。如果写成扩充向量的形式的话,就是 P ( Y = 1 x ) = e x p ( w x ) 1 + e x p ( w x ) P(Y=1|x)=\frac {exp(w\cdot x)}{1+exp(w\cdot x)} 这个公式了(要同除以 e x p ( w x ) exp(w\cdot x) )。

def sigmoid(self, inX):
        return np.exp(inX) / (1 + np.exp(inX))

最后就是我们的训练的函数了。

def train(self, dataSet, labels):   #训练
        dataMat = np.mat(dataSet)   #将数据集转成矩阵的形式
        labelMat = np.mat(labels).transpose()#将类别集合转成矩阵的形式
        m, n = np.shape(dataSet)    #行列
        alpha = 0.01
        maxIter = 500
        weights = np.ones((n, 1))
        for i in range(maxIter):    #迭代
            h = self.sigmoid(dataMat * weights)
            error = h - labelMat    #预测值和标签值所形成的误差
            weights = weights -  alpha * dataMat.transpose() * error    #权重的更新
        return weights

这里使用了梯度下降算法来进行训练,根据以下公式。
w L ( w ) = X T ( h y ) {\nabla _w}L\left( w \right) = {{\bf{X}}^T}\left( {{\bf{h - y}}} \right)
对应下面的代码。

error = h - labelMat    #预测值和标签值所形成的误差
weights = weights -  alpha * dataMat.transpose() * error    #权重的更新

最后我们运行一下。

    logistic = Logistic()
    dataSet, labels = logistic.loadDataSet()
    weights = logistic.gradDescent(dataSet, labels)
    print weights

完整代码和数据可以在逻辑斯蒂回归代码下载。
如果您觉得好用的话,麻烦点个赞。

猜你喜欢

转载自blog.csdn.net/tudaodiaozhale/article/details/77532135
今日推荐