逻辑斯蒂回归(logistic regression)原理小结
本博客中使用到的完整代码请移步至: 我的github:https://github.com/qingyujean/Magic-NLPer,求赞求星求鼓励~~~
适用问题:多类分类
模型特点:特征条件下类别的条件概率分布;对数线性模型
模型类型:判别模型
损失函数:逻辑斯蒂损失
学习策略:极大似然估计,或者正则化的极大似然估计
学习算法:梯度下降法、拟牛顿法
1. 模型函数
逻辑斯蒂回归是解决分类
任务的。逻辑斯蒂回归模型属于“对数线性模型”
。
先看看逻辑斯蒂回归与线性回归的联系。首先想到的是线性回归+阈值,可以转化为一个分类任务,以阈值划分区间,落到不同范围则分成不同的类,例如使用“单位阶跃函数”
:
y
=
{
0
,
i
f
z
<
0
0.5
,
i
f
z
=
0
其
中
z
=
X
θ
1
,
i
f
z
>
0
y=\begin{cases}0,&if\;z<0\\ 0.5,&if\;z=0\;\;\;\;\;其中z=\pmb{X\theta}\\ 1,&if\;z>0\end{cases}
y=⎩⎪⎨⎪⎧0,0.5,1,ifz<0ifz=0其中z=XθXθXθifz>0
但这样做有2个问题:
- 不够健壮,非常容易受到噪声的影响
- 阶跃函数不连续,不可导,无法使用常用的优化算法(梯度下降、拟牛顿法、最小二乘法等)求解最值点的参数。
考虑在“线性回归原理小结”中提到的“广义线性模型”
,单调可微
的函数
g
(
⋅
)
g(\cdot)
g(⋅)可作为“联系函数”
,能将线性回归模型的预测值与真实label联系起来,如果真实标记是离散的,就就对应了现在讲的分类任务。
“sigmoid”函数拥有非常好的数学性质:
g
(
z
)
=
1
1
+
e
−
z
g(z)=\frac{1}{1+e^{-z}}
g(z)=1+e−z1
- 它能将实数范围压缩到(0,1)之间,并在z=0附近变化较快。
- 当 z → + ∞ z \rightarrow +\infty z→+∞时, g ( z ) → 1 g(z) \rightarrow 1 g(z)→1,当 z → − ∞ z \rightarrow -\infty z→−∞时, g ( z ) → 0 g(z) \rightarrow 0 g(z)→0,且 g ( 0 ) = 0.5 g(0)=0.5 g(0)=0.5,这正好与概率对应上。
- 单调可微(连续光滑,处处可导),且导数求解简单方便, g ′ ( z ) = g ( z ) ( 1 − g ( z ) ) g^{'} (z)=g(z)(1-g(z)) g′(z)=g(z)(1−g(z))。
- 函数曲线关于(0,0.5)中心对称。
手动实现sigmoid函数
def sigmoid(z):
return 1./(1+np.exp(-z))
使用“sigmoid”函数
代替“单位阶跃函数”
,即使用“sigmoid”函数
作为联系函数
g
(
⋅
)
g(\cdot)
g(⋅),并令
z
=
x
θ
z=x\theta
z=xθ,则得到了二元逻辑斯蒂回归模型
的一般形式:
h
θ
(
x
)
=
1
1
+
e
−
x
θ
h_\theta (x)=\frac{1}{1+e^{-x\theta}}
hθ(x)=1+e−xθ1
x作为样本输入,
h
θ
(
x
)
h_\theta (x)
hθ(x)作为模型输出,并将其视作后验概率
p
(
y
=
1
∣
x
,
θ
)
p(y=1|x,\theta)
p(y=1∣x,θ)。
- 那么当 x θ > 0 x\theta>0 xθ>0时, h θ > 0.5 h_\theta>0.5 hθ>0.5, y预测为1,且当 h θ → 1 h_\theta \rightarrow 1 hθ→1时,y预测分类为1的概率就越大;
- 当 x θ < 0 x\theta<0 xθ<0时, h θ < 0.5 h_\theta<0.5 hθ<0.5, y预测为0,且当 h θ → 0 h_\theta \rightarrow 0 hθ→0时,y预测分类为0的概率就越大;
- 当
x
θ
=
0
x\theta=0
xθ=0时,
h
θ
=
0.5
h_\theta=0.5
hθ=0.5时,无法做出预测。
p ( y = 1 ∣ x , θ ) = h θ ( x ) = 1 1 + e − x θ = e x θ 1 + e x θ p(y=1|x,\theta)=h_\theta (x)=\frac{1}{1+e^{-x\theta}}=\frac{e^{x\theta}}{1+e^{x\theta}} p(y=1∣x,θ)=hθ(x)=1+e−xθ1=1+exθexθ
p ( y = 0 ∣ x , θ ) = 1 − h θ ( x ) = e − x θ 1 + e − x θ = 1 1 + e x θ p(y=0|x,\theta)=1-h_\theta (x)=\frac{e^{-x\theta}}{1+e^{-x\theta}}=\frac{1}{1+e^{x\theta}} p(y=0∣x,θ)=1−hθ(x)=1+e−xθe−xθ=1+exθ1
一个事件的“几率”
,表示该事件发生的概率与不发生的概率的比值,即
p
1
−
p
\frac{p}{1-p}
1−pp,而该事件的“对数几率”
为
l
o
g
i
t
(
p
)
=
l
o
g
p
1
−
p
logit(p)=log\frac{p}{1-p}
logit(p)=log1−pp,而在二元逻辑斯蒂回归中,输出
y
=
1
y=1
y=1的对数几率是:
l
o
g
p
(
y
=
1
∣
x
,
θ
)
1
−
p
(
y
=
1
∣
x
,
θ
)
)
=
x
θ
log\frac{p(y=1|x,\theta)}{1-p(y=1|x,\theta))}=x\theta
log1−p(y=1∣x,θ))p(y=1∣x,θ)=xθ
即在逻辑斯蒂回归中,输出
y
=
1
y=1
y=1的对数几率是输入x的线性函数,或者说上式实际上是在用线性回归模型的预测结果去逼近真实label的对数几率,这里也是最能体现“回归”的地方,残留了线性回归的影子。该模型也叫作“对数几率回归”
。
2. 损失函数
平方损失在逻辑斯蒂回归分类问题中是非凸的,逻辑回归不是连续的,所以这里不再使用平方损失,而是使用极大似然
来推导损失函数。
把
p
(
y
=
1
∣
x
,
θ
)
p(y=1|x,\theta)
p(y=1∣x,θ)和
p
(
y
=
0
∣
x
,
θ
)
p(y=0|x,\theta)
p(y=0∣x,θ)的式子结合起来,写成一个式子:
p
(
y
∣
x
,
θ
)
=
h
θ
(
x
)
y
(
1
−
h
θ
(
x
)
)
1
−
y
p(y|x,\theta)=h_\theta (x)^y (1-h_\theta (x))^{1-y}
p(y∣x,θ)=hθ(x)y(1−hθ(x))1−y
即为一个样本属于其真实label y的概率分布表达式。
似然函数的目标是:令每个样本属于其真实label的概率越大越好,即“极大似然法”
。
似然函数为:
L
(
θ
)
=
∏
i
=
1
m
p
(
y
(
i
)
∣
x
(
i
)
,
θ
)
=
∏
i
=
1
m
h
θ
(
x
(
i
)
)
y
(
i
)
(
1
−
h
θ
(
x
(
i
)
)
)
1
−
y
(
i
)
L(\theta)=\prod_{i=1}^m p(y^{(i)}|x^{(i)},\theta)=\prod_{i=1}^mh_\theta (x^{(i)})^{y^{(i)}} (1-h_\theta (x^{(i)}))^{1-y^{(i)}}
L(θ)=i=1∏mp(y(i)∣x(i),θ)=i=1∏mhθ(x(i))y(i)(1−hθ(x(i)))1−y(i)
令
L
(
θ
)
L(\theta)
L(θ)越大越好,即求
L
(
θ
)
L(\theta)
L(θ)的极大值,作为优化目标,求解对应的参数,即使用“极大似然估计”
。
对似然函数取对数可使得表达式更简洁,得到对数似然表达式,然后再取负,可得到负对数似然表达式,那么求极大值就可转化为求极小值。
J
(
θ
)
=
−
l
n
L
(
θ
)
=
−
∑
i
=
1
m
[
y
(
i
)
l
o
g
(
h
θ
(
x
(
i
)
)
)
+
(
1
−
y
(
i
)
)
l
o
g
(
1
−
h
θ
(
x
(
i
)
)
)
]
J(\theta)=-lnL(\theta)=-\sum\limits_{i=1}^{m}[y^{(i)}log(h_{\theta}(x^{(i)}))+ (1-y^{(i)})log(1-h_{\theta}(x^{(i)}))]
J(θ)=−lnL(θ)=−i=1∑m[y(i)log(hθ(x(i)))+(1−y(i))log(1−hθ(x(i)))]
此时即得到二元逻辑斯蒂回归的损失函数
,问题转化为以负对数似然函数
为目标的最优化问题(求解极小值)。
J
(
θ
)
=
−
[
(
l
o
g
(
h
θ
(
X
)
)
T
y
+
(
l
o
g
(
1
−
h
θ
(
X
)
)
T
(
1
−
y
)
]
J(\theta) = -[(\,log\,(h_\theta(\pmb{X}))^T\pmb{y}+(\,log\,(1-h_\theta(\pmb{X}))^T(1-\pmb{y})]
J(θ)=−[(log(hθ(XXX))Tyyy+(log(1−hθ(XXX))T(1−yyy)]
其中1表示全1向量,
h
θ
(
X
)
=
1
1
+
e
−
X
θ
h_\theta(\pmb{X})=\frac{1}{1+e^{-X\theta}}
hθ(XXX)=1+e−Xθ1。
手动实现损失函数的计算
# 计算损失函数
def compute_loss(theta, X, y):
if np.ndim(theta) == 1:
theta = theta[:, np.newaxis]
z_x = X.dot(theta) # h=θ^T dot X=θ0*x0+θ1*x1
# print(z_x.shape) # (100,3)x(3,1)=>(100,1)
h_x = sigmoid(z_x) # =>(100,1)
m = y.size # 100,用于对loss求平均
J_loss = -1./m * (np.log(h_x).T.dot(y) + np.log(1-h_x).T.dot(1-y)) # =>(1,1)
if np.isnan(J_loss):
return np.inf
return J_loss[0][0]
加载数据:
data = np.loadtxt(data_dir+'data1.txt', delimiter=',')
print('data shape:', data.shape) # (100,3)
print(data[:5])
输出:
data shape: (100, 3)
[[34.62365962 78.02469282 0. ]
[30.28671077 43.89499752 0. ]
[35.84740877 72.90219803 0. ]
[60.18259939 86.3085521 1. ]
[79.03273605 75.34437644 1. ]]
绘制样本数据点的分布:
# 绘制数据点,便于查看数据分布
def plot_data(data, label_pos, label_neg, axes=None):
# 获取正负样本的index
pos = data[:,2] == 1
neg = data[:,2] == 0
if axes is None:
axes = plt.gca()
axes.scatter(data[pos][:,0], data[pos][:,1], marker='+', c='k', s=60, linewidth=2, label=label_pos)
axes.scatter(data[neg][:,0], data[neg][:,1], c='y', s=60, linewidth=2, label=label_neg)
axes.legend()
plot_data(data, 'y=1', 'y=0')
plt.show()
查看一下 θ = [ 0 , 0 , 0 ] \theta=[0,0,0] θ=[0,0,0]时时的loss:
# 把θ0与x0=[1,1,...,1] 与特征x1,x2,..一起组成一个大X
X = np.c_[np.ones(data.shape[0]), data[:,0:2]]
print(X[:5], X.shape) # (100, 3)
y = np.c_[data[:,2]]
print(y[:5], y.shape) # (100,1)
loss = compute_loss(np.array([[0],[0],[0]]), X, y)
print('\nloss:', loss)
输出:
[[ 1. 34.62365962 78.02469282]
[ 1. 30.28671077 43.89499752]
[ 1. 35.84740877 72.90219803]
[ 1. 60.18259939 86.3085521 ]
[ 1. 79.03273605 75.34437644]] (100, 3)
[[0.]
[0.]
[0.]
[1.]
[1.]] (100, 1)
loss: 0.6931471805599453
3. 学习算法
逻辑斯蒂回归学习常采用梯度下降法
以及拟牛顿法
。这里给出使用梯度下降法
对损失函数的优化过程。
δ
J
(
θ
)
δ
θ
j
=
∑
i
=
1
m
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
x
j
(
i
)
\frac{\delta J(\theta)}{\delta\theta_{j}} = \sum_{i=1}^{m} ( h_\theta (x^{(i)})-y^{(i)})x^{(i)}_{j}
δθjδJ(θ)=i=1∑m(hθ(x(i))−y(i))xj(i)
其矩阵/向量形式为:
δ
J
(
θ
)
δ
θ
=
X
T
(
h
θ
(
X
)
−
y
)
\frac{\delta J(\theta)}{\delta\theta} = \pmb{X^T}(h_\theta(\pmb{X})-\pmb{y})
δθδJ(θ)=XTXTXT(hθ(XXX)−yyy)
则
θ
\theta
θ的使用梯度下降法的迭代计算公式为:
θ
=
θ
−
α
X
T
(
h
θ
(
X
)
−
y
)
\theta=\theta-\alpha\pmb{X^T}(h_\theta(\pmb{X})-\pmb{y})
θ=θ−αXTXTXT(hθ(XXX)−yyy)
手动实现梯度计算
# 计算梯度
def compute_gradient(theta, X, y):
if np.ndim(theta) == 1:
theta = theta[:, np.newaxis]
# 计算model输出
z_x = X.dot(theta) # θ^T dot X=θ0*x0+θ1*x1
# print(z_x.shape) # (100,3)x(3,1)=>(100,1)
h_x = sigmoid(z_x) # =>(100,1)
m = y.size # 100 对应loss中求平均时的m
# 计算梯度并更新参数 X.T.dot(h_x-y):(3,100)x(100,1)=>(3,1)
grad = 1./m * X.T.dot(h_x-y) # (3,1)
return grad.flatten() # (3,)
initial_theta = np.zeros(X.shape[1]) # (3,)
initial_theta = initial_theta[:, np.newaxis] # (3,1)
print(initial_theta.shape) # (3,1)
loss = compute_loss(initial_theta, X, y)
grad = compute_gradient(initial_theta, X, y)
print('loss:', loss)
print('grad:', grad)
输出:
(3, 1)
loss: 0.6931471805599453
grad: [ -0.1 -12.00921659 -11.26284221]
使用梯度下降求解参数,利用scipy.optimize.minimize()
函数,指定最小化的目标即损失函数的计算,然后是梯度的计算,优化参数theta,输入输出(X, y),即可实现最小化损失函数。
from scipy.optimize import minimize
res = minimize(compute_loss, initial_theta, args=(X,y),
jac=compute_gradient, options={'maxiter':400})
res
输出:
fun: 0.2034977015895099
hess_inv: array([[ 2.85339493e+03, -2.32908823e+01, -2.27416470e+01],
[-2.32908823e+01, 2.04489131e-01, 1.72969525e-01],
[-2.27416470e+01, 1.72969525e-01, 1.96170322e-01]])
jac: array([-2.68557620e-09, 4.36433485e-07, -1.39671757e-06])
message: 'Optimization terminated successfully.'
nfev: 34
nit: 25
njev: 30
status: 0
success: True
x: array([-25.16131634, 0.2062316 , 0.20147143])
# 查看最后优化得到的参数theta的值
final_updated_theta = res.x
print('theta:', final_updated_theta, final_updated_theta.shape) # (3,)
输出:
theta: [-25.16131634 0.2062316 0.20147143] (3,)
根据求解出的参数 θ \theta θ绘制出决策边界:
# 绘制决策边界
# 边界:
x1_min, x1_max = X[:,1].min(), X[:,1].max() # 注意X[0]是常数列[1,1,...,1]
x2_min, x2_max = X[:,2].min(), X[:,2].max()
xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max), np.linspace(x2_min, x2_max)) # 生成网格坐标
# print(xx1.shape, xx2.shape) # (50, 50) (50, 50)
XX = np.c_[np.ones(xx1.ravel().shape[0]), xx1.ravel(), xx2.ravel()]
# print(XX.shape) # (2500, 3)
z_x = XX.dot(final_updated_theta) # (2500, 3)x(3,)=>(2500,)
h_x = sigmoid(z_x)
h_x = h_x.reshape(xx1.shape) # (50,50)
# print(h_x.shape)
plt.contour(xx1, xx2, h_x, [0.5], linewidths=1, colors='b') # 决策边界
plot_data(data, 'y=1', 'y=0') # # 样本数据点
plt.legend(loc=1)
4. 加正则项的逻辑斯蒂回归
为防止模型过拟合,一般可以加入正则化项
,常见的有L1正则化
和L2正则化
。例如这里考虑L2正则化,那么其加正则化项的损失函数
代数表达式为:
J
(
θ
)
=
−
[
(
l
o
g
(
h
θ
(
X
)
)
T
y
+
(
l
o
g
(
1
−
h
θ
(
X
)
)
T
(
1
−
y
)
]
+
λ
2
∣
∣
θ
∣
∣
2
2
J(\theta) = -[(\,log\,(h_\theta(\pmb{X}))^T\pmb{y}+(\,log\,(1-h_\theta(\pmb{X}))^T(1-\pmb{y})]+\frac{\lambda}{2}||\theta||^2_2
J(θ)=−[(log(hθ(XXX))Tyyy+(log(1−hθ(XXX))T(1−yyy)]+2λ∣∣θ∣∣22
即
J
(
θ
)
=
−
[
(
l
o
g
(
h
θ
(
X
)
)
T
y
+
(
l
o
g
(
1
−
h
θ
(
X
)
)
T
(
1
−
y
)
]
+
λ
2
∑
j
=
1
n
θ
j
2
即J(\theta)=-[(\,log\,(h_\theta(\pmb{X}))^T\pmb{y}+(\,log\,(1-h_\theta(\pmb{X}))^T(1-\pmb{y})]+\frac{\lambda}{2}\sum_{j=1}^{n}\theta_{j}^{2}
即J(θ)=−[(log(hθ(XXX))Tyyy+(log(1−hθ(XXX))T(1−yyy)]+2λj=1∑nθj2
注意:
正则化项中
θ
\theta
θ从下标1开始计算,
θ
0
\theta_0
θ0不参与计算。
加正则项的逻辑斯蒂回归的损失函数手动实现
# 计算损失函数
def compute_loss_reg(theta, reg, *args):
if np.ndim(theta) == 1:
theta = theta[:, np.newaxis] # (28,)=>(28,1)
XX, y = args
z_x = XX.dot(theta) # h=θ^T dot X=θ0*x0+θ1*x1
# print(z_x.shape) # (118,28)x(28,1)=>(118,1)
h_x = sigmoid(z_x) # =>(118,1)
m = y.size # 118 用于求平均损失
J_loss = -1./m * (np.log(h_x).T.dot(y) + np.log(1-h_x).T.dot(1-y)) # =>(1,1)
# 注意:正则项的求和中j是从1开始的,而不是0,因为约束的是特征,而\theta_0对应的是x_0=1常数项
reg_item = reg/(2.*m) * np.sum(np.square(theta[:,0][1:]))
J_loss = J_loss + reg_item
if np.isnan(J_loss):
return np.inf
return J_loss[0][0]
那么加正则项后的偏导(梯度)
代数表达式为:
δ
J
(
θ
)
δ
θ
j
=
∑
i
=
1
m
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
x
j
(
i
)
+
λ
θ
j
\frac{\delta J(\theta)}{\delta\theta_{j}} = \sum_{i=1}^{m} ( h_\theta (x^{(i)})-y^{(i)})x^{(i)}_{j}+\lambda\theta_j
δθjδJ(θ)=i=1∑m(hθ(x(i))−y(i))xj(i)+λθj
其矩阵/向量形式为:
δ
J
(
θ
)
δ
θ
=
X
T
(
h
θ
(
X
)
−
y
)
+
λ
θ
\frac{\delta J(\theta)}{\delta\theta} = \pmb{X^T}(h_\theta(\pmb{X})-\pmb{y})+\lambda\pmb{\theta}
δθδJ(θ)=XTXTXT(hθ(XXX)−yyy)+λθθθ
加正则项的梯度计算的手动实现
# 计算梯度
def compute_gradient_reg(theta, reg, *args):
if np.ndim(theta) == 1:
theta = theta[:, np.newaxis] # (28,)=>(28,1)
XX, y = args
# 计算model输出
z_x = XX.dot(theta) # θ^T dot X=θ0*x0+θ1*x1
# print(z_x.shape) # (118,28)x(28,1)=>(118,1)
h_x = sigmoid(z_x) # =>(118,1)
m = y.size # 118 对应于平均损失中的m
# 计算梯度并更新参数 X.T.dot(h_x-y):(28,118)x(118,1)=>(28,1)
grad = 1./m * XX.T.dot(h_x-y) # (28,1)
reg_item = reg/m * np.r_[ [[0]], theta[1:] ] # (1,1) 行拼接 (27,1)=>(28,1)
grad = grad + reg_item # (28,1)
return grad.flatten() # (28,)
加载数据:
data2 = np.loadtxt(data_dir+'data2.txt', delimiter=',')
print('data shape:', data2.shape) # (100,3)
print(data2[:5])
plot_data(data2, 'y=1', 'y=0')
输出:
data shape: (118, 3)
[[ 0.051267 0.69956 1. ]
[-0.092742 0.68494 1. ]
[-0.21371 0.69225 1. ]
[-0.375 0.50219 1. ]
[-0.51325 0.46564 1. ]]
可见该数据不是直接线性可分的,不能直接使用逻辑斯蒂回归。考虑在“线性回归原理小结”中提到“多项式回归”
,这里使用“多项式特征”(sklearn.preprocessing.PolynomialFeatures)
对原始数据
X
X
X进行特征转化,对转化后的数据
X
′
X'
X′再使用逻辑斯蒂回归。由于数据比之前的复杂,这次便可在学习时加入正则项
以避免过拟合
。。
X = data2[:, 0:2]
y = np.c_[data2[:,2]]
print(X.shape, y.shape) # (118, 2) (118, 1)
poly = PolynomialFeatures(6) # 最高次项为6次
XX = poly.fit_transform(X) # X是有2个特征,XX有28个特征(含组合特征)
XX.shape # (118, 28)
# 0次项:1个,1次项:2个,2次项:3个(x1^2,x2^2,x1x2),3次项:4个
# 4次项:5个,5次项:6个,6次项:7个,一共28个特征
initial_theta = np.zeros(XX.shape[1]) # (28,)
initial_theta = initial_theta[:, np.newaxis]
print(initial_theta.shape) # (28,1)
loss = compute_loss_reg(initial_theta, 1, XX, y)
grad = compute_gradient_reg(initial_theta, 1, XX, y)
print('loss:', loss)
print('grad:', grad)
输出:
(28, 1)
loss: 0.6931471805599454
grad: [8.47457627e-03 1.87880932e-02 7.77711864e-05 5.03446395e-02
1.15013308e-02 3.76648474e-02 1.83559872e-02 7.32393391e-03
8.19244468e-03 2.34764889e-02 3.93486234e-02 2.23923907e-03
1.28600503e-02 3.09593720e-03 3.93028171e-02 1.99707467e-02
4.32983232e-03 3.38643902e-03 5.83822078e-03 4.47629067e-03
3.10079849e-02 3.10312442e-02 1.09740238e-03 6.31570797e-03
4.08503006e-04 7.26504316e-03 1.37646175e-03 3.87936363e-02]
绘制决策边界,并查看不同的正则化项系数,对于决策边界的影响
- lambda = 0 : 就是没有正则化,此时会容易过拟合
- lambda = 1 : 合适的正则化项系数
- lambda = 100 : 正则化项太激进,导致基本没拟合出决策边界
# 预测
def predict(theta, X, threshold=0.5):
z_x = X.dot(theta) # (b,3)x(3,1)=>(b,1)
h_x = sigmoid(z_x) # (b,1)
pred = h_x >= threshold
return pred.astype('int') # (b,1) b个样本的预测结果
fig, axes = plt.subplots(1, 3, sharey=True, figsize=(17,5))
print(axes.shape) # (3,)
lambda_list = [0., 1., 100.]
for i,C in enumerate(lambda_list):
# 最小化损失
res2 = minimize(compute_loss_reg, initial_theta, args=(C,XX,y),
jac=compute_gradient_reg, options={'maxiter':3000})
final_updated_theta = res2.x # (28,)
# print('theta:', final_updated_theta.shape) # (28,)
# 计算准确率 XX:(118, 28) y:(118, 1) theta:=>(28,1)
pred = predict(final_updated_theta.reshape(-1,1), XX) # (118,1)
# print(pred.shape) # (118,1)
accuracy = 100. * sum(pred.ravel() == y.ravel()) / y.size
# 绘制原始数据分布
plot_data(data2, 'y=1', 'y=0', axes=axes.flatten()[i])
# 绘制决策边界 X:(118,2) y:(118,1)
# 边界:
x1_min, x1_max = X[:,0].min(), X[:,0].max() # 注意这里的X不含常数列[1,1,...,1]
x2_min, x2_max = X[:,1].min(), X[:,1].max()
xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max), np.linspace(x2_min, x2_max)) # 生成网格坐标
# print(xx1.shape, xx2.shape) # (50, 50) (50, 50)
X_ = np.c_[xx1.ravel(), xx2.ravel()]
# print(X_.shape) # (2500,2) # 没算常数列
XX_ = poly.fit_transform(X_) # (2500,28)
# print(XX_.shape) # (2500,28)
z_x = XX_.dot(final_updated_theta) # (2500, 28)x(28,)=>(2500,)
h_x = sigmoid(z_x) # (2500,)
h_x = h_x.reshape(xx1.shape) # (50,50)
#print(h_x.shape) # (50,50)
axes.flatten()[i].contour(xx1, xx2, h_x, [0.5], linewidths=1, colors='g') # 决策边界
# 设置标题
axes.flatten()[i].set_title('Train accuracy {:.2f}% with Lambda = {}'.format(accuracy, C))
5. 多项逻辑斯蒂回归
二项逻辑斯蒂回归推广到多项逻辑斯蒂回归
,可用于解决多分类问题
。假设离散型随机变量y的取值集合为{1,2,…,K},那么多项逻辑斯蒂回归的概率分布表达式如下:
p
(
y
=
k
∣
x
,
θ
)
=
e
x
θ
k
1
+
∑
k
=
1
K
−
1
e
x
θ
k
,
k
=
1
,
2
,
.
.
.
,
K
−
1
p(y=k|x,\theta ) = \frac{e^{x\theta_k}} {1+\sum\limits_{k=1}^{K-1}e^{x\theta_k}}\;\;,\;\;k=1,2,...,K-1
p(y=k∣x,θ)=1+k=1∑K−1exθkexθk,k=1,2,...,K−1
p
(
y
=
K
∣
x
,
θ
)
=
1
1
+
∑
k
=
1
K
−
1
e
x
θ
k
p(y=K|x,\theta ) = \frac{1} {1+\sum\limits_{k=1}^{K-1}e^{x\theta_k}}
p(y=K∣x,θ)=1+k=1∑K−1exθk1
注意:
这里的“多项逻辑斯蒂回归”
是解决多分类问题,而前面以及“线性回归原理小结”中提到的“多项式回归”
是解决 “非线性特征” 经过特征转化,得到 多元“线性特征” 的问题。
6. 模型综合评价
- 能以近似概率的形式输出结果;
- 直接对分类的可能性建模,无需事先假设数据分布,避免了假设分布不准确所带来的问题;
- 形式简单,易于建模;
- 可解释性强,可控度高。 θ \theta θ直观的表达了各特征在预测中的重要性;
- 训练快,feature engineering后效果也不错;
- 添加feature很简单;
- 结果是近似概率,可以做ranking model 排序模型。
7. 二分类 vs 多分类
利用二分类器解决多分类问题,关键在于如何对多分类任务进行拆分,以及如何对多个分类器进行集成。常用的拆分策略:
- 一对一(One vs. One,简称OvO):将给定标注数据集按K个类别两两配对,产生
K
(
K
−
1
)
2
\frac{K(K-1)}{2}
2K(K−1)个二分类任务。测试时,新样本同时提交到所有分类器。产生
K
(
K
−
1
)
2
\frac{K(K-1)}{2}
2K(K−1)分类结果,然后对这些分类结果进行
“投票”
,产生最终分类结果。 - 一对其余(One vs. Rest,简称OvR):每次将一个类作为正例,其余其他类都作为负例,形成 N N N个二分类任务。测试时,新样本同时提交到所有分类器。若只有1个分类器预测为正类,则对应类别即为最终分类结果,若有多个分类器预测为正类,则取置信度大的为最终分类结果。
- 多对多(Many vs. Many,简称MvM):每次将若干类作为正例,若干类作为负例。OvO和OvR都是MvM的特例。
完整代码
完整代码请移步至: 我的github:https://github.com/qingyujean/Magic-NLPer,求赞求星求鼓励~~~
参考
[1] 统计学习方法(第2版) 李航
[2] 机器学习(西瓜书) 周志华
[3] 逻辑回归原理小结 刘建平