手搓线性回归

Posted 湖工商梁朝伟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手搓线性回归相关的知识,希望对你有一定的参考价值。

上课的时候的一个实验,闲得无聊把3维的线性回归矩阵化,以便以后可以对几百几千维的数据也可以使用该算法(虽然直接sklearn更快),但毕竟是手搓出来的用起来好玩一点点。

线性回归原理如下(原理很简单,字是鬼画符,不看也罢):

 

注:这里只是回归,不是分类。多分类的问题的话需要训练多组参数W和b,用softmax进行分类,其结构就类似没有隐藏层只有输出层的神经网络。这里就懒得弄了。

鸢尾花数据集链接如下:

链接:https://pan.baidu.com/s/1Lm5oKDfnnFGvWycuF9D1PA 
提取码:1234

具体代码如下,注释有详细介绍:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.preprocessing import LabelEncoder  # 处理鸢尾花数据的


def compute_error(b, W, points):
    '''
    计算损失,这里采用简单的(y-y^hat)**2这一损失函数
    :param b: 偏差b,一个标量,
    :param W: 形状是(n, 1),对应鸢尾花数据集的话是(4, 1)
    :param points:
    :return:
    '''
    total_error = 0
    # 遍历每一个数据集,计算总损失
    for i in range(0, len(points)):
        X = points[i:i + 1, 0:4].T  # X的维度是(4, 1)
        y = points[i, 4]

        total_error += (y - (np.dot(W.T, X)[0, 0]+b))**2
    # 平均损失
    return total_error / float(len(points))

def gradient(b_current, W_current, points, learning_rate):
    '''
    梯度下降算法
    :param b_current: 上一步的b
    :param W_current: 上一步的W,形状是(4, 1)
    :param points: 传入的数据集矩阵
    :param learning_rate: 学习率
    :return:new_b, new_W
    '''
    b_gradient = 0
    W_gradient = np.zeros((4, 1))
    cnt = float(len(points))

    for i in range(0, len(points)):
        X = points[i:i+1, 0:-1].T  # shape: (4, 1)
        y = points[i, -1]  # y是个标量
        # 损失函数(y-y^hat)**2对标量b和向量W求偏导得它们的梯度
        b_gradient += (2 / cnt) * ((np.dot(W_current.T, X)[0, 0] + b_current) - y)
        W_gradient += (2 / cnt) * ((np.dot(W_current.T, X)[0, 0]+b_current)-y) * X

    # 梯度下降发更新参数
    new_W = W_current - (learning_rate * W_gradient)
    new_b = b_current - (learning_rate * b_gradient)

    return new_b, new_W

def lr(points, starting_b, starting_W, learning_rate, num_iterations):
    '''
    线性回归模型
    :param points:
    :param starting_b: 1个标量
    :param starting_W: W参数向量,这里shape是(4, 1)
    :param learning_rate:学习率
    :param num_iterations:迭代次数
    :return:
    '''
    b = starting_b
    W = starting_W
    # update for several times
    for i in range(num_iterations):
        b, W = gradient(b, W, np.array(points), learning_rate)
        print('第{}次 损失:{}'.format(i+1, compute_error(b, W, points)))
    return b, W


def main():
    # 处理数据
    df_data = pd.read_csv('Iris.csv')
    non_numeric_features = ["Species"]
    for feature in non_numeric_features:
        df_data[feature] = LabelEncoder().fit_transform(df_data[feature])

    x = df_data.iloc[:, 1:5]
    y = df_data.iloc[:, 5:]
    print(type(x))
    points = np.hstack((x, y))  # points是鸢尾花数据集,其shape:(n, 5),最后一列是标签y
    # print(points)

    x_shape = points[:, :-1].shape  # (n, 特征数),这里是(n, 4)
    learning_rate = 0.001
    initial_b = 2  # 初始化b参数shape (4, 1)
    initial_W = np.zeros((x_shape[1], 1))  # 初始化W参数shape (4, 1)
    num_iterations = 1000

    print("Running...")
    b, W = lr(points, initial_b, initial_W, learning_rate, num_iterations)
    print('最终损失:{}'.format(compute_error(b, W, points)))


if __name__ == '__main__':
    main()

 

OKK!

以上是关于手搓线性回归的主要内容,如果未能解决你的问题,请参考以下文章

线性回归详解(代码实现+理论证明)

线性回归详解(代码实现+理论证明)

机器学习入门 ----线性回归模型及其Python代码解析

线性回归模型|机器学习

Python应用实战线性回归(附Python代码)

如何用matlab线性回归分析?