Python实现Logistic Regression(逻辑回归模型)算法

       声明:代码的运行环境为Python3。Python3与Python2在一些细节上会有所不同,希望广大读者注意。本博客以代码为主,代码中会有详细的注释。相关文章将会发布在我的个人博客专栏《Python从入门到深度学习》,欢迎大家关注~


       Logistic Regression算法是一个分类算法,分类算法是一种监督学习算法,它是指根据样本的特征,将样本划分到指定的类别中。Logistic Regression是一个二分类的线性分类算法,说到线性分类算法就不得不说一下线性可分与线性不可分的概念了,如果一个分类问题可以使用线性判别函数正确分类,则称该问题为线性可分,否则称为线性不可分问题。

一、模型介绍

1、Sigmoid函数

       Logistic Regression模型属于线性分类模型,对于线性可分问题,我们需要一条直线将不同的类进行区分,这条直线被表示为:

       其中,W为权重值,b为偏置项,这条直线也被称为超平面。在Logistic Regression模型中,学习得到该直线之后,将数据分为两类,可以通过阈值函数将数据映射到不同的类别中,常用的阈值函数有Sigmoid函数,它表示为:

       代码实现Sigmoid函数:

def sigmoid(x):
    '''
    定义sigmoid函数
    :param x: 参数x
    :return: 返回计算后的值
    '''
    return 1.0 / (1 + np.exp(-x))

 

2、损失函数

       对于Logistic Regression模型来说,权重W和偏置b是唯一的未知参数,故求其值就显得尤为重要!为了求权重和偏置的值,我们需要定义损失函数。

       对于Logistic Regression算法,其属于类别a的概率为:

       其中,是Sigmoid函数。假设有n个样本,我们使用极大似然估计对其进行估计,这里我们使用Log函数,将负的Log似然函数作为其损失函数,于是问题转换为对负的Log函数求极小值,表示为:

       代码实现求解损失函数:

def errorRate(pre, label):
    '''
    损失函数
    :param pre: 预测值
    :param label: 实际值
    :return: 错误率
    '''
    m = np.shape(pre)[0]
    errSum = 0.0
    for i in range(m):
        if pre[i, 0] > 0 and (1 - pre[i, 0]) > 0:
            errSum -= (label[i, 0] * np.log(pre[i, 0]) + (1 - label[i, 0]) * np.log(1 - pre[i, 0]))
        else:
            errSum -= 0.0
    return errSum / m

二、梯度下降法

       在很多监督学习模型中,都需要对原始模型构建损失函数,接下来通过优化算法对损失函数进行优化,找到最优的解,优化算法中常用的例如最小二乘法、梯度下降法等等。此处,为了求得损失函数的最优解,我们使用梯度下降法进行求解。

       梯度下降法的基本流程如下:

       (1)随机选择开一个初始点;

       (2)选择梯度下降的方向;

       (3)选择步长;

       (4)更新点;

       (5)重复(2)、(3)、(4)步知道满足终止条件。

       代码实现梯度下降法:

def LRGradientDescent(feature, label, maxIteration, alpha):
    '''
    使用梯度下降法训练逻辑回归模型
    :param feature: 特征
    :param label: 标签
    :param maxIteration: 最大迭代次数
    :param alpha: 学习率α
    :return: 返回权重矩阵
    '''
    n = np.shape(feature)[1]  # 特征的个数
    w = np.mat(np.ones((n, 1)))  # 初始化权重矩阵
    i = 0 # 定义指标, 用于与最大迭代次数进行比较
    while i <= maxIteration:  # 当指标小于最大迭代次数时
        i += 1
        sig = sigmoid(feature * w)  # 调用sigmoid函数计算sigmoid的值
        error = label - sig
        w = w + alpha * feature.T * error  # 权重修正
        if i % 100 == 0:
            print("迭代", str(i), "时的错误率为:", str(errorRate(sig, label)))
    return w

三、算法测试

1、数据集:分为训练集和测试集

(1)训练集

(2)测试集

2、加载数据集

       我们此处使用如下方法加载数据集,也可使用其他的方式进行加载,此处可以参考我的另外一篇文章《Python两种方式加载文件内容》。加载文件内容代码如下:

def loadData(fileName):
    '''
    加载测试数据
    :param fileName: 文件名
    :return: 返回特征和标签
    '''
    f = open(fileName)  # 打开训练数据集所在的文档
    feature = []  # 存放特征的列表
    label = []  # 存放标签的列表
    for row in f.readlines():
        f_tmp = []  # 存放特征的中间列表
        l_tmp = []  # 存放标签的中间列表
        number = row.strip().split("\t")  # 得到每行特征和标签
        f_tmp.append(1)  # 设置偏置项
        for i in range(len(number) - 1):
            f_tmp.append(float(number[i]))
        l_tmp.append(float(number[-1]))
        feature.append(f_tmp)
        label.append(l_tmp)
    f.close()  # 关闭文件,这个操作很重要
    return np.mat(feature), np.mat(label)

3、保存权重值

       训练数据集,得到权重值,使用如下方法保存权重值:

def saveWeight(fileName, weight):
    '''
    保存权重矩阵
    :param fileName: 保存后的文件名
    :param weight: 权重矩阵
    :return:
    '''
    m = np.shape(weight)[0]
    f = open(fileName, "w")
    weight_list = []
    for i in range(m):
        weight_list.append(str(weight[i ,0]))
    f.write("\t".join(weight_list))
    f.close()

4、使用训练得到的权重对测试集进行分类

'''
分类算法(线性二分类):logistic Regression
'''

from LogisticRegression.LogisticRegression_train import sigmoid
import numpy as np

def loadFile(fileName, num):
    '''
    加载测试集
    :param fileName:
    :param num:
    :return: 返回特征
    '''
    f = open(fileName)
    feature = []
    for row in f.readlines():
        f_tmp = []
        number = row.strip().split("\t")
        if len(number) != num - 1:  # 排除测试集中不符合要求的数据
            continue
        f_tmp.append(1)  # 设置偏置项
        for i in number:
            f_tmp.append(float(i))
        feature.append(f_tmp)
    f.close()
    return np.mat(feature)

def loadWeights(weights):
    '''
    加载权重值
    :param weights: 权重所在的文件位置
    :return: 权重矩阵
    '''
    f = open(weights)
    w = []
    for row in f.readlines():
        number = row.strip().split("\t")
        w_tmp = []
        for i in number:
            w_tmp.append(float(i))
        w.append(w_tmp)
    f.close()
    return np.mat(w)

def predict(feature, w):
    '''
    对测试数据进行预测
    :param feature: 测试数据的特征
    :param w: 权重
    :return: 预测结果
    '''
    sig = sigmoid(feature * w.T)
    n = np.shape(sig)[0]
    for i in range(n):
        if sig[i, 0] < 0.5:
            sig[i, 0] = 0.0
        else:
            sig[i, 0] = 1.0
    return sig

def saveResult(fileName, result):
    '''
    保存预测结果
    :param file_name: 结果文件名
    :param result: 结果值
    :return:
    '''
    m = np.shape(result)[0]
    res = []
    for i in range(m):
        res.append(str(result[i, 0]))
    f = open(fileName, "w")
    f.write("\t".join(res))
    f.close()

if __name__ == "__main__":
    path = "./data/"  # 数据集的存放路径
    w = loadWeights("weights")
    n = np.shape(w)[1]
    lr_test_data = loadFile(path + "test.txt", n)
    sig = predict(lr_test_data, w)
    saveResult("resultData", sig)

5、测试集分类如下图所示

        你们在此过程中遇到了什么问题,欢迎留言,让我看看你们都遇到了哪些问题。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

象在舞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值