我尝试使用scipy.optimize.minimum
估算逻辑回归中的参数。在此之前,我写了对数似然函数和对数似然函数的梯度。然后我分别使用 Nelder-Mead 和 BFGS 算法。 原来后者失败但前者失败了。因为 BFGS 算法也使用渐变,我怀疑渐变部分(function log_likelihood_gradient(x, y)
)是否有错误。但是,由于我收到警告Desired error not necessarily achieved due to precision loss.
我正在使用加州大学洛杉矶分校的教程和数据集(见link),正确的估计是,
仅供参考,我还强烈建议您阅读此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
定义对数似然函数和的梯度。两者都来自如下公式,
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)
我知道我的帖子有点长,但我很乐意回答你提出的任何问题,有人可以帮忙吗?