美文网首页
逻辑回归

逻辑回归

作者: 鲸鱼酱375 | 来源:发表于2019-06-19 02:26 被阅读0次

    理论知识

    Logistic回归算法基于Sigmoid函数,或者说Sigmoid就是逻辑回归函数。

    为什么是sigmoid函数:

    在logistic regression (LR)中,这个目标是什么呢?最大化条件似然度。考虑一个二值分类问题,训练数据是一堆(特征,标记)组合,(x1,y1), (x2,y2), .... 其中x是特征向量,y是类标记(y=1表示正类,y=0表示反类)。LR首先定义一个条件概率p(y|x;w)。 p(y|x;w)表示给定特征x,类标记y的概率分布,其中w是LR的模型参数(一个超平面)。有了这个条件概率,就可以在训练数据上定义一个似然函数,然后通过最大似然来学习w。这是LR模型的基本原理。

    对于大多数(或者说所有)线性分类器,response value(响应值) <w,x> (w和x的内积) 代表了数据x属于正类(y=1)的confidence (置信度)。<w,x>越大,这个数据属于正类的可能性越大;<w,x>越小,属于反类的可能性越大。<w,x>在整个实数范围内取值。现在我们需要用一个函数把<w,x>从实数空间映射到条件概率p(y=1|x,w),并且希望<w,x>越大,p(y=1|x,w)越大;<w,x>越小,p(y=1|x,w)越小(等同于p(y=0|x,w)越大),而sigmoid函数恰好能实现这一功能(参见sigmoid的函数形状):首先,它的值域是(0,1),满足概率的要求;其次,它是一个单调上升函数。最终,p(y=1|x,w)=sigmoid (<w,x>). 综上,LR通过最大化类标记的条件似然度来学习一个线性分类器。为了定义这个条件概率,使用sigmoid 函数将线性分类器的响应值<w,x>映射到一个概率上。sigmoid的值域为(0,1),满足概率的要求;而且是一个单调上升函数,可将较大的<w,x>映射到较大的概率p(y=1|x,w)。sigmoid的这些良好性质恰好能满足LR的需求。

    说到底源于sigmoid,或者说exponential family所具有的最佳性质,即maximum entropy的性质。虽然不清楚历史上孰先孰后,但这并不妨碍maximum entropy给了logistic regression一个很好的数学解释。为什么maximum entropy好呢?entropy翻译过来就是熵,所以maximum entropy也就是最大熵。熵原本是information theory中的概念,用在概率分布上可以表示这个分布中所包含的不确定度,熵越大不确定度越大。所以大家可以想象到,均匀分布熵最大,因为基本新数据是任何值的概率都均等。而我们现在关心的是,给定某些假设之后,熵最大的分布。也就是说这个分布应该在满足我假设的前提下越均匀越好。比如大家熟知的正态分布,正是假设已知mean和variance后熵最大的分布。回过来看logistic regression,这里假设了什么呢?首先,我们在建模预测 Y|X,并认为 Y|X 服从bernoulli distribution,所以我们只需要知道 P(Y|X);其次我们需要一个线性模型,所以 P(Y|X) = f(wx)。接下来我们就只需要知道 f 是什么就行了。而我们可以通过最大熵原则推出的这个 f,就是sigmoid。其实前面也有人剧透了bernoulli的exponential family形式,也即是 1/ (1 + e^-z)

    ps:由于指数家族和广义线性模型公式推出来的就是sigmoid函数

    最大嫡原理

    image.png

    广义线性模型

    image.png
    image.png

    逻辑回归原理

    其中涉及的数学原理和步骤如下:
    (1)需要一个合适的分类函数来实现分类【单位阶跃函数、Sigmoid函数】
    (2)损失函数(Cost函数)来表示预测值(h(x)h(x))与实际值(yy)的偏差(h−yh−y),要使得回归最佳拟合,那么偏差要尽可能小(偏差求和或取均值)。
    (3)记J(ω)J(ω)表示回归系数为ωω时的偏差,那么求最佳回归参数ωω就转换成了求J(ω)J(ω)的最小值。【梯度下降法】
    所以,接下来就围绕这几个步骤进行展开。

    损失函数

    image.png
    image.png

    梯度上升法

    推导公式

    python实现#

    很好的推导实现

    import numpy as np
    import matplotlib.pyplot as plt
    import pandas as pd
    
    
    def load_data(path, header):
        marks_df = pd.read_csv(path, header=header)
        return marks_df
    
    
    if __name__ == "__main__":
        # load the data from the file
        data = load_data("data/marks.txt", None)
    
        # X = feature values, all the columns except the last column
        X = data.iloc[:, :-1]
    
        # y = target values, last column of the data frame
        y = data.iloc[:, -1]
    
        # filter out the applicants that got admitted
        admitted = data.loc[y == 1]
    
        # filter out the applicants that din't get admission
        not_admitted = data.loc[y == 0]
    
        # plots
        plt.scatter(admitted.iloc[:, 0], admitted.iloc[:, 1], s=10, label='Admitted')
        plt.scatter(not_admitted.iloc[:, 0], not_admitted.iloc[:, 1], s=10, label='Not Admitted')
        plt.legend()
        plt.show()
    
    X = np.c_[np.ones((X.shape[0], 1)), X]
    y = y[:, np.newaxis]
    theta = np.zeros((X.shape[1], 1))
    
    def sigmoid(x):
        # Activation function used to map any real value between 0 and 1
        return 1 / (1 + np.exp(-x))
    
    def net_input(theta, x):
        # Computes the weighted sum of inputs
        return np.dot(x, theta)
    
    def probability(theta, x):
        # Returns the probability after passing through sigmoid
        return sigmoid(net_input(theta, x))
    def cost_function(self, theta, x, y):
        # Computes the cost function for all the training samples
        m = x.shape[0]
        total_cost = -(1 / m) * np.sum(
            y * np.log(probability(theta, x)) + (1 - y) * np.log(
                1 - probability(theta, x)))
        return total_cost
    
    def gradient(self, theta, x, y):
        # Computes the gradient of the cost function at the point theta
        m = x.shape[0]
        return (1 / m) * np.dot(x.T, sigmoid(net_input(theta,   x)) - y)
    def fit(self, x, y, theta):
        opt_weights = fmin_tnc(func=cost_function, x0=theta,
                      fprime=gradient,args=(x, y.flatten()))
        return opt_weights[0]
    parameters = fit(X, y, theta)
    x_values = [np.min(X[:, 1] - 5), np.max(X[:, 2] + 5)]
    y_values = - (parameters[0] + np.dot(parameters[1], x_values)) / parameters[2]
    
    plt.plot(x_values, y_values, label='Decision Boundary')
    plt.xlabel('Marks in 1st Exam')
    plt.ylabel('Marks in 2nd Exam')
    plt.legend()
    plt.show()
    def predict(self, x):
        theta = parameters[:, np.newaxis]
        return probability(theta, x)
    def accuracy(self, x, actual_classes, probab_threshold=0.5):
        predicted_classes = (predict(x) >= 
                             probab_threshold).astype(int)
        predicted_classes = predicted_classes.flatten()
        accuracy = np.mean(predicted_classes == actual_classes)
        return accuracy * 100
    accuracy(X, y.flatten())
    

    算法优化#

    把梯度下降改成随机梯度下降等,暂时pass,如果后面遇到再补习

    优缺点

    优点:

    1、实现简单;

    2、分类时计算量非常小,速度很快,存储资源低;

    缺点:

    1、容易欠拟合,一般准确度不太高

    2、只能处理两分类问题(在此基础上衍生出来的softmax可以用于多分类),且必须线性可分;

    reference:
    https://zhuanlan.zhihu.com/p/24967776
    https://www.zhihu.com/question/35322351
    https://blog.csdn.net/lc013/article/details/55002463
    https://blog.csdn.net/moxigandashu/article/details/72779856
    https://towardsdatascience.com/building-a-logistic-regression-in-python-301d27367c24

    相关文章

      网友评论

          本文标题:逻辑回归

          本文链接:https://www.haomeiwen.com/subject/lodcqctx.html