3.【Python】分类算法—Softmax Regression
前言
Softmax回归算法主要用于多分类问题,是逻辑回归算法的推广,值得注意的是,Softmax回归算法中任意两个类是线性可分的。
一、Softmax Regression模型
1.Softmax Regression模型
对于Softmax Regression模型,输入特征为
X
(
i
)
ϵ
R
n
+
1
X^{(i)}\epsilon R^ {n+1}
X(i)ϵRn+1,类标记为
y
(
i
)
ϵ
0
,
1
,
.
.
.
,
k
y^{(i)}\epsilon{0,1,...,k}
y(i)ϵ0,1,...,k。假设函数为每一个样本估计其所属的类别的概率
P
(
y
=
j
∣
X
)
P(y=j |X)
P(y=j∣X)。具体假设函数如下,其中
Θ
\Theta
Θ表示向量。
则对于每一个样本估计其所属的类别的概率为:
2.Softmax Regression的损失函数
在Softmax Regression算法的损失函数中引入指令函数
I
(
⋅
)
I(\cdot )
I(⋅),表示为:
与Logistic Regression算法中对于损失函数的处理方式类似,都采用极大似然法,并以负的log似然函数作为损失函数,表示为:
I
{
y
(
i
)
=
j
}
I \left \{ y^{(i)}=j \right \}
I{y(i)=j}表示属于第j类时,
I
{
y
(
i
)
=
j
}
=
1
I \left \{ y^{(i)}=j \right \}=1
I{y(i)=j}=1或者
I
{
y
(
i
)
=
j
}
=
0
I \left \{ y^{(i)}=j \right \}=0
I{y(i)=j}=0。
3.Softmax Regression的求解
对于损失函数可以采用梯度下降法进行求解,求解其梯度表示为:
梯度下降的公式可以通过下式更新:
以下将用python代码实现softmax regression的更新过程,构建梯度更新函数gradientAscent,以此实现模型中权重的更新。
import numpy as np
def gradientAscent (feature_data,label_data,k,maxCycle,alpha):
'''利用梯度下降法训练softmax模型
input:feature_data(mat):特征
label_data(mat):标签
k(int):类别的个数
maxCycle(int):最大的迭代次数
alpha(float):学习率
output:weights(mat):权重
'''
m,n = np.shape(feature_data)
#np.ones返回一个全1的n维数组
weights = np.mat(np.ones((n,k)))
i = 0
while i <= maxCycle:
err = np.exp(feature_data * weights)
if i %100 == 0:
print("\t----iter:", i,\
" , cost: ", cost(err,label_data))
rowsum = -err.sum(axis = 1)
rowsum = rowsum.repeat(k,axis = 1)
err = err/rowsum
for x in range(m):
err[x,label_data[x,0]] +=1
weights = weights + (alpha/m) * feature_data.T * err
i += 1
return weights
其中,函数cost用于计算当前损失函数的值,输入为当前预测值err和样本标签label_data。
def cost(err,label_data):
'''计算损失函数的值
input:err(mat):exp的值
label_data(mat):标签的值
output:sum_cost / m(float):损失函数的值
'''
m = np.shape(err)[0]
sum_cost = 0.0
for i in range(m):
if err[i,label_data[i,0]]/np.sum(err[i,:]) > 0:
sum_cost -= np.log(err[i,label_data[i,0]]/np.sum(err[i,:]))
else:
sum_cost -= 0
return sum_cost/m
二、Softmax Regression和Logistic Regression
1.Softmax Regression中的参数特点
在Softmax Regression中有些参数是没用的,称为参数冗余。假设从参数向量
θ
j
{\theta _{j}}
θj中减去向量
ψ
\psi
ψ,对预测结果没用任何影响,说明模型中存在多组最优解。
2.由Softmax Regression到Logistic Regression
Logistic Regression是Softmax Regression特征数为2 时的特殊情况,此时Softmax Regression的假设函数为:
由于Softmax Regression具有冗余性,减去
ψ
\psi
ψ依然等价,令
ψ
=
θ
1
\psi={\theta _{1}}
ψ=θ1,
θ
1
{\theta _{1}}
θ1和
θ
2
{\theta _{2}}
θ2同时减去
ψ
\psi
ψ可得:
特征数为2 时两者假设函数是等价的。
三、Softmax Regression实践
1.构建Softmax Regression算法的训练模型
使用类似如图的数据对Softmax Regression模型进行训练。
(图侵删)
训练模型的主函数如下,首先需要导入训练数据data.txt,而后利用梯度下降法gradientAscent对模型进行训练,已经在前面给出代码,最终将模型参数保存至weights中。
if __name__ == "__main__":
inputfile = "data.txt"
#1.导入训练数据
print("------1.load data------")
feature,label,k = load_data("data.txt")
#2.训练softmax regression模型
print("------2.training-------")
weights = gradientAscent(feature,label,k,1000,0.4) #最大迭代次数1000,学习率0.4
#3.保存最终的模型
print("------3.save model------")
save_model("weights",weights)
首先构建导入训练数据的load_data函数,得出训练数据的特征feature_data 、标签label_data和训练样本的类别个数k。
#data.txt为文件名,inputfile为文件
def load_data(inputfile):
'''
input: inputfile(string)训练数据的文件位置
output: feature_data(mat)特征
label_data(mat)标签
k(int)类别的个数
'''
f = open(inputfile) #打开文件
feature_data = []
label_data = []
#逐行读取
for line in f.readlines():
feature_tmp = []
#strip spilt
lines = line.strip().split("\t")
feature_tmp.append(1) #偏置项
for i in range(len(lines)-1): #读除最后一行的前几行
feature_tmp.append(float(lines[i]))
label_data.append(int(lines[-1])) #读最后一行
feature_data.append(feature_tmp)
f.close() #关闭文件
#.T为转置
return np.mat(feature_data),\
np.mat(label_data).T,len(set(label_data))
gradientAscent函数在第一节第3.点总已经定义。
最后构建训练模型的save_model函数,将模型和weights保存在file_name中。
def save_model(file_name, weights):
'''保存最终的模型
input:
file_name(string): 保存的文件名
weights(mat):softmax模型
'''
f_w = open(file_name, "w")
m, n = np.shape(weights)
for i in range(m):
w_tmp = []
for j in range(n):
w_tmp.append(str(weights[i,j]))
f_w.write("\t".join(w_tmp)+"\n")
f_w.close()
2.预测测试数据
将文件命名为softmax_regression_test.py,构建测试模型的主程序,首先导入模型的权重等参数,然后导入测试数据,其后利用训练好的softmax模型对测试数据进行预测,最后将预测结果保存到文件中。
测试模型的主程序如下:
if __name__ == "__main__":
#1.保存softmax模型
print("------1.load model------")
w, m, n = load_weights("weights")
#2.导入测试数据
print("------2.load data------")
test_data = load_data(4000,m)
#3.利用训练好的softmax regression模型对测试数据进行预测
print("------3.get prediction-------")
result = predict(test_data, w)
#4.保存最终的预测结果
print("------4.save prediction------")
save_model("result", result)
构建load_weights函数导入训练模型参数,主要是权重矩阵和矩阵的行列数。
def load_weights(weights_path):
'''导入softmax训练模型
input:weights_path(string)权重的存储位置
output:weights(mat)将权重存到矩阵中
m(int)权重的行数
n(int)权重的列数
'''
f = open(weights_path)
w = []
for lines in f.readlines():
lines = line.strip().split("\t")
w_tmp = []
for x in lines:
w_tmp.append(float(x))
w.append(w_tmp)
f.close()
weights = np.mat(w)
m, n = np.shape(weights)
return np.mat(w)
构建load_data函数导入测试数据,这里测试数据为随机数,需要导入random模块。
import random as rd
def load_data(num,m):
'''导入测试数据
input:
num(int):生成的测试样本的个数
m(int):样本的维数
output:testdataset(mat)生成测试样本
'''
testdataset = np.mat(np.ones(num, m))
for i in range(num):
#随机生成[-3,3]之间的随机数
testdataset[i, 1] = rd.random() * 6 - 3
#随机生成[0,15]之间的随机数
testdataset[i,2] = rd.random() * 15
return testdataset
构建predict函数对测试数据进行预测。
def predict(test_data, weights):
'''利用训练好的softmax模型对测试数据进行预测
input:
test_data(mat):测试数据的特征
weights(mat):模型的权重
output:h.argmax(axis=1)所属的类别
'''
h = test_data * weights #每个样本属于每一个类别的概率
#每一列最大值所在位置的索引
return h.argmax(axis=1) #获得最终的类别标签
构建save_result函数保存预测结果。
def save_result (file_name, result):
'''保存最终的预测结果
input:
file_name(string):保存最终结果的文件名
result(mat):最终的预测结果
'''
f_result = open(file_name, "w")
m = np.shape(result)[0]
for i in range(m):
f_result.write(str(result[i, 0])+ "\n")
f_result.close()
总结
以上针对Softmax Regression算法的原理和python具体实现过程进行了介绍,python的具体实现过程主要分为两个部分—训练和预测。
参考文献:《Python机器学习算法》