机器学习机器学习

逻辑回归与CS229 newton methed

2019-02-25  本文已影响34人  Vophan

CS229 Newton's Method

这节课的重点:

  • 逻辑回归
  • 牛顿方法
  • 指数分布族
  • 广义线性模型

逻辑回归

首先,逻辑回归是一个二分类的模型。

之所以叫做回归,我认为是这样的:

它和线性回归都是广义线性模型,只不过是线性回归没有Sigmoid函数

那么Sigmoid函数是什么呢?

在所有的逻辑回归的教程中,他们都会提到逻辑回归的假设函数是Sigmoid,但是谁能解释一下为什么用Sigmoid呢?那么多函数,为什么偏偏是他呢?

我们来慢慢解释:

  1. 首先,我们来看sigmoid函数是一个值域在0-1之间的S型的函数,这样也就代表了他的特殊性,也就是说,他可以将特征映射为一个事件发生的概率。但是,有那么多0-1之间的函数,所以这并不是他真正的解释。

    img
  2. 在吴恩达教授的CS229的lecture4中提到了指数分布族和广义线性模型,真正的解释了为什么逻辑回归的假设函数是Sigmoid,而线性回归的假设函数是最小二乘模型?


    首先,我们先说一下什么是指数分布族:

    指数分布族

    指数分布族就是指可以表示为指数函数形式的概率分布,形式如下:
    P(y;\eta) = b(y)exp(\eta^TT(y)-\alpha(\eta))
    其中:

    • \eta是分布的自然参数
    • T(y)是充分统计量,通常T(y) = y

    当参数a、b、T都固定时,就固定了一个以\eta​为参数的分布族

    比如说:

    伯努利分布,多项式分布,高斯分布,伽马分布都是指数分布族的。

    下面我们以伯努利分布为例子来解释一下:为什么他是指数分布族

    首先我们知道伯努利分布的概率函数是:
    p(x;\phi) = \phi^x*(1-\phi)^{1-x} \\ = exp(xlog\phi + (1-x)log(1-\phi)) \\ =exp(xlog(\frac{\phi}{1-\phi}) + log(1-\phi))

所以我们就证明了,伯努利分布是属于指数分布族的。

而且:
\eta^T = log(\frac{\phi}{1-\phi})\\ \phi = \frac{1}{1+e^{-\eta}}\\ T(x) = x\\ a(\eta) = -log(1-\phi) = log(1 + e^\eta)\\ b(y) = 1
然后,我们展示一下,如何用指数分布族构成广义线性模型:

广义线性模型就是通过是三个假设将指数分布族转换成对应的机器学习模型

1、首先很多我们平常接触的概率分布都可以被表示成为指数形式,也就是很多概率分布属于指数分布族。在指数分布族格式中,一组确定的BAT三个参数(b,a,T),对应一个概率分布
2、广义线性模型的三个假设:(5个参数)

  • y|x,θ属于某个概率分布:给定x的前提下,y属于谁(确定三个参数)
  • h = E[t(y)|x] 目标函数(也就是假设函数)是充分统计量的期望(因变量的条件期望
  • η = θX 因为线性模型,自然参数=参数和x的线性组合(自变量的线性组合)

构建一个广义线性模型,其实就是求取假设函数h,所以:
h = E(T(y)|x) \\ = E(y|x)\\ = \phi \\ = \frac{1}{1+e^{-\eta}} \\ = \frac{1}{1+e^{-\theta^Tx}}
这样,我们就得到了我们的Logistic function。

牛顿方法

首先,我们先来看一下,对于逻辑回归,我们最一般的解法:

根据极大似然估计,我们可以得到逻辑回归的损失函数:
L(\theta) = \prod_{i=0}^{n}h(\theta)^{x_i}*(1-h(\theta))^{1-x_i} \\ NLL\\ Loss=\frac{1}{m}\sum_{i=0}^{n}x_ilogh(\theta) + (1-x_i)log(1-h(\theta))
然后,我们用梯度上升法:
\theta = \theta - \alpha\bigtriangledown_\theta L(\theta)
求出最终的\theta

但是,我们现在可以用牛顿方法来求合理规模数据(不是特别大)的逻辑回归的\theta

其实,牛顿方法在我们高中的时候就学过了,只不过当时他出现在微积分后面的拓展阅读,当时我记得他算过题,却没想到在这里又一次相遇。

我们来看一下什么是牛顿方法呢?

一般的,我们有一个函数g(x),而我们要求取g(x) = 0这个方程:

newton methed

如图:

  1. 首先确定一个x_0,然后令x=x_0,求出该点的切线和x轴的交点x_1
  2. x=x_1,重复这个过程,直到g(x) = 0

然后,我们来描述一下这个算法:

  1. x=0
  2. x = x-\frac{g(x)}{g'(x)} until g(x) = 0

这是x为1维的情况,如果x为多维,就用到牛顿-拉普森方法:
\theta:=\theta - H_-1\bigtriangledown_\theta l(\theta)
这个式子与前面不同就是那个H,H叫做Hessian矩阵,是一个nxn的矩阵,他的定义为:

hessian matrix

为什么是这个定义呢?

这就涉及到了牛顿法的本质:

实际上,牛顿法就是函数f在x处利用泰勒公式展开,得到他的近似函数,进而求解最小值。


这样我们就看出来,hessian矩阵是怎么求出来的了:

求取泰勒展开的二阶近似函数的最小值点,所以令他导数为零,最后求得牛顿-拉普森方法的公式。

为什么说是合理规模的数据呢?

我们可以看一下我们的每一次迭代,都要计算黑塞矩阵,如果特征维度高的话,这将带来极大的时间损耗。

而且,Hessian 矩阵非正定(非凸)导致无法收敛;

那么,为什么数据量小的时候,他的速度快呢?

用术语说,牛顿法的收敛速度叫做二次收敛,也就是说,每一次迭代都可以让误差值变成原来的二次方:

比如:

  1. error:0.001
  2. error:0.000001

代码待续:

# ********************
#   waiting for me
# ********************

import numpy as np
from sklearn.datasets import make_classification
from matplotlib import pyplot as plt

class Logistic_Regression:
    """
    the class to implement the Logistic Regreesion
    """

    def __init__(self, features, nums, classes):
        self.features = features
        self.nums = nums
        self.classes = classes
        self.alpha = 0.3
        self.max_epoch = 50
        self.data = self.make_data()
        self.theta = self.train()

    def make_data(self):
        """
        this is the function to make the training data
        :param features: the dimension of data features
        :param nums: the number of data
        :return:data
        """
        _dataset = make_classification(n_samples=self.nums, n_features=self.features, n_classes=self.classes)
        return _dataset

    def sigmoid(self, x):
        """
        this is the function to implement the sigmoid function
        :param x:this is (theta * x)
        :return:result: probility
        """
        result = 1/(1+np.exp(-x))
        return result

    def train(self, newton_mothod=False):
        if newton_mothod:
            pass
        else:
            theta = np.ones((self.features, 1))
            for i in range(self.max_epoch):
                grident = (1/self.nums)*np.dot(self.data[0].T, (self.sigmoid(np.dot(self.data[0], theta)) - self.data[1].reshape((20, 1))))
                theta = theta + self.alpha * grident
            return theta

    def test(self, data):
        return np.round(self.sigmoid(np.dot(self.theta.T, data.T)))

上一篇下一篇

猜你喜欢

热点阅读