Logistic回归算法及实现

Logistic回归可以被看成是一种概率估计。我们在每个特征上乘一个回归系数,然后所有值相加,总和带入sigmoid函数,得到一个0~1之间的数值,大于0.5的被分到1类,小于0.5的被分到0类别中。

一、理论基础

  • 用Logistic回归进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类。“回归”源于最佳拟合,表示要找到的最佳拟合参数。
  • 优点:计算代价不高,易于理解和实现
  • 缺点:易欠拟合,分类精度可能不高
  • 适用数据类型:数值型和标称型
  • sigmoid函数
    在这里插入图片描述
  • 梯度算子总是指向函数值变化最快的方向
  • 梯度上升算法伪代码:在这里插入图片描述

二、代码实现

2.1 加载数据
def load_dataset():
    """
    读取拟合数据集和标签
    :return: 数据集,标签
    """
    data_list = []
    label_list = []
    with open('./testSet.txt', 'r') as f:
        for line in f.readlines():
            line_data = line.strip().split()   # 去掉左右空格, 并按空格切分
            data_list.append([1.0, float(line_data[0]), float(line_data[1])])
            label_list.append(int(line_data[2]))
    return data_list, label_list
2.2 梯度上升算法
def sigmoid(data):
    """
    分类函数
    :param data: 输入数据
    :return: 分类概率
    """
    return 1.0 / (1 + np.exp(-data))


def grad_asent(data_list, label_list):
    """
    用梯度上升获取最佳拟合系数
    :param data_list: 数据列表
    :param label_list: 标签列表
    :return: 最佳拟合系数
    """
    data_mat = np.mat(data_list)
    label_mat = np.mat(label_list).transpose()
    r,c = np.shape(data_mat)
    alpha = 0.001
    max_cycle = 500
    weights = np.ones((c, 1))
    for i in range(max_cycle):
        h = sigmoid(data_mat * weights)
        loss = label_mat - h
        weights += alpha * data_mat.transpose() * loss
    return weights
2.3 随机梯度上升算法

算法的伪代码是:在这里插入图片描述

def stoc_grad_asent(data_list, label_list, num_iter=150):
    """
    随机梯度上升获取最佳拟合参数
    :param data_list: 数据矩阵
    :param label_list: 标签向量
    :return: 最佳拟合参数
    """
    data_mat = np.array(data_list)
    r, c = np.shape(data_mat)
    weights = np.ones(c)
    for j in range(num_iter):
        data_index = list(range(r))
        for i in range(r):
            alpha = 4 / (1.0+j+i)+0.01
            rand_index = int(random.uniform(0, len(data_index)))
            h = sigmoid(np.sum(data_mat[rand_index] * weights))
            error = label_list[rand_index] - h
            weights += alpha * error * data_mat[rand_index]
            del (data_index[rand_index])
    return weights

以上步长alpha每次迭代都会调整,这样会防止数据波动。

2.4 绘制最佳拟合曲线
def plot_best_fit(weights):
    """
    画最佳拟合曲线
    :param weights: 最优参数
    :return:
    """
    data_list, label_list = load_dataset()
    data_array = np.array(data_list)
    n = np.shape(data_list)[0]
    x1 = []
    y1 = []
    x2 = []
    y2 = []
    for i in range(n):
        if label_list[i] == 1:
            x1.append(data_array[i, 1])
            y1.append(data_array[i, 2])
        else:
            x2.append(data_array[i, 1])
            y2.append(data_array[i, 2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.scatter(x1, y1, s=30, c='red', marker='s')
    ax.scatter(x2, y2, s=30, c='green')
    x = np.arange(-3.0, 3.0, 0.1)
    y = (-weights[0] - weights[1]*x)/ weights[2]
    ax.plot(x, y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()
    
2.5 实际应用:预测病马死亡率
def colic_test():
    """`
    在训练集训练初最佳参数
    在测试集上获得错误率
    :return: 测试集上的错误率
    """
    train_set = []
    train_labels = []
    with open('./horseColicTraining.txt', 'r') as f:
        for line in f.readlines():
            current_line = line.strip().split('\t')
            line_list = []
            for i in range(21):
                line_list.append(float(current_line[i]))
            train_set.append(line_list)
            train_labels.append(float(current_line[21]))
    train_weights = stoc_grad_asent(np.array(train_set), train_labels, 500)
    error_count = 0
    num_test_vector = 0
    with open('horseColicTest.txt', 'r') as f:
        for line in f.readlines():
            num_test_vector += 1
            current_line = line.strip().split('\t')
            line_list = []
            for i in range(21):
                line_list.append(float(current_line[i]))
            if int(classify_vector(line_list, train_weights)) != int(current_line[21]):
                error_count += 1
        error_rate = float(error_count) / num_test_vector
        print("the error rate of this test is: %f" % error_rate)
    return error_rate

def main():
    num_test = 10
    error = [colic_test() for i in range(num_test)]
    print("after %d iterations the average rate is: %f" % (num_test, np.mean(error)))

if __name__ == '__main__':
    main()

输出结果为:

在这里插入图片描述
平均错误率为34%,这个结果并不差,因为有30%的数据缺失。
处理数据中缺失值的可选做法是:
1、使用可用特征的均值来填补缺失的值
2、使用特殊值来填补缺失值,比如-1
3、忽略有缺失值的样本
4、使用相似样本的均值填补缺失
5、使用另外的机器学习算法预测缺失
对于本例子中缺失值的做法是:当缺失值是特征是用0代替,当缺失值是标签时,直接去除改样例。

参考文献
  • Peter Harrington著,李锐,李鹏等译. 机器学习实战[M]. 人民邮电出版社.2018.1. p73-88

PS:代码中的数据集都是从参考文献所提供的代码中来的,有需要的伙伴可以留下邮箱,私发给你。
关于Logistic的理论推导参考https://www.jianshu.com/p/b2714426c971

END
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值