一、简述
上一篇博客写到线性回归,它是一个线性拟合的过程,而逻辑回归是一个分类的过程,逻辑回归可以用于多分类,一般用在二分类的模型中。对于二维特征,只需要用一根直线进行分割,对于三维特征,需要用一个面进行分割,对于更多维的特征,就很难想象了,这里,我们只讨论二维特征。
二、数学原理
1、sigmoid函数:
2、对于线性边界的情况,边界形式如下:
3、构造预测函数为:
4、hθ(x)函数的值有特殊的含义,它表示结果取1的概率,因此对于输入x分类结果为类别1和类别0的概率分别为:
5、输出y(标签值0或1)类别的概率可以用以下公式表示:
举个例子,假设h(x) = 0.01,则表示y=0的概率为0.99,y=1的概率为0.01,这就要看训练集中y的值了,
6、取似然函数,就是对每组预测概率之间的乘积,乘积越大,则损失越小:
我们要改变参数theta,使得每组数据预测正确的概率值尽可能地大,乘积也就尽可能地大
7、对上式取对数,单调性没有改变,我觉得这种操作是为了更好地求导,得到如下式子:
8、损失函数一般习惯于取最小值,所以在最大值(上式)取负数就是最小值了,然后对m组数据取平均,除以m就是损失函数:
9、对theta求梯度如下:
10、使用梯度下降法更新参数,梯度下降法首先针对的凸函数,这样才能得到全局最优解。梯度下降法的设计和实现都很简单,但是效率很低。这里提下其他几种参数更新方法:Momentum、AdaGrad、Adam,感兴趣的可以查阅资料。梯度下降法如下:
11、逻辑回归原理参考
三、编程测试
环境:window10+pycharm2017.3+python3.6.6
import numpy as np
import matplotlib.pyplot as plt
"""
函数说明:梯度下降求最优值
Parameters:
feature --m*n
lable --m*1
maxCycle --最大迭代次数
alpha --学习率
Returns:
最优参数值
"""
def lr_train_bgd(feature, lable, maxCycle, alpha):
# feature: m*n
n = np.shape(feature)[1] # 每组数据的特征个数
m = np.shape(feature)[0] # 多少组数据
w = np.ones(n).reshape(n, 1) #初始化权重
i = 0
while i < maxCycle:
i += 1
x = np.dot(feature, w)
sigmoid = sig(x) # m*1
error = lable - sigmoid
if i % 50 == 0:
print("损失值: " + str(i) + ": " + str(error_rate(sigmoid, lable)))
# 梯度为: gradient := -np.dot(feature.T, error)/m ; w := w - gradient
# feature.T: n*m error:m*1 w: n*1
w = w + alpha * np.dot(feature.T, error) / m
return w
#计算损失值
"""
函数说明:计算loss或误差率
Parameters:
sigmoid --经过sigmoid转换的值
lable --标签数据
Returns:
返回误差率
"""
def error_rate(sigmoid, lable):
m = np.shape(sigmoid)[0] #特征条数
sum = 0.
for i in range(m):
if sigmoid[i, 0] > 0 and (1 - sigmoid[i, 0] > 0):
sum -= + lable[i, 0] * np.log(sigmoid[i, 0]) + (1 - lable[i, 0]) * np.log(1 - sigmoid[i, 0])
return sum/m
"""
函数说明:将值映射到0-1上,使用了sigmoid函数
Parameters:
X --待变换的值或矩阵
Returns:
返回 X的sigmoid值
"""
def sig(X):
return 1./(1 + np.exp(-X))
"""
函数说明:加载数据集
Parameters:
无
Returns:
返回 feature 和 lable
"""
def loadData():
feature = []
lable = []
fr = open('set.txt')
lines = fr.readlines()
for line in lines:
lineArr = line.strip().split()
feature.append([1.0, lineArr[0], lineArr[1]])
lable.append([lineArr[-1]])
return np.array(feature, dtype='float64'), np.array(lable, dtype='float64')
"""
函数说明:显示结果
Parameters:
weights --训练得到的参数
feature --特征数据
lable --标签数据
Returns:
无
"""
def display(feature, lable, weights):
xclass0 = []
yclass0 = []
xclass1 = []
yclass1 = []
for i in range(np.shape(lable)[0]):
if lable[i] == 1:
xclass0.append(feature[i, 1])
yclass0.append(feature[i, 2])
else:
xclass1.append(feature[i, 1])
yclass1.append(feature[i, 2])
fig = plt.figure()
ax = fig.add_subplot(111) # 添加subplot
ax.scatter(xclass0, yclass0, s=10, c='red', marker='s', alpha=.5) # 绘制正样本
ax.scatter(xclass1, yclass1, s=20, c='green', alpha=.5) # 绘制负样本
x = np.arange(-3.0, 3.0, 0.1)
y = (-weights[0] - weights[1] * x) / weights[2]
ax.plot(x, y)
plt.title('BestFit') # 绘制title
plt.xlabel('X1')
plt.ylabel('X2') # 绘制label
plt.show()
if __name__ == '__main__':
feature, lable = loadData()
w = lr_train_bgd(feature, lable, 5000, 0.2)
print(w)
display(feature, lable, w)
set,txt文件的数据格式形如:
-0.017612 14.053064 0
-1.395634 4.662541 1
-0.752157 6.538620 0
-1.322371 7.152853 0
0.423363 11.054677 0
0.406704 7.067335 1
损失值: 0.09733279544154633
权重:
[[11.23640427]
[ 1.00910356]
[-1.53621881]]
测试截图如下: