机器学习(四)-多变量线性回归

1 多变量线性回归应用场景

目前为止,咱们探讨了单变量/特征的回归模型,如今咱们对房价模型增长更多的特征,例如房间数楼层等,构成一个含有多个变量的模型.。python

1.1 单变量线性回归案例

  • 模型: hθ(x) = θ0 + θ1x

在这里插入图片描述

1.2 多变量线性回归案例

在这里插入图片描述

  • 模型:

在这里插入图片描述

  • 新的概念

在这里插入图片描述
例如:算法

x(1) = [40, 1, 1, 10]
        x(2) = [96, 2, 1, 5]    
        x(3) = [135, 3, 2, 20]

在这里插入图片描述例如:dom

x(1)1 = 40
x(1)2 = 1
.......

2 多元梯度降低法

  • 模型:

在这里插入图片描述

  • 参数:

在这里插入图片描述

  • 损失函数:

在这里插入图片描述

  • 梯度降低公式(重复执行):

在这里插入图片描述

2.1 一元梯度降低n=1, 重复执行,直到收敛

在这里插入图片描述
在这里插入图片描述

2.2 多元梯度降低n>1

在这里插入图片描述

2.3 多元批梯度降低代码

import numpy as np

# 1). 模拟数据
X1 = 2 * np.random.randn(100, 1)
X2 = 4 * np.random.rand(100, 1)
X3 = 6 * np.random.rand(100, 1)
y = 4 + 3 * X1 + 4 * X2 + 5 * X3 + np.random.randn(100, 1)

#  2). 实现梯度降低算法
#  np.c_是将数据组合成向量格式: (n, 1) (n,1) = (n, 2)
X_b = np.c_[np.ones((100, 1)), X1, X2, X3]
# 初始化theta的值, 须要计算四个theta的值;
theta = np.random.randn(4, 1)
# 设置学习率和收敛次数
learning_rate = 0.1
n_iterations = 1000

# 根据公式计算
for iteration in range(n_iterations):
    # 梯度降低公式 = 1/样本数 * (预测值 - 真实值) *Xi
    gradients = 1 / 100 * X_b.T.dot(X_b.dot(theta) - y)
    # theta = theta - 学习率 * 梯度值
    theta = theta - learning_rate * gradients

print(theta)
  • 代码执行结果:

在这里插入图片描述

3 梯度降低法实践一:特征缩放

3.1 梯度降低法遇到的问题

在咱们面对多维特征问题的时候,咱们要保证这些特征都具备相近的尺度,这将帮助梯度降低算法更快地收敛。而特征缩放是为了确保特征在一个数量级上。 函数

以房价问题为例,假设咱们使用两个特征,房屋的尺寸和房间的数量,其中x1 = 房屋面积(0-400 m2), x2 = 卧室数量(1-5), 以两个参数分别为横纵坐标,绘制代价函数的等高线图能,看出图像会显得很扁,梯度降低算法须要很是屡次的迭代才能收敛。学习

在这里插入图片描述

3.2 解决方法

  • 解决方法一:测试

    • 尝试将全部特征的尺度都尽可能缩放到-1到1之间。好比:

x1 = 房屋面积 / 400
x2 = 卧室数量 / 5字体

在这里插入图片描述

  • 解决方法二: 平方均值法
    在原来的基础上把特征 xi 替换成 xi – μ;
    在这里插入图片描述

也能够把最大值换成标准差,或者最大值 – 最小值。优化

4 梯度降低法实践二: 学习率

4.1 梯度降低法遇到的问题

梯度降低算法收敛所须要的迭代次数根据模型的不一样而不一样,咱们不能提早预知,咱们能够绘制迭代次数和代价函数的图表来观测算法在什么时候趋于收敛。
在这里插入图片描述
梯度降低算法的每次迭代受到学习率的影响,spa

  • 若是学习率太小,则达到收敛所需的迭代次数会很是高;
  • 若是学习率过大,每次迭代可能不会减少代价函数,可能会越过局部最小值致使没法收敛。

4.2 解决方法

  • 自动测试是否收敛的方法,例如将代价函数的变化值与某个阀值(例如0.001)进行比较,但一般看上面这样的图表更好。

尝试在以下的数值中选择α : …, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1,…设计

5 梯度降低算法补充

5.1 三种梯度降低总结

如何选择?

  • 训练集比较小: 使用批梯度降低(小于2000个)
  • 训练集比较大:使用Mini-bitch梯度降低 通常的Mini-batch size 是64,128,256, 512,1024, Mini-batch size要适用CPU/GPU的内存

在这里插入图片描述

5.2 随机梯度降低

随机梯度降低思想:把m个样本分红m份,每次用1份作梯度降低;也就是说,当有m个样本时,批梯度降低只能作一次梯度降低,可是随机梯度降低能够作m次。

  • 实现代码
import numpy as np
import random
X = 2 * np.random.rand(100, 1)
Y = 4 + 3 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
# 每轮epochs处理m个样本;
n_epochs = 1000
# 学习率
a0 = 0.1
# 定义衰减率
decay_rate = 1

def learning_schedule(epoch_num):
    """
    定义一个学习率衰减的函数
    """
    return (1.0 / (decay_rate * epoch_num + 1)) * a0


# 初始化theta值
theta = np.random.randn(2, 1)

# 初始化随机值
num = [i for i in range(100)]
m = 100

for epoch in range(n_epochs):
    rand = random.sample(num, 100)
    for i in range(m):
        random_index = rand[i]
        xi = X_b[random_index:random_index + 1]
        yi = Y[random_index:random_index + 1]
        # 随机梯度降低值
        gradients = xi.T.dot(xi.dot(theta) - yi)
        # 学习率
        learning_rate = learning_schedule(epoch+1)
        theta = theta - learning_rate * gradients

print(theta)
  • 执行结果展现:

在这里插入图片描述

5.3 Mini-batch梯度算法

随机梯度降低会丧失向量带来的加速,因此咱们不会太用随机梯度降低。

  • 实现代码
import numpy as np
import random

X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
# print(X_b)

n_epochs = 500
a = 0.03
m = 100
num = [i for i in range(100)]



theta = np.random.randn(2, 1)
batch_num = 5
batch_size = m // 5

# epoch 是轮次的意思,意思是用m个样本作一轮迭代
for epoch in range(n_epochs):
    # 生成100个不重复的随机数
    for i in range(batch_num):
        start = i*batch_size
        end = (i+1)*batch_size
        xi = X_b[start:end]
        yi = y[start:end]
        gradients = 1/batch_size * xi.T.dot(xi.dot(theta)-yi)
        print(a)
        learning_rate = a
        theta = theta - learning_rate * gradients

print(theta)
  • 执行结果展现:

在这里插入图片描述

5.4 Mini-batch梯度算法优化: 学习率衰减

在作Mini-batch的时候,由于噪声的缘由,可能训练结果不是收敛的,而是在最低点周围晃动,若是咱们要解决这个问题,那咱们就须要减小学习率,让他在尽可能小的范围内晃动
1 epoch = 1 次遍历全部的数据

  • 学习率衰减公式:

在这里插入图片描述

  • 实现代码
import numpy as np
import random

X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
X_b = np.c_[np.ones((100, 1)), X]
# print(X_b)

n_epochs = 500
t0, t1 = 5, 50

m = 100
num = [i for i in range(100)]

def learning_schedule(t):
    return float(t0) / (t + t1)

theta = np.random.randn(2, 1)

batch_num = 5
batch_size = m // 5

# epoch 是轮次的意思,意思是用m个样本作一轮迭代
for epoch in range(n_epochs):
    # 生成100个不重复的随机数
    for i in range(batch_num):
        start = i*batch_size
        end = (i+1)*batch_size
        xi = X_b[start:end]
        yi = y[start:end]
        gradients = 1/batch_size * xi.T.dot(xi.dot(theta)-yi)
        learning_rate = learning_schedule(epoch*m + i)
        theta = theta - learning_rate * gradients

print(theta)
  • 执行结果展现:

在这里插入图片描述

6 特征和多项式回归

6.1 过拟合的问题

过拟合的问题出如今变量(θ)过多的时候,这时候咱们没有更多的数据去拟合模型,虽然损失函数的值基本接近于0。

在这里插入图片描述

6.2 过拟合的解决方法:

  • 减小特征的数量(通常不用)
    1)手动选择特征数
    2)模型选择
  • 正则化(特征缩放)
    保留全部特征,可是减小量级或者参数θ_j的大小

6.2 特征缩放

房价预测时, 假设咱们不知道房屋面积,可是知道房屋的长宽。

在这里插入图片描述

  • 模型设计:
    hθ(x) = θ0 + θ1 x 房屋的长度 + θ2 x 房屋的宽度
  • 特征未缩放图形展现

在这里插入图片描述

  • 特征缩放图形展现

在这里插入图片描述
注:若是咱们采用多项式回归模型,在运行梯度降低算法前,特征缩放很是有必要。

6.3 正则化

  • 如何不想要theta3和theta4?

在这里插入图片描述
首先, 咱们能够在损失函数中,加入关于theta3和theta4的项, 迫使若损失函数想要最小化, 必须让theta3和theta4尽量的小。
在这里插入图片描述

而后正则化, 公式以下图:

在这里插入图片描述

6.4 L1 正则和 L2 正则的区别

  • L1 会趋向于减小特征值
  • L2 会趋向于保留特征值

在这里插入图片描述

7 正则化算法与代码实现

7.1 Ridge(岭)回归

7.1.1 算法理解

在这里插入图片描述

7.1.2 实现公式

在这里插入图片描述

7.1.3 代码实现

  • 两种实现岭回归的方法:
"""
岭回归
方法一: 岭回归运用了L2正则化
"""
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.linear_model import SGDRegressor


X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)

# alpha是惩罚项里的alpha, solver处理数据的方法,auto是根据数据自动选择,svd是解析解,sag就是随机梯度降低
ridge_reg = Ridge(alpha=1, solver='auto')
# 学习过程
ridge_reg.fit(X, y)
# 预测
print(ridge_reg.predict([[1.5], [2], [2.5]]))
# 打印截距
print(ridge_reg.intercept_)
# 打印系数
print(ridge_reg.coef_)

"""
方法二: 岭回归和sgd & penalty=2是等价的
"""
sgd_reg = SGDRegressor(penalty='l2')
sgd_reg.fit(X, y.ravel())
print(sgd_reg.predict([[1.5], [2], [2.5]]))
# 打印截距
print("W0=", sgd_reg.intercept_)
# 打印系数
print("W1=", sgd_reg.coef_)

7.2 Lasso(拉索)回归

7.2.1 算法理解

在这里插入图片描述

7.2.2 实现公式

在这里插入图片描述

7.2.3 代码实现

"""
Lasso 回归

Lasso用的是l1的正则化
"""
import numpy as np
from sklearn.linear_model import Lasso
from sklearn.linear_model import SGDRegressor

X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)

lasso_reg = Lasso(alpha=0.15)
lasso_reg.fit(X, y)
print(lasso_reg.predict([[1.5]]))
print(lasso_reg.coef_)

sgd_reg = SGDRegressor(penalty='l1', n_iter=1000)
sgd_reg.fit(X, y.ravel())
print(sgd_reg.predict([[1.5]]))
print(sgd_reg.coef_)

7.3 Elastic Net回归

7.3.1 算法理解

在这里插入图片描述

7.3.2 实现公式

在这里插入图片描述

7.3.3 代码实现

import numpy as np
from sklearn.linear_model import ElasticNet

X = 2 * np.random.rand(100, 1)
Y = 4 + 3 * X + np.random.randn(100, 1)

elastic_reg = ElasticNet(alpha=0.15, l1_ratio=0.5)

elastic_reg.fit(X, Y)
print(elastic_reg.predict([[1.5]]))
print(elastic_reg.coef_)
print(elastic_reg.intercept_)


from sklearn.linear_model import SGDRegressor
elastic_reg = SGDRegressor(penalty='elasticnet')
elastic_reg.fit(X, Y)
print(elastic_reg.predict([[1.5]]))
print(elastic_reg.coef_)

8 正规方程和梯度降低比较

梯度降低:

  • 须要选择合适的α
  • 须要屡次迭代
  • 当n很大时,效果很好

正规方程:

  • 不须要选择学习率a
  • 不须要迭代
  • 须要计算X的转置乘X总体的逆
  • 当n很大时,计算很慢

总结:根据经验,当特征数量到10000的时候,是会换成梯度降低比较好

8.1 多项式回归的梯度降低代码

import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression

# 1). 数据准备;
# 样本数
m = 100
X = 6 * np.random.randn(m, 1) - 3
Y = 0.5 * X ** 2 + X + 2 + np.random.randn(m, 1)

# 2). 处理
# 2-1). 将一个高阶方程转化为一个一阶方程;(多元线性回归)
# degree:用几维处理数据;
poly_features = PolynomialFeatures(degree=2, include_bias=False)
# fit_transform === fit() + transform(), 其中transform就是用来作归一化的;
X_poly = poly_features.fit_transform(X, Y)

# 2-2). 处理一阶方程
line_reg = LinearRegression()
line_reg.fit(X_poly, Y)

print(line_reg.coef_)
print(line_reg.intercept_)

8.2 不一样维度绘制的图形

import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression

# 1). 数据准备;
# 样本数
m = 100
X = 6 * np.random.randn(m, 1) - 3
Y = 7 * X ** 2 + 5 *X + 2 + np.random.randn(m, 1)

# plt.plot(X, Y, 'b.')
# plt.show()


# 设置图像维度及线条的字体显示
d = {1: 'g-', 2: 'r.', 10: 'y*'}
# d = {2: 'g-'}


for i in d:
    # 2). 处理
    # 2-1). 将一个高阶方程转化为一个一阶方程;(多元线性回归)
    # degree:用几维处理数据;
    poly_features = PolynomialFeatures(degree=i, include_bias=False)
    # fit_transform === fit() + transform(), 其中transform就是用来作归一化的;
    X_poly = poly_features.fit_transform(X)
    print(X_poly)

    # 2-2). 处理一阶方程
    line_reg = LinearRegression()
    line_reg.fit(X_poly, Y)

    print(line_reg.coef_)
    print(line_reg.intercept_)

    y_predict = line_reg.predict(X_poly)
    plt.plot(X_poly[:, 0], y_predict, d[i])


plt.show()