逻辑回归模型所做的假设是:
相应的决策函数为: y=1,if P(y=1|x)>0.5
(实际应用时特定的情况可以选择不同阈值,如果对正例的判别准确性要求高,可以选择阈值大一些,对正例的召回要求高,则可以选择阈值小一些)
那么,给定一个逻辑回归模型,如何来调整参数θ?首先我们假设:
上面两个公式是为了,方便后面的计算。
假设我们有n个独立的训练样本{(x1, y1) ,(x2, y2),…, (xn, yn)},y={0, 1}。那每一个观察到的样本(xi, yi)出现的概率是:
当y=1的时候,后面那一项没有了(为1),那就只剩下x属于1类的概率,当y=0的时候,第一项没有了(为1),那就只剩下后面那个x属于0的概率(1减去x属于1的概率)
求θ最优值相当于求,θ使得已知样本出现的最大概率。
因为每个样本都是独立的,所以n个样本出现的概率就是他们各自出现的概率相乘,假设生成m个训练样本相互独立,我们可以写出关于参数θ的似然函数:
(为了方便计算)将它转换为log似然函数:
如何最大化似然函数呢?我们可以使用梯度下降即:
类似于其他算法,例如神经网络BP,根据输入样本,已知的x,每次更新θ),其中α为学习速率。
接下来的问题就是对于L(θ)对θ求导了。
首先,设g(z)为 sigmoid函数,有如下公式g’(z)=g(z)(1-g(z)):
上式中,我们使用了g’(z)=g(z)(1-g(z))。最终得出随机梯度下降法则:
代码实现
- 数据集见github,方便起见,数据集的读取使用pandas。
import pandas as pd
def get_data():
path = '../dataset/logistic_regression/lr_ml_action.txt'
data = pd.read_csv(path, delim_whitespace=True,
names=['f1', 'f2', 'label'],
dtype={'A': np.float64, 'B': np.float64, 'C': np.int64})
# add bias w0 (添加逻辑回归的第一项即偏置W0)
data['f0'] = 1
print data.head()
features = ['f0', 'f1', 'f2']
# 输出转化为 numpy array
return data[features].values, data.label.values
输出的前五行如下:
f1 f2 label f0
0 -0.017612 14.053064 0 1
1 -1.395634 4.662541 1 1
2 -0.752157 6.538620 0 1
3 -1.322371 7.152853 0 1
4 0.423363 11.054677 0 1
类如下:
import numpy as np
class LogisticRegression(object):
def __init__(self):
self._map_method()
pass
def _map_method(self):
self._do_train = {"gd": self._gd, "sgd": self._sgd}
def _sigmoid(self, x):
return 1.0 / (1 + np.exp(-x))
def fit(self, X, Y, **opt):
m, n = X.shape
self._weight = np.ones((n, 1))
max_iter = opt.get("max_iter", 100)
alpha = opt.get("alpha", 0.01)
method = opt.get("method", "sgd")
for k in xrange(max_iter):
try:
# 训练
self._do_train[method](X, Y, alpha)
# 输出当前迭代次数的错误率
print "iter %s error rate %s" % (k, self._get_error_rate(X, Y))
except KeyError:
raise ValueError('method error')
def _sgd(self, X, Y, alpha):
"""
stochastic gradient descent随机梯度下降法
"""
m, n = X.shape
for i in xrange(m):
# pred = self._sigmoid(X[i, :] * self._weight)
pred = self._sigmoid(np.dot(X[i, :], self._weight))
error = Y[i] - pred
self._weight = self._weight + alpha * np.matrix(X[i, :]).T * error
def _gd(self, X, Y, alpha):
"""
gradient descent梯度下降法
"""
pred = self._sigmoid(X * self._weight)
error = Y - pred
self._weight = self._weight + alpha * X.T * error
def _get_error_rate(self, X, Y):
all_num = len(Y)
error_num = 0
for i in xrange(all_num):
pred = self._sigmoid(np.dot(X[i, :], self._weight)) > 0.5
if pred != bool(Y[i]):
error_num += 1
return error_num * 1.0 / all_num
训练代码如下:
def test_lr():
X, Y = get_data()
lr = LogisticRegression()
lr.fit(X, Y)
程序运行的结果如下(可见错误率一直在下降):
具体代码见github
参考
李航《统计学习方法》
《机器学习实战》
http://blog.csdn.net/zouxy09/article/details/20319673
http://blog.yhat.com/posts/logistic-regression-and-python.html