# 逻辑回归

### Hypothesis function 预测函数

h

θ

(

x

)

=

1

1

+

e

x

θ

T

(1)

h_{theta}(x) = frac{1}{1+e^{-bold{x}*theta^T}} tag{1}

hθ(x)=1+exθT1(1)

### 代价函数

Cost

(

h

θ

(

x

)

,

y

)

=

{

log

(

h

θ

(

x

)

)

if

y

=

1

log

(

1

h

θ

(

x

)

)

if

y

=

0

(2)

operatorname{Cost}left(h_{theta}(x), yright)=left{begin{aligned} -log left(h_{theta}(x)right) & text { if } y=1 \ -log left(1-h_{theta}(x)right) & text { if } y=0 end{aligned}right. tag{2}

Cost(hθ(x),y)={log(hθ(x))log(1hθ(x)) if y=1 if y=0(2)

Cost

(

h

θ

(

x

)

,

y

)

=

y

×

log

(

h

θ

(

x

)

)

(

1

y

)

×

log

(

1

h

θ

(

x

)

)

(3)

operatorname{Cost}left(h_{theta}(x), yright)=-y times log left(h_{theta}(x)right)-(1-y) times log left(1-h_{theta}(x)right) tag{3}

Cost(hθ(x),y)=y×log(hθ(x))(1y)×log(1hθ(x))(3)

y

=

1

y=1

y=1时，

h

θ

(

x

)

h_{theta}(x)

hθ(x)越接近于1，

C

o

s

t

Cost

Cost越小。当

y

=

0

y=0

y=0时，

h

θ

(

x

)

h_{theta}(x)

hθ(x)越接近于0，

C

o

s

t

Cost

Cost越小。换句话说，在使用这样的代价函数进行模型的训练时，会让

y

=

0

y=0

y=0时的

h

θ

(

x

)

h_theta(x)

hθ(x)趋于

0

0

0，会让

y

=

1

y=1

y=1时的

h

θ

(

x

)

h_theta(x)

hθ(x)趋于

1

1

1。也就是说，对于最终训练得到的模型，

h

θ

(

x

)

h_theta(x)

hθ(x)越大，表明它被判别为这一类的可能性越大。

J

(

θ

)

=

1

m

i

=

1

m

[

y

(

i

)

log

(

h

θ

(

x

(

i

)

)

)

(

1

y

(

i

)

)

log

(

1

h

θ

(

x

(

i

)

)

)

]

(4)

J(theta)=frac{1}{m} sum_{i=1}^{m}left[-y^{(i)} log left(h_{theta}left(x^{(i)}right)right)-left(1-y^{(i)}right) log left(1-h_{theta}left(x^{(i)}right)right)right] tag{4}

J(θ)=m1i=1m[y(i)log(hθ(x(i)))(1y(i))log(1hθ(x(i)))](4)

J

(

θ

)

J(theta)

J(θ)的偏导数的最终推导结果如下，其中i表示第i个数据，j表示该数据的第j维的值。

θ

j

J

(

θ

)

=

θ

j

[

1

m

i

=

1

m

[

y

(

i

)

log

(

1

+

e

θ

T

x

(

i

)

)

(

1

y

(

i

)

)

log

(

1

+

e

θ

T

x

(

i

)

)

]

]

=

1

m

i

=

1

m

[

h

θ

(

x

(

i

)

)

y

(

i

)

]

x

j

(

i

)

(5)

begin{aligned} frac{partial}{partial theta_{j}} J(theta)=&frac{partial}{partial theta_{j}}left[-frac{1}{m} sum_{i=1}^{m}left[-y^{(i)} log left(1+e^{-theta^{T} x^{(i)}}right)-left(1-y^{(i)}right) log left(1+e^{theta^{T} x^{(i)}}right)right]right]\ =&frac{1}{m} sum_{i=1}^{m}left[h_{theta}left(x^{(i)}right)-y^{(i)}right] x_{j}^{(i)} end{aligned} tag{5}

θjJ(θ)==θj[m1i=1m[y(i)log(1+eθTx(i))(1y(i))log(1+eθTx(i))]]m1i=1m[hθ(x(i))y(i)]xj(i)(5)

θ

theta

θ的维度，需要注意的是

θ

bold{theta}

θ

θ

1

theta_1

θ1开始进行正则化。

J

(

θ

)

=

1

m

i

=

1

m

[

y

(

i

)

log

(

h

θ

(

x

(

i

)

)

)

(

1

y

(

i

)

)

log

(

1

h

θ

(

x

(

i

)

)

)

]

+

λ

2

m

j

=

1

n

θ

j

2

(6)

J(theta)=frac{1}{m} sum_{i=1}^{m}left[-y^{(i)} log left(h_{theta}left(x^{(i)}right)right)-left(1-y^{(i)}right) log left(1-h_{theta}left(x^{(i)}right)right)right]+frac{lambda}{2 m} sum_{j=1}^{n} theta_{j}^{2} tag{6}

J(θ)=m1i=1m[y(i)log(hθ(x(i)))(1y(i))log(1hθ(x(i)))]+2mλj=1nθj2(6)

### 梯度下降算法

R

e

p

e

a

t

u

n

t

i

l

c

o

n

v

e

r

g

e

n

c

e

{

θ

0

:

=

θ

0

α

1

m

i

=

1

m

(

(

h

θ

(

x

(

i

)

)

y

(

i

)

)

x

0

(

i

)

)

θ

j

:

=

θ

j

α

1

m

i

=

1

m

(

(

h

θ

(

x

(

i

)

)

y

(

i

)

)

x

j

(

i

)

+

λ

m

θ

j

)

for

j

=

1

,

2

,

n

}

(7)

begin{aligned} Repeat , until , convergence,{ &theta_{0}:=theta_{0}-alpha frac{1}{m} sum_{i=1}^{m}left(left(h_{theta}left(x^{(i)}right)-y^{(i)}right) cdot x_{0}^{(i)}right) \ &theta_{j}:=theta_{j}-alpha frac{1}{m} sum_{i=1}^{m}left(left(h_{theta}left(x^{(i)}right)-y^{(i)}right) cdot x_{j}^{(i)}+frac{lambda}{m} theta_{j}right) \ & text { for } j=1,2, ldots n \ &} end{aligned} tag{7}

Repeatuntilconvergence{θ0:=θ0αm1i=1m((hθ(x(i))y(i))x0(i))θj:=θjαm1i=1m((hθ(x(i))y(i))xj(i)+mλθj) for j=1,2,n}(7)

### 逻辑回归用于多分类问题

i

i

i”和“不是

i

i

i”之间决定。我们将把分类器训练包含在一个函数中，该函数计算

N

N

N个分类器中的每个分类器的最终权重，得到最后的结果。

N

N

N分类问题来说，我们要制定并训练出

N

N

N个分类器。也就是说，我们需要先将原样本的y标签变化为N份针对不同分类器的y标签。对于从

i

=

1

,

,

N

i=1,dots,N

i=1,,N类的y，我们都以

i

i

i为主体转化出N份的y标签，值只有1和0，他们分别对应是第

i

i

i类和不是第

i

i

i类。

N

N

N个分类器，得到不同分类器下的

θ

theta

θ值，并加他们都添加到

a

l

l

_

t

h

e

t

a

all_theta

all_theta当中。之后，我们就可以进行逻辑

N

N

N类回归预测。对于输入的样本值，我们要在

N

N

N个分类器中进行预测，最终最高

h

θ

(

x

)

h_theta(x)

hθ(x)值对应的那一类就是我们最终预测的结果。

### 代码实例

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# 逻辑回归做多类别预测
print(data['X'].shape,data['y'].shape)


h

θ

h_theta

hθ函数)和

C

o

s

t

Cost

Cost函数:

#sigmoid 函数
def sigmoid(z):
return 1 / (1 + np.exp(-z))

#代价函数
def cost(theta, X, y, learningRate):
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)
#sigmoid函数里套 X * theta.T 就是 H函数   (5000,400) * (400,1)
#有关*的注释：
#a*b 如果a和b都是narray 且 规格相同，按普通乘法来，如果他们都是matrix,必须按矩阵乘法的规格来
#因此这里X是(5000,400) theta 则是(400,1) 相乘之后是 (5000,1)
#y标签里的值是1-10 10代表0
#np.multiply 两矩阵规格相同时，计算得到其内积
first = np.multiply(-y, np.log(sigmoid(X * theta.T)))
second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))
#len(X) 5000-也就是X的第一维的长度 这里表示5000 theta 正则化前就是乘以1/2m
#theta[:,1:theta.shape[1]]表示从theta1开始正则化， theta0不参与正则化
reg = (learningRate / (2 * len(X))) * np.sum(np.power(theta[:,1:theta.shape[1]], 2))
return np.sum(first - second) / len(X) + reg    #first - second 后要求sum


def gradient_with_loop(theta, X, y, learningRate):
theta = np.matrix(theta)
#X 本身是(400,)的一个向量，我们要把它转为列向量(转换为矩阵，它就变成了(1,400)的列向量)
# 把一维的向量转换为列向量--->意味着把它转换为矩阵
X = np.matrix(X)
y = np.matrix(y)

#取[1] 也就是400
parameters = int(theta.ravel().shape[1])

#(5000,400) * (400,1) ->(5000,1)
error = sigmoid(X * theta.T) - y

for i in range(parameters):
# 在error外面乘x_j^i i是代表第几个X 因为这里是 np.multiply
# 这里 就是将上一步得到的error 每行和 X[,i]的每行相乘
# 与公式是一致的 至于这个代码里的i是指theta 对应的i 也就是公式中的j 因为x是有400维的
# 公式当中x^(i)_{j} i 是指第几个数据 他都是400维  j是指400中的具体第几个维度
# 所以对于不同的theta_{j} 它是对应不同维度(400)的x
# 这里的error (5000,1) X[:,i] 也是(5000,1) 它的每一行
# 5000行的每个值都是乘了5000个X的第i个 (5000,i) i代表theta的下标
term = np.multiply(error, X[:, i])

if (i == 0):
else:
grad[i] = (np.sum(term) / len(X)) + ((learningRate / len(X)) * theta[:, i])



θ

theta

θ的梯度，它的大小与

θ

theta

θ的大小是一样的(X的维度)。在进行梯度下降的时候是要把所有变量都要走一遍 所以要sum所有/m。我们看到动态的梯度/参数在变化是因为有大量的样本，一个样本是过一遍，而不是因为epoch的变化(不要混淆)。

#向量化的梯度函数
theta = np.matrix(theta)
X = np.matrix(X)
y = np.matrix(y)

parameters = int(theta.ravel().shape[1])
# X * theta.T ->(5000,1) x^(i) 第 i个数据与 theta向量相乘 theta.T是(400,1) theta原来是(1,400)
error = sigmoid(X * theta.T) - y

#(400,5000) * (5000,1) -> (400,1) 第n个x 的error 乘以 第n个 x 的x_j^{i} 并加和 (1,400)
#X.T * error X是行向量，(400,5000) * (5000,1) -> (400,1) 转置 (1,400)
grad = ((X.T * error) / len(X)).T + ((learningRate / len(X)) * theta)

#在进行梯度下降的时候是要把所有变量都要走一遍 所以要sum所有的/m

# intercept gradient is not regularized
# 特殊处理一下 拦截 (0,0) 也就是theta 0
grad[0, 0] = np.sum(np.multiply(error, X[:, 0])) / len(X)



10

10

10个可能的类，并且由于逻辑回归只能一次在

2

2

2个类之间进行分类，我们需要多类分类的策略。在本练习中，我们的任务是实现一对一全分类方法，其中具有k个不同类的标签就有k个分类器，每个分类器在“类别

i

i

i”和“不是

i

i

i”之间决定。

10

10

10个分类器中的每个分类器的最终权重，并将权重返回为

k

(

n

+

1

)

k*(n+1)

k(n+1)数组，其中n是参数数量。 权重返回是

k

(

n

+

1

)

k*(n+1)

k(n+1)规格。

10

10

10个分类器的

θ

theta

θ的结果如下：

from scipy.optimize import minimize

def one_vs_all(X, y, num_labels, learning_rate):
rows = X.shape[0]
params = X.shape[1]

# k X (n + 1) array for the parameters of each of the k classifiers
# k个分类器 有k*(n+1)个权重
all_theta = np.zeros((num_labels, params + 1))

# insert a column of ones at the beginning for the intercept term
# 给X在最前面插入了一个 1 与 theta_0相加->代表截距/常数项
X = np.insert(X, 0, values=np.ones(rows), axis=1)

# labels are 1-indexed instead of 0-indexed
# 1-10 对于5000个y里 如果它==i,就变1,!=i就变0
for i in range(1, num_labels + 1):
theta = np.zeros(params + 1)
# 意思就是:对于5000个不同类别的y 类别变成 第 i类和不是第i类
y_i = np.array([1 if label == i else 0 for label in y])
y_i = np.reshape(y_i, (rows, 1))

# minimize the objective function
fmin = minimize(fun=cost, x0=theta, args=(X, y_i, learning_rate), method='TNC', jac=gradient)
all_theta[i - 1, :] = fmin.x
# 第 i 种分类的 (n+1)个theta值

return all_theta


def predict_all(X, all_theta):
rows = X.shape[0]
params = X.shape[1]
num_labels = all_theta.shape[0]

# same as before, insert ones to match the shape
X = np.insert(X, 0, values=np.ones(rows), axis=1)

# convert to matrices
X = np.matrix(X)
all_theta = np.matrix(all_theta)

# compute the class probability for each class on each training instance
h = sigmoid(X * all_theta.T)
# 对于第i类来说，判断是第i类或者不是第i类，h(x)值越大，说明是第i类的可能性越大

# create array of the index with the maximum probability
h_argmax = np.argmax(h, axis=1)

# because our array was zero-indexed we need to add one for the true label prediction
h_argmax = h_argmax + 1

return h_argmax


θ

theta

θ添加了一个额外的参数（与训练数据一列），以计算截距项（常数项）。其次，我们将y从类标签转换为每个分类器的二进制值（要么是

i

i

i类，要么不是

i

i

i类）。最后，我们使用SciPy的较新优化API来最小化每个分类器的代价函数。 如果指定的话，API将采用目标函数，初始参数集，优化方法和jacobian（渐变）函数。然后将优化程序找到的参数分配给参数数组。

θ

theta

θ是一维数组，因此当它被转换为计算梯度的代码中的矩阵时，它变为

(

1

×

401

)

(1×401)

(1×401)矩阵。我们还检查y中的类标签，以确保它们看起来与想象的一致。

all_theta = one_vs_all(data['X'], data['y'], 10, 1)
y_pred = predict_all(data['X'], all_theta)
correct = [1 if a == b else 0 for (a, b) in zip(y_pred, data['y'])]
accuracy = (sum(map(int, correct)) / float(len(correct)))
print ('accuracy = {0}%'.format(accuracy * 100))