对逻辑回归的进一步理解

概要

  • 逻辑回归即使用一个超平面将整个空间一分为二,并且在边界附近赋予连续(即不是非黑即白,而是可以有0-1之间的小数概率)的概率估计的二分类方法。

  • 逻辑回归使用\(θX\)作为划分数据的边界。

  • 逻辑回归使用

\[ g( Z) =\frac{1}{1+e^{Z}} \]

替代离散的分布函数,其中,g(Z)即概率统计中的分布函数,可根据极大似然估计得到使用已有样本点估计的近似值:从理论上来讲,此时的似然函数应该是最大的,可以用梯度上升法求之。 对边界的理解 — 显然,Z=θX这个“超平面”可以作为划分整个空间的依据。本来到这里就可以用分段函数完成估计了,但是(1)分布函数是离散的,(2)并且不利于计算靠近分界时的概率,所以引入了S函数使分布函数连续化且能估计在边界附近的概率值,一举两得。

对代价函数的证明与理解

  • 在证明的时候,本来是要分别讨论y=1和y=0时的分布函数的,在得出代价函数的时候使用了一个技巧统一了公式

  • 我们知道,在实际情况下的点为\((y_{i},X_{i})\),而\(y_i\)只能为0或1,所以有如下讨论:
    \[h(X)=p(y=1|X_{i},θ)\] 显然,只有以上这个等式我们并不能用到y=0的点,所以有如下公式:
    \[1-h(X)=p(y=0|X_{i},θ)\]

二者相乘后就得到了统一后的结果: \[ h(X_{i})^{y_{i}}*(1-h(X_{i})^{1-y_{i}}=p(y_{i}|X_{i},θ) \]

我们的目的就是要使以上式子最大化(极大似然的原理:我们观测到的一组数据是n个相互独立的随机变量的观测值,将它们出现的概率乘起来即得到整个观测值出现的概率,而我们观测到的现象一定是出现概率最大的那个结果,所以带入数据后整个式子的值最大)。
接下来就是熟悉的极大似然估计的步骤了,由极大似然估计法要将其最大化,利用高数知识,函数取对数后求导,令导数为零可以解出θ值(而在计算机中则使用梯度上升等方法得到结果)
对其取对数可得逻辑回归的代价函数(与其他回归的代价函数类似,但此处因为是极大似然估计,是求其最大值) \[ L(θ)=-\frac{1}{m}[\sum_{i-1}^{m}y^{i}logh_{θ}(x^{i}+(1-y^{i})log(1-h_{θ}(x^{i}))] \]

  • 接下来就是手工求导出公式并使用梯度下降等算法了,可以愉快的逻辑回归了:) 对\(θ_{i}\)求偏导: \[ \frac{\partial}{\partial{θ_{i}} }L(θ)=(y-h(x))x_{i} \]

  • 梯度上升: \[ θ_{i}=θ_{i}+α(y-h(x))x_{i} \]

贴上手写的浮肿的代码(文件已传github):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import numpy as np
import matplotlib.pylab as plot
class Logistic:
'''
特征系数θ
'''
theta = np.zeros((1, 1))
'''
梯度上升循环次数
'''
cycleNum = 10000
'''
特征向量X、标记向量y
'''
X = np.zeros((1, 1))
Y = np.zeros((1, 1))
alpha = 1
def z(self, X): # z函数,决定z函数的形式 注:这里的X是向量不是矩阵
return X.dot(self.theta.transpose())
def h(self, x):
return 1.0 / (1 + np.exp(-self.z(x)))
def fit(self, X, Y):
cx=np.ones((X.shape[0],1))
self.X = np.c_[cx,X]
self.Y = Y
self.theta = np.random.random((1, self.X.shape[1])) # 由于theta使用random函数导致其为二维而不是一维。
i = 0
j = 0
while j < self.cycleNum:
dtheta = np.zeros((1, self.X.shape[1]))
# print(self.theta)
# print(self.theta[0][0] / self.theta[0][1])
while i <= self.Y.shape[0] - 1:
dtheta += (self.Y[i] - self.h(self.X[i])) * self.X[i]
i += 1
i = 0 # 初始化i
self.theta = self.theta + self.alpha * dtheta
j += 1
def predict(self, vX):
output = self.h(vX)
if output < 0.5:
return 0
else:
return 1
if __name__ == '__main__':
lineSplit = []
x_train = []
y_train = []
with open("testSet-LR.txt", 'r') as f:
lines = f.readlines()
for line in lines:
lineSplit = (line.strip().split())
x_train.append([float(lineSplit[0]), float(lineSplit[1])])
y_train.append([int(lineSplit[2])])
x_train = np.array(x_train)
y_train = np.array(y_train)
logis = Logistic()
logis.alpha = 100
logis.cycleNum = 30000
logis.fit(x_train, y_train)
xop = []
yop = []
xpe = []
ype = []
i = 0
while i <= x_train.shape[0] - 1:
if y_train[i] == 1:
xop.append(x_train[i][0])
yop.append(x_train[i][1])
else:
xpe.append(x_train[i][0])
ype.append(x_train[i][1])
i += 1
fig=plot.figure()
plot.scatter(xop, yop, color="red")
plot.scatter(xpe, ype, color="blue")
plot.xlim((-10,20 ))
plot.ylim((-10, 20))
X = np.linspace(-10, 10, 30)
Y = -X * logis.theta[0][1] / logis.theta[0][2] - logis.theta[0][0] / logis.theta[0][2]
plot.plot(X, Y)
plot.show()
fig.savefig('lr.jpg')

参考资料:用最大似然估计求逻辑回归参数