机器学习-线性回归算法

1、简单例子

数据:工资和年龄(2个特征)

目标:预测银行会贷款给我多少钱(标签)

考虑:工资和年龄都会影响最终银行贷款的结果那么它们各自有多大的影响呢?(参数)

工资年龄额度
40002520000
80003070000
50002835000
75003350000
120004085000

1.1、通俗解释

X1,X2就是我们的两个特征(年龄,工资)

Y是银行最终会借给我们多少钱

找到最合适的一条线(想象一个高维)来最好的拟合我们的数据点

2、数学公式

2.1、简单线性回归例子

假设\theta _{1}​是年龄的参数,\theta _{2}​是工资的参数

拟合的平面:​h_\theta(x)=\theta_0+\theta_1x_1+\theta_2x_2 (\theta_0​是偏置项)

整合:​h_\theta(x)=\sum_{i=0}^n\theta_ix_i=\theta^Tx

真实值和预测值之间肯定是要存在差异的(用​\varepsilon来表示该误差)

对于每个样本:

y^{(i)}=\theta^T x^{(i)} +\varepsilon^{(i)}

误差​\varepsilon^{(i)}是独立并且具有相同的分布,并且服从均值为0方差为​\theta^2 的高斯分布;

独立:张三和李四一起来贷款,他俩没关系;

同分布:他俩都来得是我们假定的这家银行;

高斯分布:银行可能会多给,也可能会少给,但是绝大多数情况下这个浮动不会太大,极小情况下浮动会比较大,符合正常情况.

2.2、线性回归最优解

预测值与误差:

y^{(i)}=\theta^{T}x^{(i)}+\varepsilon^{(i)}         (1)

由于误差服从高斯分布:

p(\varepsilon^{(i)})=\frac{1}{\sqrt{2\pi }\sigma}\exp \left( -\frac{(\varepsilon ^{(i)})^2}{2\sigma^{2}} \right)        (2)

将(1)式带入(2)式:

p(y^{(i)}|x^{(i)};\theta)=\frac{1}{\sqrt{2\pi }\sigma}\exp \left( -\frac{(y^{(i)}-\theta^{T}x^{(i)})^{2}}{2\sigma^{2}} \right)

似然函数:

L(\theta)=\prod_{i=1}^{m} p(y^{(i)}|x^{(i)};\theta) = \prod_{i=1}^{m} \frac{1}{\sqrt{2\pi }\sigma}\exp \left( -\frac{(y^{(i)}-\theta^{T}x^{(i)})^{2}}{2\sigma^{2}} \right)

解释:什么样的参数跟我们的数据组合后恰好是真实值

对数似然:

\log L(\theta) = \log \prod_{i=1}^{m} \frac{1}{\sqrt{2\pi }\sigma}\exp \left( -\frac{(y^{(i)}-\theta^{T}x^{(i)})^{2}}{2\sigma^{2}} \right)

解释:乘法难解,加法就容易了,对数里面乘法可以转换成加法

展开化简:

\begin{aligned} & \sum_{i=1}^{m} \log \frac{1}{\sqrt{2\pi }\sigma}\exp \left( -\frac{(y^{(i)}-\theta^{T}x^{(i)})^{2}}{2\sigma^{2}} \right) \\ =& m \log \frac{1}{ \sqrt{2\pi} \sigma}- \frac{1}{ \sigma^{2} }\cdot \frac{1}{2} \sum_{i=1}^{n} (y^{(i)}-\theta^{T}x^{(i)})^{2} \end{aligned}

目标:让似然函数(对数变换后也一样)越大越好(最小二乘法)

J(\theta)=\frac{1}{2} \sum_{i=1}^{n} (y^{(i)}-\theta^{T}x^{(i)})^{2}

目标函数:

J(\theta)=\frac{1}{2} \sum_{i=1}^{n} (h_{\theta}(x^{(i)}) - y^{(i)})^{2} = \frac{1}{2}(X\theta - y)^{T} (X\theta - y)

求偏导:

\begin{aligned} \bigtriangledown _{\theta} J(\theta) &= \bigtriangledown _{\theta} \left( \frac{1}{2}(X\theta - y)^{T} (X\theta - y) \right)\\ &= \bigtriangledown _{\theta} \left( \frac{1}{2} ({\theta}^{T} X^{T} - y^{T}) (X\theta - y) \right)\\ &= \bigtriangledown _{\theta} \left( \frac{1}{2} ( {\theta}^{T} X^{T} X\theta - {\theta}^{T} X^{T}y - y^{T}X\theta + y^{T}y ) \right)\\ &= \frac{1}{2} \left( 2X^{T} X\theta - X^{T}y - (y^{T}X)^{T} \right)\\ &= X^{T} X\theta - X^{T}y \end{aligned}

偏导等于0: \theta=(X^{T}X)^{-1}X^{T}y

2.3、评估方法

最常用的评估项R^{2}:

1- \frac{ \sum_{i=1}^{m}(\hat{y}_i - y_{i})^{2} }{ \sum_{i=1}^{m}( y_{i} - \bar{y}_i )^{2} }

其中\sum_{i=1}^{m}(\hat{y}_i - y_{i})^{2}​为 残差平方和

\sum_{i=1}^{m}( y_{i} - \bar{y}_i )^{2}​为 类似方差项

R^{2}​的取值越接近于1我们认为模型拟合的越好

2.4、梯度下降

2.4.1、梯度下降的解释

引入:当我们得到了一个目标函数后,如何进行求解?

直接求解?(并不一定可解,线性回归可以当做是一个特例

常规套路:机器学习的套路就是我交给机器一堆数据,然后告诉它什么样的学习方式是对的(目标函数),然后让它朝着这个方向去做;

如何优化:一口吃不成个胖子,我们要静悄悄的一步步的完成迭代(每次优化一点点,累积起来就是个大成绩了)

目标函数:​J({\theta}_{0},{\theta}_{1})=\frac{1}{2m} \sum_{i=1}^{m} \left( h_{\theta}(x^{(i)}) - y^{(i)} \right) ^{2}

目标函数也是损失函数,即需要预测的结果和实际结果的差值尽量的小。

公式里的1/2对损失函数没有影响,只是为了能抵消求导后的乘数2。

寻找山谷的最低点,也就是我们的目标函数终点(什么样的参数能使得目标函数达到极值点)

下山分几步走呢?(更新参数)

(1):找到当前最合适的方向

(2):走那么一小步,走快了该”跌倒 ”了

(3):按照方向与步伐去更新我们的参数

2.4.2、线性回归使用梯度下降

梯度下降,目标函数: J(\theta)=\frac{1}{2m} \sum_{i=1}^{m} \left( y^{(i)} - h_{\theta}(x^{(i)}) \right) ^{2}

批量梯度下降:

\begin{aligned} \frac{ \partial J(\theta) }{\partial {\theta}_j} = -\frac{1}{m} \sum_{i=1}^{m}( y^{(i)} - h_{\theta}(x^{(i)}) )x_{j}^{i} \end{aligned}

当步长\alpha=-1为​时:

{\theta}_{j} = {\theta}_{j} +\frac{1}{m} \sum_{i=1}^{m}( y^{(i)} - h_{\theta}(x^{(i)}) )x_{j}^{i}

(容易得到最优解,但是由于每次考虑所有样本,速度很慢)

随机梯度下降:

{\theta}_{j} = {\theta}_{j} + ( y^{(i)} - h_{\theta}(x^{(i)}) )x_{j}^{i}

(每次找一个样本,迭代速度快,但不一定每次都朝着收敛的方向)

小批量梯度下降法:

{\theta}_{j} = {\theta}_{j} -\alpha \frac{1}{10} \sum_{k=i}^{i+9}( h_{\theta}(x^{(k)}) - y^{(k)} )x_{j}^{k}

(每次更新选择一小部分数据来算,实用!

2.4.3、步长和批量选取

批处理数量:一次性取32,64,128都可以,很多时候还得考虑内存和效率

学习率(步长):对结果会产生巨大的影响,一般取数要小一些

如何选择:从小的数开始,不行再小

3、代码(Python)

3.1、使用Scikit-learn库

直接使用Python的Scikit-learn库来实现是最方便的,也是性能很优秀的的方式。

以下是使用Python的Scikit-learn库实现线性回归的代码示例:

from sklearn.linear_model import LinearRegression

# 创建线性回归模型对象
lr_model = LinearRegression()

# 准备训练数据
X_train = [[1, 2], [3, 4], [5, 6]]
y_train = [3, 7, 11]

# 训练模型
lr_model.fit(X_train, y_train)

# 使用模型进行预测
X_test = [[7, 8], [9, 10]]
y_pred = lr_model.predict(X_test)

# 打印预测结果
print(y_pred)

3.2、自己手写线性回归

一般实际使用还是推荐直接应用现有的Scikit-learn库来实现,手写是用于学习。

这里的例子用的是单个特征的线性回归算法

①主函数类

from typing import Any

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pandas import DataFrame

from linear_regression import LinearRegression
# 单变量线性回归

# 读取csv文件,这里自动去除了表头
data: DataFrame = pd.read_csv('../data/world-happiness-report-2017.csv')

# 得到训练和测试数据
train_data: DataFrame = data.sample(frac = 0.8)
test_data = data.drop(train_data.index)

# 选取对应的字段用来做x,y
input_param_name = 'Economy..GDP.per.Capita.'
output_param_name = 'Happiness.Score'

x_train = train_data[[input_param_name]].values
y_train = train_data[[output_param_name]].values

x_test = test_data[input_param_name].values
y_test = test_data[output_param_name].values

# scatter:散布在各处,这里是指画散点图
plt.scatter(x_train,y_train,label='Train data')
plt.scatter(x_test,y_test,label='test data')
plt.xlabel(input_param_name)
plt.ylabel(output_param_name)
plt.title('Happy')
# legend:图例。用于显示上面 label 的内容,不写会报错
plt.legend()
plt.show()

#最大迭代次数
num_iterations = 500
# 学习率,即当误差为小于0.01时训练结束
learning_rate = 0.01

linear_regression = LinearRegression(x_train,y_train)
(theta,cost_history) = linear_regression.train(learning_rate,num_iterations)

print ('开始时的损失:',cost_history[0])
print ('训练后的损失:',cost_history[-1])

# 画线性图
plt.plot(range(num_iterations),cost_history)
plt.xlabel('Iter')
plt.ylabel('cost')
plt.title('GD')
# plt.show()前可加多个plt.plot(),画在同一张图上
plt.show()

predictions_num = 100
# 类似用法:np.linspace(start = 0, stop = 100, num = 5)
# 得到array([ 0., 25., 50., 75., 100.])
x_predictions = np.linspace(x_train.min(),x_train.max(),predictions_num).reshape(predictions_num,1)
y_predictions = linear_regression.predict(x_predictions)

plt.scatter(x_train,y_train,label='Train data')
plt.scatter(x_test,y_test,label='test data')
plt.plot(x_predictions,y_predictions,'r',label = 'Prediction')
plt.xlabel(input_param_name)
plt.ylabel(output_param_name)
plt.title('Happy')
plt.legend()
plt.show()

②线性回归类 LinearRegression

import numpy as np
from utils.features import prepare_for_training

class LinearRegression:

    def __init__(self,data,labels,normalize_data=True):
        """
        1.对数据进行预处理操作
        2.先得到所有的特征个数
        3.初始化参数矩阵
        """
        (data_processed,
         features_mean, 
         features_deviation)  = prepare_for_training(data, normalize_data=True)
         
        self.data = data_processed
        self.labels = labels
        self.features_mean = features_mean
        self.features_deviation = features_deviation
        self.normalize_data = normalize_data
        
        num_features = self.data.shape[1]
        self.theta = np.zeros((num_features,1))
        
    def train(self,alpha,num_iterations = 500):
        """
                    训练模块,执行梯度下降
        """
        cost_history = self.gradient_descent(alpha,num_iterations)
        return self.theta,cost_history
        
    def gradient_descent(self,alpha,num_iterations):
        """
                    实际迭代模块,会迭代num_iterations次
        """
        cost_history = []
        for _ in range(num_iterations):
            self.gradient_step(alpha)
            cost_history.append(self.cost_function(self.data,self.labels))
        return cost_history
        
        
    def gradient_step(self,alpha):    
        """
                    梯度下降参数更新计算方法,注意是矩阵运算
        """
        num_examples = self.data.shape[0]
        prediction = LinearRegression.hypothesis(self.data,self.theta)
        delta = prediction - self.labels
        theta = self.theta
        theta = theta - alpha*(1/num_examples)*(np.dot(delta.T,self.data)).T
        self.theta = theta
        
        
    def cost_function(self,data,labels):
        """
                    损失计算方法
        """
        num_examples = data.shape[0]
        delta = LinearRegression.hypothesis(self.data,self.theta) - labels
        cost = (1/2)*np.dot(delta.T,delta)/num_examples
        return cost[0][0]
        
        
        
    @staticmethod
    def hypothesis(data,theta):   
        # np.dot:乘法
        predictions = np.dot(data,theta)
        return predictions
        
    def get_cost(self,data,labels):  
        data_processed = prepare_for_training(data,
         self.normalize_data
         )[0]
        
        return self.cost_function(data_processed,labels)
    def predict(self,data):
        """
                    用训练的参数模型,与预测得到回归值结果
        """
        data_processed = prepare_for_training(data,
         self.normalize_data
         )[0]
         
        predictions = LinearRegression.hypothesis(data_processed,self.theta)
        
        return predictions

③数据处理 prepare_for_training.py

"""Prepares the dataset for training"""

import numpy as np
# . 表示导入当前文件夹下的包
from .normalize import normalize


def prepare_for_training(data, normalize_data=True):

    # 计算样本总数
    num_examples = data.shape[0]

    data_processed = np.copy(data)

    # 预处理
    features_mean = 0
    features_deviation = 0
    data_normalized = data_processed
    if normalize_data:
        (
            data_normalized,
            features_mean,
            features_deviation
        ) = normalize(data_processed)

        data_processed = data_normalized


    # 加一列1
    # np.hstack:水平(按列顺序)把数组给堆叠起来,vstack()函数正好和它相反
    data_processed = np.hstack((np.ones((num_examples, 1)), data_processed))

    return data_processed, features_mean, features_deviation

④初始化参数矩阵 normalize

"""Normalize features"""

import numpy as np


def normalize(features):

    features_normalized = np.copy(features).astype(float)

    # 计算均值
    # axis=0,计算每一列的均值
    # axis=1,计算每一行的均值
    features_mean = np.mean(features, 0)

    # 计算标准差
    features_deviation = np.std(features, 0)

    # 标准化操作
    # shape函数:返回行数和列数
    if features.shape[0] > 1:
        features_normalized -= features_mean

    # 防止除以0
    features_deviation[features_deviation == 0] = 1
    features_normalized /= features_deviation

    return features_normalized, features_mean, features_deviation

⑤运行结果

训练数据和测试数据

 训练过程中的损失值

 训练结果

 4、想法

        线性回归是机器学习中非常简单的一种算法,可以用来入门学习了解机器学习,少有的可以完全由自己手写代码的算法。

        最后,觉得有帮助或者有点收获的话,帮忙点个赞吧!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值