写在前面
本文主要是学习记录贴,参考《统计学习方法》和部分博客完成。如有错误,欢迎积极评论指出。
初步了解
1 回顾
在前面感知机模型那一章,我们通过一个超平面,对所有的样本点进行分类,即样本点在超平面的哪一边,就将该样本点所属的类进行输出。
如上图所示,感知机模型中的sign是一个不光滑的函数,x=0是跳跃间断点,因此,无法进行微分。但是根据我们之前的了解,机器学习中,主要采用的是梯度下降的方式。而在感知机模型中,因为sign没办法微分,所以感知机模型对sign的内部,也就是w和b进行了梯度下降。而逻辑斯蒂回归,基于上面的思考,提出了一种新的解决方案。
2 问题与解决
首先,在感知机模型中,我们验证了sign(wx+b)的作用。但是在超平面附近的点,相隔距离很近的点,但是输出却差别很大。这个在我们实际感受中,显得有点怪。因此我们需要将这一点进行优化,使模型更贴近我们的现实感知。
结合之前讲过的朴素贝叶斯的概念,我们不一样非要输出其所属类别,我们可以该样本点属于+1和-1的概率,在根据概率值进行判断。这样,我们在超平面附近的点,不仅可以知道它所属的类别,还可以知道它属于这个类的一个可信度。
其次针对第二个问题,对于感知机模型的sign,是不可微的。虽然说我们可以跳过sign实现梯度下降。但是如果存在一个可微分函数,对sign进行替代,那么整个模型是不是就更加合理。
3 逻辑斯蒂回归
针对上面的解决方案,逻辑斯蒂回归模型被提出。对于感知机模型{-1,+1}的硬输出,逻辑斯蒂回归采用P(Y=1|x)和P(Y=0|x)代替输出。然后比较两个条件概率值的大小,将实例x分到概率值较大的类。
接下来是,逻辑斯蒂分布。
如上图所示,f(x)函数是平滑的,当x=0的时候,f(x)=0.5,当x接近于0的时候,概率值在0.5左右,表示对这个样本的分类没有太大把握。当x趋向于无穷大时,表示概率值为1或0,表示我们很确认这个分类结果是对的。
逻辑斯蒂回归二分类模型
逻辑斯蒂回归模型:
统计学习方法中,对w和b做了如下变换:
接下来,对似然函数进行求导:
接下来,我们就可以根据梯度上升或者梯度下降算法,对w进行学习。
逻辑斯蒂回归多分类
逻辑斯蒂回归多分类模型,是在二分类的基础上,实现的。多分类模型为:
其实原理很简单,对于多分类模型,其随机变量的取值范围为{1, 2, 3 …K},我们将取值范围分为两个部分,即{1, 2, 3…K-1}和{K},这样,又化为了二分类模型,接着循环,得到最终的分类结果。
这种多分类方式,用的其实已经不多了,因为softmax回归模型被提出后,逐渐取代了逻辑斯蒂多分类模型。接下来,我们来看看softmax回归模型。
softmax回归模型
公式推导如下:
代码实现
逻辑斯蒂回归相对简单,这里以softmax回归为例:
# The acc is: 0.9185
import numpy as np
# 导入数据
def LoadData(filename):
data = []
label = []
file = open(filename)
for line in file.readlines():
curline = line.strip().split(',')
data.append([int(int(dt) > 128) for dt in curline[1:]]) #二值化
label.append(int(curline[0]))
return data, label
#这段代码,传入的是一个数组,传出也是一个数组
def softmax(wx):
return np.exp(wx) / np.sum(np.exp(wx))
# trainData:训练数据
# trainLabel:训练标签
# iter:迭代次数
# alpha:学习速率
def softmaxRegression(trainData, trainLabel, iter=200, alpha=0.001):
for i in trainData:
i.append(1) #根据书上,对特征末尾加上1,方便和[w,b]构成的数组进行内积运算
trainData = np.array(trainData)
k = 10 # 分类数目
w = np.zeros((k, len(trainData[0])))# 权重w,定义为10*785维数组
for iter in range(iter):
print('迭代次数:', iter)
for j in range(len(trainData)): # 每一次迭代都遍历一次数据集
x = trainData[j].reshape(-1, 1) # 转化为列向量
y = np.zeros((10, 1))
y[trainLabel[j]] = 1 # 当y==k时,输出1,否则为0。标签向量[0,0,0...k...K]
y_i = softmax(np.dot(w, x))
w += alpha*(np.dot((y - y_i), x.T)) # 根据公式定义
return w
def test(w, testData, testLabel):
for data in testData:
data.append(1)
error = 0
testData = np.array(testData)
for i in range(len(testData)):
predict = np.argmax(np.dot(w, testData[i].reshape(-1, 1))) # 输出概率最大的值,即为预测结果
if predict != testLabel[i]:
error += 1
return 1 - error/len(testData)
if __name__ == "__main__":
print('read train data')
trainData, trainLabel = LoadData('Mnist/mnist_train/mnist_train.csv')
print('read test data')
testData, testLabel = LoadData('Mnist/mnist_test/mnist_test.csv')
print('start calculate w')
w = softmaxRegression(trainData, trainLabel)
print('start test')
acc = test(w, testData, testLabel)
print('The acc is: ', acc)