使用BFGS优化算法估算逻辑回归

时间:2016-09-09 23:34:08

标签: python optimization scipy logistic-regression numerical-analysis

我尝试使用scipy.optimize.minimum估算逻辑回归中的参数。在此之前,我写了对数似然函数和对数似然函数的梯度。然后我分别使用 Nelder-Mead BFGS 算法。 原来后者失败但前者失败了。因为 BFGS 算法也使用渐变,我怀疑渐变部分(function log_likelihood_gradient(x, y))是否有错误。但是,由于我收到警告Desired error not necessarily achieved due to precision loss.

,这也可能是由于与 Nelder-Mead 相关的任何数字问题所致

我正在使用加州大学洛杉矶分校的教程和数据集(见link),正确的估计是,

enter image description here

仅供参考,我还强烈建议您阅读此post以了解数据集的问题设置和预处理。

现在是我的代码,第一部分是数据准备。你可以简单地运行它来获得一份副本,

import numpy as np
from scipy.optimize import minimize
from patsy import dmatrices

from urllib.request import urlretrieve
url = 'http://www.ats.ucla.edu/stat/data/binary.csv'
urlretrieve(url, './admit_rate.csv')
data = pd.read_csv('./admit_rate.csv')

y, x = dmatrices('admit ~ gre + gpa + C(rank)', data, return_type = 'dataframe')
y = np.array(y, dtype=np.float64)
x = np.array(x, dtype=np.float64)

第二部分是MLE部分,log_likelihood定义对数似然函数的总和,log_likelihood_gradient定义对数似然函数和的梯度。两者都来自如下公式, enter image description here

def sigmoid(x):
    """
    Logistic function
    """
    return 1.0 / (1 + np.exp(-x))

def sigmoid_derivative(x):
    """
    Logistic function's first derivative
    """
    return sigmoid(x) * (1 - sigmoid(x))

def log_likelihood(x, y):
    """
    The sum of log likelihood functions
    """
    n1, n2 = x.shape
    def log_likelihood_p(p):
        """
        p: betas/parameters in logistic regression, to be estimated
        """
        p = p.reshape(n2, 1)
        sig = sigmoid(np.dot(x, p)).reshape(n1, 1)
        return np.sum(y * np.log(sig) + (1 - y) * np.log(1 - sig)) 
    return log_likelihood_p

def log_likelihood_gradient(x, y):
    """
    The gradient of the sum of log likelihood functions used in optimization
    """
    n1, n2 = x.shape
    def log_likelihood_gradient_p(p):
        """
        p: betas/parameters in logistic regression, to be estimated
        """
        p = p.reshape(n2, 1)
        xp = np.dot(x, p)
        sig = sigmoid(xp)
        sig_der = sigmoid_derivative(xp)
        return np.sum(y * sig_der / sig * x - (1 - y) * sig_der / (1 - sig) * x, axis=0)
    return log_likelihood_gradient_p

def negate(f):  
    return lambda *args, **kwargs: -f(*args, **kwargs)

第三部分是优化部分,我从初始值开始

x0 = np.array([ - 1,-0.5,-1,-1.5,0,1])

对于 Nelder-Mead ,它可以正常工作并输出

数组([-3.99005691e + 00,-6.75402757e-01,-1.34021420e + 00,-1.55145450e + 00,2.26447746e-03,8.04046227e-01]

但是当我尝试 Nelder-Mead 算法时,它失败了

x0 = np.array([ - 1,-0.5,-1,-1.5,0,1])

即使我像 Nelder-Mead 算法的输出那样给出了更接近的初始值,它也会失败并显示警告Desired error not necessarily achieved due to precision loss

内尔德-米德

x0 = np.array([-1, -0.5, -1, -1.5, 0, 1])
estimator1 = minimize(negate(log_likelihood(x, y)), x0, 
               method='nelder-mead', options={'disp': True})
print(estimator1.success)
estimator1.x

BFGS

x0 = np.array([ -3.99005691e+00,  -6.75402757e-01,  -1.34021420e+00,
        -1.55145450e+00,   2.26447746e-03,   8.04046227e-01])
estimator2 = minimize(negate(log_likelihood(x, y)), x0, method='BFGS', 
                     jac=log_likelihood_gradient(x, y), options={'disp': True})
print(estimator2.success)

我知道我的帖子有点长,但我很乐意回答你提出的任何问题,有人可以帮忙吗?

0 个答案:

没有答案