import numpy as np
import math
%matplotlib inline
import matplotlib.pyplot as plt
def loadDataSet():
dataMat = []
labelMat = []
with open('testdata.txt', 'r') as fr:
for line in fr.readlines():
lineArr = line.strip().split()
dataMat.append([1, float(lineArr[0]), float(lineArr[1])])
labelMat.append(int(lineArr[2]))
return dataMat, labelMat
返回 dataMat(list) 和 labelMat(list)
dataMat.len 为 (dataSize)(float)
labelMat.len 为 (dataSet)(int)
def sigmoid(inX):
return 1.0/(1 + np.exp(-inX))
σ ( z ) = 1 1 + e − z \sigma(z) = {{1}\over{1 + e^{-z}}} σ(z)=1+e−z1
值得注意的是 σ ′ ( z ) = σ ( z ) ( 1 − σ ( z ) ) \sigma'(z) = \sigma(z)(1 - \sigma(z)) σ′(z)=σ(z)(1−σ(z))
sigmoid 函数经常被用于二分类,当 σ ( z ) < 0.5 \sigma(z) < 0.5 σ(z)<0.5 时,被认为 P = 0 P = 0 P=0。而 σ ( z ) ≥ 0.5 \sigma(z) \ge 0.5 σ(z)≥0.5 时,被认为 P = 1 P = 1 P=1。
在 logistic regression 里,我们把每个特征乘于一个回归系数,然后相加,将得到的总和带进 σ ( z ) \sigma(z) σ(z) 中,得到一个 0 ∼ 1 0 \sim 1 0∼1 的值。
即 z = ω 0 x 0 + ω 1 x 1 + ⋯ + ω n x n z = \omega_{0}x_{0} + \omega_{1}x_{1} + \cdots + \omega_{n}x_{n} z=ω0x0+ω1x1+⋯+ωnxn,如果采用向量的写法可以写成 z = w T x z = w^{T}x z=wTx。
其中, ω \omega ω 是回归系数(权重)的了列向量,而 x x x 是输入的特征值列向量。
因此我们现在剩下的问题就是如何求解回归系数(权重 ω \omega ω)。
def gradAscent(dataMatIn, classLabels):
dataMatrix = np.mat(dataMatIn)
labelMat = np.mat(classLabels).transpose()
m, n = np.shape(dataMatrix)
alpha = 0.001
maxCycles = 100
weights = np.ones((n, 1))
for k in range(maxCycles):
h = sigmoid(dataMatrix * weights)
error = labelMat - h
weights = weights + alpha * dataMatrix.transpose() * error
return weights
梯度是一个向量,表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该方向变化最快(梯度的方向),变化率最大(梯度的模)。
我们将梯度记为 ∇ \nabla ∇,则 f ( x , y ) f(x,y) f(x,y) 的梯度为 ∇ f ( x , y ) = [ ∂ f ( x , y ) ∂ x ∂ f ( x , y ) ∂ y ] \nabla f(x,y) = \begin{bmatrix}\partial f(x,y)\over \partial x \\ \partial f(x,y) \over \partial y \end{bmatrix} ∇f(x,y)=[∂x∂f(x,y)∂y∂f(x,y)] 。
表示我们现在需要沿着 x x x 轴移动 ∂ f ( x , y ) ∂ x \partial f(x,y)\over \partial x ∂x∂f(x,y),沿着 y y y 轴移动 ∂ f ( x , y ) ∂ y \partial f(x,y)\over \partial y ∂y∂f(x,y) 。( f ( x , y ) f(x,y) f(x,y) 要在这些点上有意义且可微)
但是我们上面的式子中,只给出了梯度的方向和变化率,并没有给出步长,因此我们还要定义一个步长 α \alpha α, α \alpha α 也会被称之为学习率(learning rate)。
在本节中,我们讨论的分类为二分类,因此类别非0即1。
我们设 x x x 为输入的特征向量, ξ \xi ξ 为类别。
我们定义 P ( ξ = 1 ∣ x ) = σ ( z ) P(\xi = 1|x) = \sigma(z) P(ξ=1∣x)=σ(z)
显然 P ( ξ = 0 ∣ x ) = 1 − P ( ξ = 1 ∣ x ) = 1 − σ ( z ) = σ ( − z ) P(\xi = 0|x) = 1 - P(\xi = 1|x) = 1 - {\sigma(z)} = \sigma(-z) P(ξ=0∣x)=1−P(ξ=1∣x)=1−σ(z)=σ(−z)
因此,对于第 i i i 个样本,有
P ( ξ = ξ i ∣ x i ) = P ( ξ = 0 ∣ x i ) 1 − ξ i P ( ξ = 1 ∣ x i ) ξ i = ( 1 − σ ( z i ) ) 1 − ξ i σ ( z i ) ξ i P(\xi = \xi_{i}|x_i) = P(\xi = 0|x_i)^{1-\xi_i}P(\xi = 1|x_i)^{\xi_i}=(1-\sigma(z_i))^{1-\xi_i}\sigma(z_i)^{\xi_i} P(ξ=ξi∣xi)=P(ξ=0∣xi)1−ξiP(ξ=1∣xi)ξi=(1−σ(zi))1−ξiσ(zi)ξi
由于各个样本之间是相互独立的,联合概率为各个样本的乘积。因此我们可以得到关于权重向量 ω \omega ω 的最大似然函数
L ( ω ) = ∏ i = 1 n ( 1 − σ ( z ) ) 1 − ξ i ( σ ( z ) ) ξ i ( n 为样本总数) \mathscr{L}(\omega) = \prod^n_{i = 1}(1-\sigma(z))^{1-\xi_i}(\sigma(z))^{\xi_i} \quad\text{($n$ 为样本总数)} L(ω)=i=1∏n(1−σ(z))1−ξi(σ(z))ξi(n 为样本总数)
两边同时取对数,得
l n L ( ω ) = ∑ i = 1 n l n ( ( 1 − σ ( z ) ) 1 − ξ i σ ( z ) ξ i ) = ∑ i = 1 n ( ( 1 − ξ i ) l n ( 1 − σ ( z ) ) + ξ i l n σ ( z ) ) = ∑ i = 1 n ( ( 1 − ξ i ) l n σ ( − z i ) + ξ i l n σ ( z i ) ) \begin{aligned} ln\ \mathscr{L}(\omega) & = \sum_{i=1}^{n}ln((1-\sigma(z))^{1-\xi_i}\sigma(z)^{\xi_i})\\ & = \sum_{i=1}^{n}((1-\xi_i)ln(1-\sigma(z)) + \xi_iln\ \sigma(z))\\ & = \sum_{i=1}^{n}((1-\xi_i)ln\ \sigma(-z_i) + \xi_iln\ \sigma(z_i))\\ \end{aligned} ln L(ω)=i=1∑nln((1−σ(z))1−ξiσ(z)ξi)=i=1∑n((1−ξi)ln(1−σ(z))+ξiln σ(z))=i=1∑n((1−ξi)ln σ(−zi)+ξiln σ(zi))
当 L ( ω ) \mathscr{L}(\omega) L(ω) 最大时,此时的 ω \omega ω 为回归系数最优解。
显然,若存在一个 ω \omega ω 使得 L ( ω ) \mathscr{L}(\omega) L(ω) 取得最大值,同样也可使 l n L ( ω ) ln\ \mathscr{L}(\omega) ln L(ω) 取最大值。
因此,求解 l n L ( ω ) ln\ \mathscr{L}(\omega) ln L(ω) 的最大值与求解 L ( ω ) \mathscr{L}(\omega) L(ω) 的最大值是等效的。
现在的问题转换为求 l n L ( ω ) ln\ \mathscr{L}(\omega) ln L(ω) 的最大值。
我们使用梯度上升求 ω \omega ω 的最大值,即 ω : = ω + α ∇ l n L ( ω ) \omega := \omega +\alpha \nabla ln\ \mathscr{L}(\omega) ω:=ω+α∇ln L(ω)
对于 ω \omega ω 的第 j j j 个分量 ω j \omega_j ωj, 有 ω j : = ω j + α ∂ l n L ( ω ) ∂ ω j \omega_j := \omega_j + \alpha {\partial ln\ \mathscr{L}(\omega) \over {\partial \omega_j}} ωj:=ωj+α∂ωj∂ln L(ω)
∂ l n L ( ω ) ∂ ω j = ∑ i = 1 n ( − ( 1 − ξ i ) ( 1 − σ ( − z i ) ) + ξ i ( 1 − σ ( z i ) ) ) ∂ z i ∂ ω j = ∑ i = 1 n ( ( ξ i − 1 ) σ ( z i ) + ξ i ( 1 − σ ( z i ) ) ) x j = ∑ i = 1 n ( ξ i − σ ( z i ) ) x j \begin{aligned}\\ {\partial ln\ \mathscr{L}(\omega) \over {\partial \omega_j}} & = \sum_{i=1}^n (-(1-\xi_i)(1 - \sigma(-z_i)) +\xi_i(1-\sigma(z_i))){\partial z_i \over \partial \omega_j}\\ & = \sum_{i=1}^n ((\xi_i - 1)\sigma(z_i) +\xi_i(1-\sigma(z_i)))x_j\\ & = \sum_{i=1}^n (\xi_i - \sigma(z_i))x_j\\ \end{aligned} ∂ωj∂ln L(ω)=i=1∑n(−(1−ξi)(1−σ(−zi))+ξi(1−σ(zi)))∂ωj∂zi=i=1∑n((ξi−1)σ(zi)+ξi(1−σ(zi)))xj=i=1∑n(ξi−σ(zi))xj
即 ∂ l n L ( ω ) ∂ ω j = x T ( ξ − σ ( z ) ) {\partial ln\ \mathscr{L}(\omega) \over {\partial \omega_j}} = x^T(\xi-\sigma(z)) ∂ωj∂ln L(ω)=xT(ξ−σ(z))
上述代码中,我们令 e r r o r = ξ − σ ( z ) error = \xi - \sigma(z) error=ξ−σ(z)
最后我们可以得到梯度上升的式子为 ω : = ω + α x T ( ξ − σ ( z ) ) \omega := \omega + \alpha x^T(\xi-\sigma(z)) ω:=ω+αxT(ξ−σ(z))
def plotBestFit(weights):
dataMat, labelMat = loadDataSet()
dataArr = np.array(dataMat)
n = np.shape(dataArr)[0]
xcord1 = []; ycord1 = []
xcord2 = []; ycord2 = []
for i in range(n):
if int(labelMat[i] == 1):
xcord1.append(dataArr[i, 1])
ycord1.append(dataArr[i, 2])
else:
xcord2.append(dataArr[i, 1])
ycord2.append(dataArr[i, 2])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xcord1, ycord1, s = 30, c = 'red', marker = 's')
ax.scatter(xcord2, ycord2, s = 30, c = 'green')
x = np.arange(-5.0, 5.0, 0.1)
y = (-weights[0] - weights[1] * x)/weights[2]
ax.plot(x, y)
plt.show()
dataArr, labelMat = loadDataSet()
weights = gradAscent(dataArr, labelMat)
print(weights)
plotBestFit(weights.getA())
[[ 1.65879592]
[ 0.2642799]
[-0.30190436]]