优化算法
一般方法
- Gradient descent
高级方法(自动设置学习率α,收敛更快) - Conjugate gradient
- BFGS
- L-BFGS
logsitc回归
预备知识
框架思路
线性函数的问题
sigmoid与logsitic回归
损失函数定义
参数求解方法
1、梯度下降法
2、小批量梯度下降法
过拟合问题
1、正则化
阈值问题
1、ROC曲线
多分类问题
1、一对多
最大熵模型
一、为什么线性回归不行?
1、线性回归受离群值影响大,某个数据可能极大影响到直线斜率,从而使得给定阈值下许多样本可能出现错分。
2、线性回归输出值不在[0,1]之间,要使用分段函数,带来的问题是损失函数不是处处可导。
H ( f ) = { 1 , f > 0.5 0 , f ≤ 0.5 H(f)=\left\{\begin{matrix}1,f>0.5\\0,f\leq0.5 \end{matrix}\right. H(f)={1,f>0.50,f≤0.5
二、sigmoid函数
g
(
z
)
=
1
1
+
e
−
z
g(z)=\frac{1}{1+e^{-z}}
g(z)=1+e−z1
对原直线进行一次非线性转换,使得其输出值在[0,1],并且可导。输出结果解释为概率,
即
p
(
x
i
)
=
h
(
x
)
=
g
(
f
(
x
)
)
=
g
(
w
t
x
i
+
b
)
p(x_i)=h(x)=g(f(x))=g(w^tx_i+b)
p(xi)=h(x)=g(f(x))=g(wtxi+b)
h
(
x
)
=
g
(
f
(
x
)
)
=
1
1
+
e
−
w
T
x
+
b
h(x)=g(f(x))=\frac{1}{1+e^{-w^{T}x+b}}
h(x)=g(f(x))=1+e−wTx+b1
损失函数定义为(实际上等价与极大似然函数)
J
(
w
)
=
−
1
m
∑
i
=
1
m
[
y
(
i
)
)
l
n
(
h
(
x
(
i
)
)
)
+
(
1
−
y
(
i
)
)
l
n
(
1
−
h
(
x
(
i
)
)
]
J(w)=-\frac{1}{m}\sum_{i=1}^{m}[y^{(i)})ln(h(x^{(i)}))+(1-y^{(i)})ln(1-h(x^{(i)})]
J(w)=−m1i=1∑m[y(i))ln(h(x(i)))+(1−y(i))ln(1−h(x(i))]
梯度下降法
Θ
j
:
=
Θ
j
−
α
(
h
(
x
(
i
)
)
−
y
(
i
)
)
x
j
(
i
)
\Theta_j :=\Theta_j-\alpha(h(x^{(i)})-y^{(i)})x^{(i)}_j
Θj:=Θj−α(h(x(i))−y(i))xj(i)
j
=
1
,
2
,
.
.
,
n
j=1,2,..,n
j=1,2,..,n
1、sigmoid函数的优势
- 函数输出值为[0,1],可以解释为概率
- 减少了极端值的影响,只有在边界附近(即是z在0附近,函数变化才敏感)
- 损失函数可导,而且为凸函数,使用梯度下降法可以收敛到最小值点
- 不需要对数据分布进行假设,因为是对 p ( x i ) p(x_i) p(xi)建模
2、过拟合问题
常用正则化方法
- L1正则化,用于产生稀疏权值矩阵,即参数中许多参数值为0,用于特征筛选。(参数为0的特征就是被筛选去掉的)
- L2正则化,增加对参数值平方和的惩罚项,约束参数值不能过大,但一般不为0,能够使得曲线更平滑,防止过拟合。
下面为L2正则化
J
(
w
)
=
−
1
m
∑
i
=
1
m
[
y
(
i
)
)
l
n
(
h
(
x
(
i
)
)
)
+
(
1
−
y
(
i
)
)
l
n
(
1
−
h
(
x
(
i
)
)
]
+
λ
2
m
∑
i
=
2
n
Θ
i
2
J(w)=-\frac{1}{m}\sum_{i=1}^{m}[y^{(i)})ln(h(x^{(i)}))+(1-y^{(i)})ln(1-h(x^{(i)})]+\frac{\lambda}{2m}\sum_{i=2}^{n}\Theta_i^2
J(w)=−m1i=1∑m[y(i))ln(h(x(i)))+(1−y(i))ln(1−h(x(i))]+2mλi=2∑nΘi2
梯度下降法
Θ
j
:
=
Θ
j
−
α
m
[
(
h
(
x
(
i
)
)
−
y
(
i
)
)
x
j
(
i
)
+
λ
Θ
j
]
\Theta_j :=\Theta_j-\frac{\alpha}{m}[(h(x^{(i)})-y^{(i)})x^{(i)}_j+\lambda\Theta_j]
Θj:=Θj−mα[(h(x(i))−y(i))xj(i)+λΘj]
j
=
1
,
2
,
.
.
,
n
j=1,2,..,n
j=1,2,..,n
三、python算法实现
import numpy as np
from sklearn.datasets import make_classification
datas=make_classification(n_samples=1000,n_features=5)
data=datas[0]
#添加常数列
data=np.column_stack((np.ones((data.shape[0],1)),data))
target=np.mat(datas[1]).T
--------------------------------------------
def sigmoid(w,x):
#sigmoid函数,输出向量形式的函数值
h=1/(1+np.exp(-np.dot(x,w)))
return h
def grad_ascent(data,target,rate):
#梯度下降法
m,n=data.shape
# w=np.ones((n,1))*0.5
w=np.mat(np.random.normal(size=n)).T
for i in range(200):
h=sigmoid(w,data)
w=w-a/m*np.dot(data.T,h-target)
return w
def regular_grad_ascent(data,target,rate,epi):
#增加二次范式惩罚的正则化损失函数的梯度下降
m,n=data.shape
# w=np.ones((n,1))*0.5
w=np.mat(np.random.normal(size=n)).T
for i in range(200):
h=sigmoid(w,data)
w=w-a/m*(np.dot(data.T,h-target)+epi*(np.row_stack((0,w[1:,0]))))
return w
def MBGD(data,target,rate,batch):
#小批量梯度下降法
m,n=data.shape
w=np.mat(np.random.normal(size=n)).T
batch_size,batch_res=m//batch,m%batch
#找数据集分割点
if batch_res==0:
#恰好分割为batch个小数据集,index有batch+1个元素,用于分割原数据
index=[0]+[k*batch_size for k in range(1,batch+1)]
else:
#添加最后一个不足batch_size的小样本集,batch增加了一个不完整batch_size集,index含有batch+1个元素
index=[0]+[k*batch_size for k in range(1,batch+1)]+[batch*batch_size+batch_res-1]
batch+=1
for k in range(20):
for i in range(batch):
h=sigmoid(w,data[index[i]:index[i+1],:])
w=w-a/m*(np.dot(data[index[i]:index[i+1],:].T,h-target[index[i]:index[i+1]]))
return w
----------------------------------
#分割训练集与测试集
x_y_data=np.column_stack((data,target))
#打乱顺序
np.random.shuffle(x_y_data)
#测试集与训练集比例
a=0.8
index=np.int0(x_y_data.shape[0]*a)
train_x,train_y=x_y_data[:index,:-1],x_y_data[:index,-1]
test_x,test_y=x_y_data[index:,:-1],x_y_data[index:,-1]
rate=0.01 #学习率
w1=grad_ascent(train_x,train_y,rate) #梯度下降
epi=0.9 #二次范式惩罚项
w2=regular_grad_ascent(train_x,train_y,rate,epi) #损失函数增加二次范式得梯度下降
w3=MBGD(train_x,train_y,rate,10) #小批量梯度下降
-------------------------
#错误率
predict=sigmoid(w2,test_x)
predict[np.where(predict>=0.5)[0],0]=1
predict[np.where(predict<0.5)[0],0]=0
print(f"测试集错误率为{np.count_nonzero(predict-test_y)/predict.shape[0]}")