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

29次阅读

共计 6883 个字符,预计需要花费 18 分钟才能阅读完成。

1 多变量线性回归应用场景
目前为止,我们探讨了单变量 / 特征的回归模型,现在我们对房价模型增加更多的特征,例如房间数楼层等,构成一个含有多个变量的模型.。
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]

例如:
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×2 = 卧室数量 / 5

解决方法二:平方均值法在原来的基础上把特征 xi 替换成 xi – μ;

也可以把最大值换成标准差,或者最大值 – 最小值。
4 梯度下降法实践二: 学习率
4.1 梯度下降法遇到的问题
梯度下降算法收敛所需要的迭代次数根据模型的不同而不同,我们不能提前预知,我们可以绘制迭代次数和代价函数的图表来观测算法在何时趋于收敛。梯度下降算法的每次迭代受到学习率的影响,

如果学习率过小,则达到收敛所需的迭代次数会非常高;
如果学习率过大,每次迭代可能不会减小代价函数,可能会越过局部最小值导致无法收敛。

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()

正文完
 0