本文介绍对数几率回归模型,是一个典型的二分类任务学习模型
书接上回,我们可以对一个数据集得到它的回归方程
我们是这样去解读回归方程的:在相关属性下对样例的某一特征的度量
我们根据回归方程得到的特征度量是一个连续值,我们可以根据这个度量值进行分类
例如:大学的绩点计算,当我们的绩点大于等于2.0才能拿到学位,否则拿不到学位,我们可以认为当度量值达到多少时将样例视为一类,而没达到的样例分为另一类。
但是问题就在于:1.训练数据集中需要预测的特征是分类的标签(0, 1),而不是其度量值
2.若训练集给出了需要预测的特征的分类标签(0, 1)和度量值,但是我们无法知道两个分类的度量值的界限
根据我们的需求,提出以下假设:
我们的线性方程为:
设有一个函数g(x):
将我们的线性方程和这个g(x)合并可得
这样我们就可利用这个函数模型来对数据分类了
我们可以像推导线性回归函数那样,找到优化目标,从而求出使得方程最优的参数ω和b,但是函数模型是一个分段函数,不连续,无法求得统一的参数,那我们是否可以找到一个类似的连续函数,即参数在取中间值时函数变化陡峭,参数在取+∞或-∞时,函数趋近与1和0,其函数图像如下:
使用最多的就是对数几率函数,其标准形式为
当然不止是对数几率函数可以,任何具有上述性质的函数都可以使用,大家可以试着寻找其他的函数来创建模型。
我们将我们的线性回归方程与对数几率函数合并,得到我们的新模型如下:
我们依然使用差值来度量它的预测准确度,则我们的优化目标函数(代价函数)如下:
表示真实值和预测值差值的平方和,其值越小代表预测越准确。
我们可以使用梯度下降算法来计算上述优化目标。
梯度下降法公式如下(梯度下降法的证明推导过程见https://blog.csdn.net/qq_41398808/article/details/90442685):
我们的优化目标函数的一阶导数为(计算过程参考:https://www.cnblogs.com/crackpotisback/p/5545708.html):
所以我们根据该公式对参数进行迭代,就可以得到我们想要的结果:
Python实现如下:
数据集: 马疝病数据集(原数据地址:http://archive.ics.uci.edu/ml/datasets/Horse+Colic)
连续的数值型数据
一条数据实例如下(最后一项是标签,正例为1,反例为0):
2.000000 1.000000 38.500000 66.000000 28.000000 3.000000 3.000000 0.000000 2.000000 5.000000 4.000000 4.000000 0.000000 0.000000 0.000000 3.000000 5.000000 45.000000 8.400000 0.000000 0.000000 0.000000
读取数据:
def loaddataset(filename):
fp = open(filename)
dataset = []
labelset = []
for i in fp.readlines():
a = i.strip().split()
#存储属性数据
dataset.append([float(j) for j in a[:len(a)-1]])
#存储标签数据
labelset.append(int(float(a[-1])))
return dataset, labelset
这是两个样例的数据读取结果:
[[2.0, 1.0, 38.5, 66.0, 28.0, 3.0, 3.0, 0.0, 2.0, 5.0, 4.0, 4.0, 0.0, 0.0, 0.0, 3.0, 5.0, 45.0, 8.4, 0.0, 0.0], [1.0, 1.0, 39.2, 88.0, 20.0, 0.0, 0.0, 4.0, 1.0, 3.0, 4.0, 2.0, 0.0, 0.0, 0.0, 4.0, 2.0, 50.0, 85.0, 2.0, 2.0]]
[Finished in 3.3s]
[0, 0]
[Finished in 3.2s]
对数几率函数如下:
def sigmoid(z):
return 1.0 / (1 + np.exp(-z))
测试过程(先给出测试过程,是因为在训练过程中我使用测试正确率来控制迭代次数):
def test(dataset, labelset, w):
data = np.mat(dataset)
a = np.ones((len(dataset), 1))
data = np.c_[data, a]
#使用训练好的参数w进行计算
y = sigmoid(np.dot(data, w))
b, c = np.shape(y)
#记录预测正确的个数,用于计算正确率
rightcount = 0
for i in range(b):
#预测标签
flag = -1
#大于0.5的为正例
if y[i, 0] > 0.5:
flag = 1
#小于等于0.5的为反例
else:
flag = 0
#记录预测正确的个数
if labelset[i] == flag:
rightcount += 1
#正确率
rightrate = rightcount / len(dataset)
return rightrate
训练过程:
def trainning(dataset, labelset, test_data, test_label):
#将列表转化为矩阵
data = np.mat(dataset)
label = np.mat(labelset).transpose()
#初始化参数w
w = np.ones((len(dataset[0])+1, 1))
#属性矩阵最后添加一列全1列(参数w中有常数参数)
a = np.ones((len(dataset), 1))
data = np.c_[data, a]
#步长
n = 0.0001
#每次迭代计算一次正确率(在测试集上的正确率)
#达到0.75的正确率,停止迭代
rightrate = 0.0
while rightrate < 0.75:
#计算当前参数w下的预测值
c = sigmoid(np.dot(data, w))
#梯度下降的计算过程,对照着梯度下降的公式
b = c - label
change = np.dot(np.transpose(data), b)
w = w - change * n
#预测,更新正确率
rightrate = test(test_data, test_label, w)
return w
最后的预测结果如下:
正确率为:0.761194
[Finished in 6.4s]
整体代码如下:
源代码和数据集资源已上传(https://download.csdn.net/download/qq_41398808/11197441)
'''
2019.05.22 19:34
马疝病数据集:连续数据,二分类,最后一列是标签列
作者:BTboay
'''
import numpy as np
def loaddataset(filename):
fp = open(filename)
dataset = []
labelset = []
for i in fp.readlines():
a = i.strip().split()
#存储属性数据
dataset.append([float(j) for j in a[:len(a)-1]])
#存储标签数据
labelset.append(int(float(a[-1])))
return dataset, labelset
def sigmoid(z):
return 1.0 / (1 + np.exp(-z))
def trainning(dataset, labelset, test_data, test_label):
#将列表转化为矩阵
data = np.mat(dataset)
label = np.mat(labelset).transpose()
#初始化参数w
w = np.ones((len(dataset[0])+1, 1))
#属性矩阵最后添加一列全1列(参数w中有常数参数)
a = np.ones((len(dataset), 1))
data = np.c_[data, a]
#步长
n = 0.0001
#每次迭代计算一次正确率(在测试集上的正确率)
#达到0.75的正确率,停止迭代
rightrate = 0.0
while rightrate < 0.75:
#计算当前参数w下的预测值
c = sigmoid(np.dot(data, w))
#梯度下降的计算过程,对照着梯度下降的公式
b = c - label
change = np.dot(np.transpose(data), b)
w = w - change * n
#预测,更新正确率
rightrate = test(test_data, test_label, w)
return w
def test(dataset, labelset, w):
data = np.mat(dataset)
a = np.ones((len(dataset), 1))
data = np.c_[data, a]
#使用训练好的参数w进行计算
y = sigmoid(np.dot(data, w))
b, c = np.shape(y)
#记录预测正确的个数,用于计算正确率
rightcount = 0
for i in range(b):
#预测标签
flag = -1
#大于0.5的为正例
if y[i, 0] > 0.5:
flag = 1
#小于等于0.5的为反例
else:
flag = 0
#记录预测正确的个数
if labelset[i] == flag:
rightcount += 1
#正确率
rightrate = rightcount / len(dataset)
return rightrate
if __name__ == '__main__':
dataset, labelset = loaddataset('horseColicTraining.txt')
test_data, test_label = loaddataset('horseColicTest.txt')
w = trainning(dataset, labelset, test_data, test_label)
rightrate = test(test_data, test_label, w)
print("正确率为:%f"%(rightrate))