1.逻辑斯蒂回归、逻辑斯蒂分布、对数几率
首先,逻辑斯蒂回归的公式为:
P
(
Y
=
1
∣
X
)
=
e
x
p
(
w
⋅
x
)
1
+
e
x
p
(
w
⋅
x
)
P(Y=1|X)=\frac{exp(w·x)}{1+exp(w·x)}
P(Y=1∣X)=1+exp(w⋅x)exp(w⋅x)
P
(
Y
=
0
∣
X
)
=
1
1
+
e
x
p
(
w
⋅
x
)
P(Y=0|X)=\frac{1}{1+exp(w·x)}
P(Y=0∣X)=1+exp(w⋅x)1
对于输入x,代入上述公式,我们可求出P(Y=1|x)的概率,
0
<
=
P
(
Y
=
1
∣
x
)
<
=
1
0<=P(Y=1|x)<=1
0<=P(Y=1∣x)<=1。
而
P
(
Y
=
1
∣
x
)
P(Y=1|x)
P(Y=1∣x)的公式来源于逻辑斯蒂分布:
由此分布可以看出,
P
(
Y
=
1
∣
x
)
P(Y=1|x)
P(Y=1∣x)的公式来与此分布相同,因此其对应的图像与F(x)图像相同。
同时对应的对数几率为
l
o
g
i
t
(
p
)
=
l
o
g
P
(
Y
=
1
∣
x
)
1
−
P
(
Y
=
1
∣
x
)
=
w
⋅
x
logit(p)=log\frac{P(Y=1|x)}{1-P(Y=1|x)}=w·x
logit(p)=log1−P(Y=1∣x)P(Y=1∣x)=w⋅x,
w
⋅
x
w·x
w⋅x对应的为整个实数域,即通过logit变换可将p对应于整个实数域,即将【0,1】与
w
⋅
x
w·x
w⋅x一一对应起来,取上述logit的反函数即为
P
(
Y
=
1
∣
X
)
=
e
x
p
(
w
⋅
x
)
1
+
e
x
p
(
w
⋅
x
)
P(Y=1|X)=\frac{exp(w·x)}{1+exp(w·x)}
P(Y=1∣X)=1+exp(w⋅x)exp(w⋅x)。
2.参数求解
而此时的我们可利用极大似然估计对上述参数进行求解,首先似然函数如下图所示
然后我们需要做的就是极大化上述的
L
(
w
)
L(w)
L(w),具体的求解方法可以用梯度下降法、牛顿法等。(疑问:而此时logistics回归为什么不直接采用梯度为0求解?)——link 虽然有时候能够通过直接令梯度为0求得,但通过梯度上升也能够得到差不多最优的结果。最重要的是有的时候不能通过直接令梯度等0直接求出结果,但总能通过梯度上升求出。(极大化——梯度上升/极小化——梯度下降)
具体的
l
(
w
)
=
∑
i
=
1
N
[
y
i
(
w
⋅
x
i
)
−
l
o
g
(
1
+
e
x
p
(
w
⋅
x
i
)
)
]
l(w)=\sum_{i=1}^{N}{[y_i(w·x_i)-log(1+exp(w·x_i))]}
l(w)=∑i=1N[yi(w⋅xi)−log(1+exp(w⋅xi))]对
w
i
w_i
wi梯度为:
∂
l
∂
w
j
=
∑
i
=
1
N
(
y
i
−
e
x
p
(
w
⋅
x
i
)
1
+
e
x
p
(
w
⋅
x
i
)
)
x
i
j
\frac{\partial l}{\partial w_j} =\sum_{i=1}^{N}(y_i-\frac{exp(w·x_i)}{1+exp(w·x_i)})x_i^j
∂wj∂l=i=1∑N(yi−1+exp(w⋅xi)exp(w⋅xi))xij
然后梯度上升的公式为:
w
j
=
w
j
+
α
∑
i
=
1
N
(
y
i
−
e
x
p
(
w
⋅
x
i
)
1
+
e
x
p
(
w
⋅
x
i
)
)
x
i
j
w_j = w_j+\alpha \sum_{i=1}^{N}(y_i-\frac{exp(w·x_i)}{1+exp(w·x_i)})x_i^j
wj=wj+αi=1∑N(yi−1+exp(w⋅xi)exp(w⋅xi))xij
对应到向量的运算为:
w
=
w
+
α
∑
i
=
1
N
(
y
i
−
e
x
p
(
w
⋅
x
i
)
1
+
e
x
p
(
w
⋅
x
i
)
)
x
i
\textbf{w} =\textbf{w}+\alpha \sum_{i=1}^{N}(y_i-\frac{exp(\textbf{w}·x_i)}{1+exp(\textbf{w}·x_i)})x_i
w=w+αi=1∑N(yi−1+exp(w⋅xi)exp(w⋅xi))xi
上述为批量梯度下降的公式,具体到随机梯度下降上:
w
=
w
+
α
(
y
i
−
e
x
p
(
w
⋅
x
i
)
1
+
e
x
p
(
w
⋅
x
i
)
)
x
i
\textbf{w}=\textbf{w}+\alpha (y_i-\frac{exp(\textbf{w}·x_i)}{1+exp(\textbf{w}·x_i)})x_i
w=w+α(yi−1+exp(w⋅xi)exp(w⋅xi))xi
总结:
以上,就是这次对逻辑斯蒂回归的大致介绍,我们首先介绍了逻辑斯蒂回归对应的公式,然后介绍了他与逻辑斯蒂分布以及对数几率之间的关系;然后介绍模型的参数求解,使用极大似然估计方法求解,先写出似然函数,然后可以利用梯度下降/牛顿法等用于求解无约束优化问题的这类方法来对参数进行求解。最后,将会附上一个minist数据集对应的手写逻辑斯蒂回归方法实现的分类。
附:逻辑斯蒂回归实现(minist数据集)
参考:https://www.pkudodo.com/2018/12/03/1-6/#comment-454
import numpy as np
import datetime
'''
minist 数据集
50000 训练集
10000 测试集(实际使用200)
训练结果:
time_cost 295
currencies 0.902
'''
def load_data(fileName):#加载数据
'''
:param fileName:minist训练集/测试集文件
:return: 对应的特征值X和标签值Y
'''
fr = open(fileName, 'r')
dataX = [];dataY = []
for line in fr.readlines():
lineArr = []
curline = line.strip().split(',')
if(curline[0]=='0'):# 二分类问题 转换为区分0和非0数字
dataY.append(1) # 标签
else:
dataY.append(0)
#dataX.append([int(num) for num in curline[1:]]) # 特征
dataX.append([int(num)/255 for num in curline[1:]]) # 特征
'''
/255是进行归一化
如果不进行归一化 则将如下代码
if(curline[0]=='0'):# 二分类问题 转换为区分0和非0数字
dataY.append(1) # 标签
else:
dataY.append(0)
改为:
if(curline[0]=='0'):# 二分类问题 转换为区分0和非0数字
dataY.append(0) # 标签
else:
dataY.append(1)
则正确率会很低
但进行归一化之后,就不会有上述问题
'''
# print(dataX)
return dataX, dataY
def logistics_Regression(trainX,trainY,iter=200):
'''
对模型进行训练
:param trainX: 训练集特征x
:param trainY:训练集标签y
:param iter:迭代次数
:return:返回学习到的参数w
'''
# 将w·x+b变为w·x
for i in range(len(trainX)):
trainX[i].append(1)
#将列表转换为数组 便于运算
trainX = np.array(trainX)
# 权值数组大小
w = np.zeros(trainX.shape[1])
#步长
h = 0.001
for i in range(iter):#迭代次数
for j in range(trainX.shape[0]):
# np.dot 点乘 矩阵相乘 a × b 、b×c ==> a × c
# * np.multiply() 对应元素相乘
wx = np.dot(w,trainX[j])
w += h*(trainY[j]*trainX[j] - trainX[j]*np.exp(wx)/(1+np.exp(wx)))
if i%20==0:
print('{:.2%}...'.format(i/200))
return w
def predict(w,X):
'''
进行结果预测
:param w: 训练好的参数
:param X: 待预测的样本特征
:return: 预测结果
'''
p = np.exp(np.dot(w,X))/(1+np.exp(np.dot(w,X)))
if(p>=0.5):
return 1
else:
return 0
def test(testX,testY,w):
'''
进行测试集的相关测试
:param testX:测试集特征
:param testY: 测试集标签
:param w: 参数
:return: 正确率
'''
for i in range(len(testX)):
testX[i].append(1)
count = 0
for i in range(len(testX)):
if testY[i] == predict(w,testX[i]):#进行测试
count+=1
return float(count/len(testX))
if __name__ == "__main__":
print("start read data...")
trainX, trainY = load_data("./mnist_train/mnist_train.csv")
testX, testY = load_data("./mnist_test/mnist_test.csv") # 进行测试
# (60000,784) (60000,1)
# testX = np.mat(testX)
start = datetime.datetime.now()
print("start train the model...")
w = logistics_Regression(trainX, trainY)
print("start test...")
acc = test(testX,testY,w)
end = datetime.datetime.now()
print("time_cost", (end - start).seconds)
print("currencies ", acc)