手记

逻辑回归手撸代码

本篇博客主要是逻辑回归的手撸代码,但是还有我的简单理解,用QW的形式描述。并不是逻辑回归的介绍,如有错误还望指出。

逻辑回归与线性回归关系

逻辑回归与线性回归同属于广义线性模型。逻辑回归就是用线性回归模型的预测值去拟合真实标记的对数几率。相当于在线性回归模型上加了一层非线性映射。

逻辑回归和线性回归就是得到一条直线。线性回归的直线是尽可能去拟合输入向量x的分布,使得训练集中所有样本点到直线的距离最短;而逻辑回归的直线是尽可能去拟合决策边界,使得训练集中的样本点尽可能分离开。因此他们的目的是不同的。

逻辑回归为什么用交叉熵损失函数,而不用平方损失函数

平方损失函数是线性回归假设样本误差服从高斯分布,利用极大似然估计推导而得;交叉熵损失函数是逻辑回归假设样本服从二项分布,利用极大似然估计推导而得。这是由于模型优化目标不同而推导得到不同的损失函数。

对于逻辑回归而言,交叉熵损失函数是凸函数,而平方损失函数不是凸函数。凸函数有着良好的优化性质,可以保证局部最优就是全局最优。而非凸函数,存在很多局部极小值,不宜优化。

交叉熵损失函数可以很好的衡量逻辑回归决策函数的好坏。

相对于其他分类算法,逻辑回归的优势

逻辑回归是对分类可能性建模,不需事先假设数据分布,避免了因假设不准确而带来的后果。

逻辑回归不仅可以预测类别,还可以得到近似的概率预测。

逻辑回归的对率函数是任意阶可导函数,数学性质好,易于优化。

代码如下:

import numpy as np
import matplotlib.pyplot as plt

import warnings
warnings.filterwarnings('ignore')

%matplotlib inline

#这里的数据是用的机器学习实战上的数据,其中也参考了上面的代码
data = []
label = []
for line in open('testSet.txt').readlines():
    tmpLine = line.strip().split()
    data.append([1.0, float(tmpLine[0]), float(tmpLine[1])])
    label.append(int(tmpLine[2]))
data = np.matrix(data)
label = np.matrix(label).transpose()

#定义sigmoid函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# 随机梯度下降
# data: 特征数据
# label: 标签
# alpha: 学习率
# epoch: 迭代次数
def SGD(data, label, alpha, epoch):
    m, n = np.shape(data)
    weights = np.ones((n, 1))
    for i in range(epoch):
        for j in np.random.permutation(m):
            h = sigmoid(np.dot(data[j], weights))
            error = h - label[j]
            weights = weights - (alpha * error * data[j]).transpose()
    return weights

# 批梯度下降
# data: 特征数据
# label: 标签
# alpha: 学习率
# epoch: 迭代次数
def BSG(data, label, alpha, epoch):
    m, n = np.shape(data)
    weights = np.ones((n, 1))
    for i in range(epoch):
        h = sigmoid(np.dot(data, weights))
        error = h - label
        weights = weights - np.dot(data.T, error) * alpha / m
    return weights

# 小批量梯度下降
# data: 特征数据
# label: 标签
# alpha: 学习率
# epoch: 迭代次数
# miniBatch: 一个小批量的大小
def miniBSG(data, label, alpha, epoch, miniBatch):
    m, n = np.shape(data)
    weights = np.ones((n, 1))
    for i in range(epoch):
        arr_reflash = np.random.permutation(m)
        miniBatch_arr = np.array_split(arr_reflash, miniBatch)
        for mini in miniBatch_arr:
            h = sigmoid(np.dot(data[mini], weights))
            error = h - label[mini]
            weights = weights - np.dot(data[mini].T, error) * alpha / miniBatch
    return weights

def plotLine(data, label, weights):
    m = np.shape(data)[0]
    x1 = []
    y1 = []
    x2 = []
    y2 = []
    for i in range(m):
        if(label[i] == 1):
            x1.append(data[i, 1])
            y1.append(data[i, 2])
        else:
            x2.append(data[i, 1])
            y2.append(data[i, 2])
    plt.figure(figsize=(10, 5))
    plt.scatter(x1, y1, c='r', marker='o')
    plt.scatter(x2, y2, c='g', marker='x')
    x = np.arange(-4, 4, 0.1)
    y = ((- weights[0] - weights[1] * x) / weights[2]).T
    plt.plot(x, y)
    plt.xlabel('X1')
    plt.ylabel('X2')

参考

统计学习方法 -李航

机器学习 -周志华

机器学习实战 -Peter Harrington

原文出处


0人推荐
随时随地看视频
慕课网APP