1、多元线性回归

1.1 概念

线性回归是机器学习中有监督机器学习下的一种算法。 回归问题主要关注的是因变量(需要预测的值,可以是一个也可以是多个)和一个 或多个数值型的自变量(预测变量)之间的关系。

需要预测的值:即目标变量,target,y,连续值预测变量。

影响目标变量的因素: ... ,可以是连续值也可以是离散值。

因变量和自变量之间的关系:即模型,model,是我们要求解的。

1.2、简单线性回归

1.3、最优解

Actual value:真实值,一般使用 y 表示。
Predicted value:预测值,是把已知的 x 带入到公式里面和猜出来的参数 w,b 计算得到的,一般使用 表示。

Error:误差,预测值和真实值的差距,一般使用 表示。

最优解:尽可能的找到一个模型使得整体的误差最小,整体的误差通常叫做损失 Loss。

Loss:整体的误差,Loss 通过损失函数 Loss function 计算得到。

2、正规方程

2.1 最小二乘法矩阵表示

X = np.array([[1,1],[2,-1]])
X
array([[ 1,  1],
       [ 2, -1]])
y = np.array([14,10])
y

array([14, 10])

# linalg 线性代数,slove计算线性回归问题
np.linalg.solve(X,y)

array([8., 6.])

2.2 矩阵转置公式与求导公式

2.3 推导正规方程\theta的解

2.4 凸函数判定

3、线性回归算法推导

3.1 深入理解回归

回归简单来说就是“回归平均值”(regression to the mean)。但是这里的 mean 并不是把 历史数据直接当成未来的预测值,而是会把期 望值当作预测值。 追根溯源回归这个词是一个叫高尔顿的人发明的,他通过大量观察数据发现:父亲比较高,儿子也比较高;父亲比较矮,那 么儿子也比较矮!正所谓“龙生龙凤生凤老鼠的儿子会打洞”!但是会存在一定偏差~

父亲是 1.98,儿子肯定很高,但有可能不会达到1.98

父亲是 1.69,儿子肯定不高,但是有可能比 1.69 高

大自然让我们回归到一定的区间之内,这就是大自然神奇的力量。

高尔顿是谁?达尔文的表弟,这下可以相信他说的十有八九是对的了吧!

人类社会很多事情都被大自然这种神奇的力量只配置:身高、体重、智商、相貌......

3.2 误差分析

3.3 最大似然估计

最大似然估计(maximum likelihood estimation, MLE)一种重要而普遍的求估计量的方法。最大似然估计明确地使用概率模型,其目标是寻找能够以较高概率产生观察数据的系统发生树。最大似然估计是一类完全基于统计的系统发生树重建方法的代表。

是不是,有点看不懂,太学术了,我们举例说明~

假如有一个罐子,里面有黑白两种颜色的球,数目多少不知,两种颜色的比例也不知。我们想知道罐中白球和黑球的比例,但我们不能 把罐中的球全部拿出来数。现在我们可以每次任意从已经摇匀的罐中拿一个球出来,记录球的颜色,然后把拿出来的球再放回罐中。这个过 程可以重复,我们可以用记录的球的颜色来估计罐中黑白球的比例。假如在前面的一百次重复记录中,有七十次是白球,请问罐中白球所占 的比例最有可能是多少?

3.4、高斯分布-概率密度函数

3.5、误差总似然

3.6、最小二乘法MSE

3.7、归纳总结升华

这种最小二乘法估计,其实我们就可以认为,假定了误差服从正太分布,认为样本误差的出现是随机的,独立的,使用最大似然估计思 想,利用损失函数最小化 MSE 就能求出最优解!所以反过来说,如果我们的数据误差不是互相独立的,或者不是随机出现的,那么就不适合 去假设为正太分布,就不能去用正太分布的概率密度函数带入到总似然的函数中,故而就不能用 MSE 作为损失函数去求解最优解了!所以, 最小二乘法不是万能的~

  还有譬如假设误差服从泊松分布,或其他分布那就得用其他分布的概率密度函数去推导出损失函数了。
  所以有时我们也可以把线性回归看成是广义线性回归。比如,逻辑回归,泊松回归都属于广义线性回归的一种,这里我们线性回归可以说是最小二乘线性回归。

4、机器学习库scikit-learn

4.1 scikit-learn简介

https://scikit-learn.org/stable/index.html

4.2 scikit-learn实现简单线性回归

from sklearn.linear_model

import LinearRegression

import numpy as np
import matplotlib.pyplot as plt
# 转化成矩阵

X = np.linspace(0,10,num = 30).reshape(-1,1) # 斜率和截距,随机生成
w = np.random.randint(1,5,size = 1)
b = np.random.randint(1,10,size = 1)

# 根据一元一次方程计算目标值y,并加上“噪声”,数据有上下波动~ y = X * w + b + np.random.randn(30,1) plt.scatter(X,y)
# 使用scikit-learn中的线性回归求解

model = LinearRegression() model.fit(X,y)
w_ = model.coef_
b_ = model.intercept_

print('一元一次方程真实的斜率和截距是:',w, b)

print('通过scikit-learn求解的斜率和截距是:',w_,b_)

plt.plot(X,X.dot(w_) + b_,color = 'green')

4.3 scikit-learn实现多元线性回归

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D
# 转化成矩阵
x1 = np.random.randint(-150,150,size = (300,1))
x2 = np.random.randint(0,300,size = (300,1))
# 斜率和截距,随机生成
w = np.random.randint(1,5,size = 2)
b = np.random.randint(1,10,size = 1)
# 根据二元一次方程计算目标值y,并加上“噪声”,数据有上下波动~
y = x1 * w[0] + x2 * w[1] + b + np.random.randn(300,1)
fig = plt.figure(figsize=(9,6))
ax = Axes3D(fig)
ax.scatter(x1,x2,y) # 三维散点图
ax.view_init(elev=10, azim=-20) # 调整视角
# 重新构造X,将x1、x2以及截距b,相当于系数w0,前面统一乘以1进行数据合并 X = np.concatenate([x1,x2],axis = 1)
# 使用scikit-learn中的线性回归求解
model = LinearRegression()
model.fit(X,y)
w_ = model.coef_.reshape(-1)
b_ = model.intercept_ print('二元一次方程真实的斜率和截距是:',w,b) print('通过scikit-learn求解的斜率和截距是:',w_,b_)
# # 根据求解的斜率和截距绘制线性回归线型图
x = np.linspace(-150,150,100)
y = np.linspace(0,300,100)
z = x * w_[0] + y * w_[1] + b_
ax.plot(x,y,z ,color = 'green')

5、梯度下降

5.1 线性回归房价预测

5.2 无约束最优化问题

import numpy as np
import matplotlib.pyplot as plt
f = lambda x : (x - 3.5)**2 -4.5*x + 10
# 导函数
d = lambda x :2*(x - 3.5) - 4.5 # 梯度 == 导数
# 梯度下降的步幅,比例,(学习率,幅度)
step = 0.1
# 求解当x等于多少的时候,函数值最小。求解目标值:随机生成的
# 相等于:'瞎蒙' ----> 方法 ----> 优化
x = np.random.randint(0,12,size = 1)[0]
# 梯度下降,每下降一步,每走一步,目标值,都会更新。
# 更新的这个新值和上一步的值,差异,如果差异很小(万分之一)
# 梯度下降退出
last_x = x + 0.02 # 记录上一步的值,首先让last_x和x有一定的差异!!! # 精确率,真实计算,都是有误差,自己定义
precision = 1e-4
print('+++++++++++++++++++++', x)
x_ = [x]
while True:

# 退出条件,精确度,满足了
if np.abs(x - last_x) < precision:

break

# 更新
last_x = x
x -= step*d(x) # 更新,减法:最小值 x_.append(x) print('--------------------',x)

# 数据可视化
plt.rcParams['font.family'] = 'Kaiti SC' plt.figure(figsize=(9,6))
x = np.linspace(5.75 - 5, 5.75 + 5, 100)
y = f(x)
plt.plot(x,y,color = 'green') plt.title('梯度下降',size = 24,pad = 15)
x_ = np.array(x_)
y_ = f(x_)
plt.scatter(x_, y_,color = 'red') plt.savefig('./图片/5-梯度下降.jpg',dpi = 200)

函数的最优解是:5.75。你可以发现,随机赋值的变量 x ,无论大于5.75,还是小于5.75,经过梯度下降,最终都慢慢靠近5.75这个最优 解!

5.3 梯度下降的方法

5.4 代码实战梯度下降

5.4.1 批量梯度下降BGD

import numpy as np

# 1、创建数据集X,y
X = np.random.rand(100, 1)
w,b = np.random.randint(1,10,size = 2)
y = w * X + b + np.random.randn(100, 1)

# 2、使用偏置项x_0 = 1,更新X
X = np.c_[X,np.ones((100, 1))]

# 3、创建超参数轮次 epoches = 10000

# 4、定义一个函数来调整学习率

t0, t1 = 5, 1000
def learning_rate_schedule(t):

return t0/(t+t1)


# 5、初始化 W0...Wn,标准正太分布创建W

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

# 6、判断是否收敛,一般不会去设定阈值,而是直接采用设置相对大的迭代次数保证可以收敛 for i in range(epoches):

# 根据公式计算梯度
g = X.T.dot(X.dot(θ) - y)
# 应用梯度下降的公式去调整 θ 值
learning_rate = learning_rate_schedule(i) θ = θ - learning_rate * g

print('真实斜率和截距是:',w,b) print('梯度下降计算斜率和截距是:',θ)

import numpy as np

# 1、创建数据集X,y
X = np.random.rand(100, 3)
w = np.random.randint(1,10,size = (3,1))
b = np.random.randint(1,10,size = 1)
y = X.dot(w) + b + np.random.randn(100, 1)

# 2、使用偏置项x_0 = 1,更新X
X = np.c_[X,np.ones((100, 1))]

# 3、创建超参数轮次 epoches = 10000

# 4、定义一个函数来调整学习率
t0, t1 = 5, 500
def learning_rate_schedule(t):

return t0/(t+t1)


# 5、初始化 W0...Wn,标准正太分布创建W

θ = np.random.randn(4, 1)

# 6、判断是否收敛,一般不会去设定阈值,而是直接采用设置相对大的迭代次数保证可以收敛 for i in range(epoches):

# 根据公式计算梯度
g = X.T.dot(X.dot(θ) - y)
# 应用梯度下降的公式去调整 θ 值
learning_rate = learning_rate_schedule(i) θ = θ - learning_rate * g

print('真实斜率和截距是:',w,b) print('梯度下降计算斜率和截距是:',θ)

5.4.2 随机梯度下降SGD

import numpy as np

# 1、创建数据集X,y
X = 2*np.random.rand(100, 1)
w,b = np.random.randint(1,10,size = 2)

y = w * X + b + np.random.randn(100, 1)

# 2、使用偏置项x_0 = 1,更新X
X = np.c_[X, np.ones((100, 1))]

# 3、创建超参数轮次、样本数量 epochs = 10000
n = 100

# 4、定义一个函数来调整学习率
t0, t1 = 5, 500
def learning_rate_schedule(t):

return t0/(t+t1)


# 5、初始化 W0...Wn,标准正太分布创建W

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

# 6、多次for循环实现梯度下降,最终结果收敛

for epoch in range(epochs):

        

        # 在双层for循环之间,每个轮次开始分批次迭代之前打乱数据索引顺序 index =         np.arange(n) # 0 ~99
        np.random.shuffle(index)

        

        X = y = for

        X[index] # 打乱顺序 y[index]
        i in range(n):

                

                y_i = y[[i]]
                g = X_i.T.dot(X_i.dot(θ)-y_i)
                learning_rate = learning_rate_schedule(epoch*n + i) θ = θ - learning_rate * g

print('真实斜率和截距是:',w,b)

print('梯度下降计算斜率和截距是:',θ)

import numpy as np

# 1、创建数据集X,y
X = 2*np.random.rand(100, 5)
w = np.random.randint(1,10,size = (5,1))
b = np.random.randint(1,10,size = 1)
y = X.dot(w) + b + np.random.randn(100, 1)

# 2、使用偏置项x_0 = 1,更新X
X = np.c_[X, np.ones((100, 1))]

# 3、创建超参数轮次、样本数量 epochs = 10000
n = 100

# 4、定义一个函数来调整学习率
t0, t1 = 5, 500
def learning_rate_schedule(t):

return t0/(t+t1)


# 5、初始化 W0...Wn,标准正太分布创建W

θ = np.random.randn(6, 1)

# 6、多次for循环实现梯度下降,最终结果收敛

for epoch in range(epochs):

        # 在双层for循环之间,每个轮次开始分批次迭代之前打乱数据索引顺序 index =         np.arange(n) # 0 ~99
        np.random.shuffle(index)

        X = y = for

        X[index] # 打乱顺序

        y[index]
        i in range(n):
                X_i = X[[i]]

                y_i = y[[i]]
                g = X_i.T.dot(X_i.dot(θ)-y_i)
                learning_rate = learning_rate_schedule(epoch*n + i) θ = θ - learning_rate * g

print('真实斜率和截距是:',w,b)

print('梯度下降计算斜率和截距是:',θ)

5.4.3 小批量梯度下降MBGD

import numpy as np

# 1、创建数据集X,y
X = np.random.rand(100, 1)
w,b = np.random.randint(1,10,size = 2) y = w * X + b + np.random.randn(100, 1)

# 2、使用偏置项x_0 = 1,更新X
X = np.c_[X, np.ones((100, 1))]

# 3、定义一个函数来调整学习率
t0, t1 = 5, 500
def learning_rate_schedule(t):

return t0/(t+t1)

# 4、创建超参数轮次、样本数量、小批量数量 epochs = 100
n = 100
batch_size = 16

num_batches = int(n / batch_size) # 5、初始化 W0...Wn,标准正太分布创建W

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

# 6、多次for循环实现梯度下降,最终结果收敛

for epoch in range(epochs):

        # 在双层for循环之间,每个轮次开始分批次迭代之前打乱数据索引顺序

        index = np.arange(n) np.random.shuffle(index)
        X = X[index]
        y = y[index]
        for i in range(num_batches):

        

                # 一次取一批数据16个样本
                X_batch = X[i * batch_size : (i + 1)*batch_size]

                y_batch = y[i * batch_size : (i + 1)*batch_size]
                g = X_batch.T.dot(X_batch.dot(θ)-y_batch)

                learning_rate = learning_rate_schedule(epoch * n + i)

                θ = θ - learning_rate * g

print('真实斜率和截距是:',w,b)

print('梯度下降计算斜率和截距是:',θ)

import numpy as np

# 1、创建数据集X,y
X = np.random.rand(100, 3)
w = np.random.randint(1,10,size = (3,1))
b = np.random.randint(1,10,size = 1)
y = X.dot(w) + b + np.random.randn(100, 1)

# 2、使用偏置项 X_0 = 1,更新X
X = np.c_[X, np.ones((100, 1))]

# 3、定义一个函数来调整学习率
t0, t1 = 5, 500
def learning_rate_schedule(t):

return t0/(t+t1)

# 4、创建超参数轮次、样本数量、小批量数量 epochs = 10000
n = 100
batch_size = 16

num_batches = int(n / batch_size) # 5、初始化 W0...Wn,标准正太分布创建W

θ = np.random.randn(4, 1)

# 6、多次for循环实现梯度下降,最终结果收敛

for epoch in range(epochs): 

        # 在双层for循环之间,每个轮次开始分批次迭代之前打乱数据索引顺序

        index = np.arange(n)
        np.random.shuffle(index)
        X = X[index]

        y = y[index]
        for i in range(num_batches):

                # 一次取一批数据16个样本
                X_batch = X[i * batch_size : (i + 1)*batch_size]

                y_batch = y[i * batch_size : (i + 1)*batch_size]
                g = X_batch.T.dot(X_batch.dot(θ)-y_batch)

                learning_rate = learning_rate_schedule(epoch * n + i) θ = θ - learning_rate * g

print('真实斜率和截距是:',w,b)

print('梯度下降计算斜率和截距是:',θ)

6、梯度下降的归一化

6.1 归一化的目的

6.2 归一化的本质

6.3 最大值和最小值归一化

import numpy as np
x_1 = np.random.randint(1,10,size = 10)
x_2 = np.random.randint(100,300,size = 10)
x = np.c_[x_1,x_2]
print('归一化之前的数据:')
display(x)
x_ = (x - x.min(axis = 0)) / (x.max(axis = 0) - x.min(axis = 0)) 
print('归一化之后的数据:')
display(x_)

使用scikit-learn函数:

import numpy as np
from sklearn.preprocessing import MinMaxScaler 

x_1 = np.random.randint(1,10,size = 10)
x_2 = np.random.randint(100,300,size = 10)
x = np.c_[x_1,x_2]
print('归一化之前的数据:')
display(x)
min_max_scaler = MinMaxScaler()
x_ = min_max_scaler.fit_transform(x) 
print('归一化之后的数据:')
display(x_)

6.4 0-均值标准化 (Z-score归一化)

import numpy as np
x_1 = np.random.randint(1,10,size = 10)
x_2 = np.random.randint(100,300,size = 10)
x = np.c_[x_1,x_2]
print('归一化之前的数据:')
display(x)
x_ = (x - x.mean(axis = 0)) / x.std(axis = 0)

print('归一化之后的数据:')
display(x_)

使用scikit-learn函数:

import numpy as np
from sklearn.preprocessing import StandardScaler

x_1 = np.random.randint(1,10,size = 10)
x_2 = np.random.randint(100,300,size = 10)
x = np.c_[x_1,x_2]
print('归一化之前的数据:')
display(x)
standard_scaler = StandardScaler()
x_ = standard_scaler.fit_transform(x) print('归一化之后的数据:')
display(x_)

6.5 正则化 Regularization

6.5.1 过拟合欠拟合

  1. 欠拟合(under fit):还没有拟合到位,训练集和测试集的准确率都还没有到达最高,学的还不到位。

  2. 过拟合(over fit):拟合过度,训练集的准确率升高的同时,测试集的准确率反而降低。学的过度了(走火入魔),做过的卷子都能

      再次答对(死记硬背),考试碰到新的没见过的题就考不好(不会举一反三)。
    
  3. 恰到好处(just right):过拟合前,训练集和测试集准确率都达到巅峰。好比,学习并不需要花费很多时间,理解的很好,考试的时候

      可以很好的把知识举一反三。
    

6.5.2 套索回归(Lasso)

L1 = |w1|+|w2|

f(x,y)  = |x| +  |y| 
#   令f(x,y) =1 绘制徒刑在平面中
#  |x| +  |y|  = 1

'''
假设x,y等于1
1 = x+y
y = 1-x
'''
fun1 = lambda x:1-x

x1 = np.linspace(0,1,50)
y1 = fun1(x1)
plt.figure(figsize = (6,6))
plt.plot(x1,y1)

plt.xlim(-2,2)
plt.ylim(-2,2)
ax = plt.gca() # 获取当前视图

ax.spines['right'].set_color('None')
ax.spines['top'].set_color('None')
ax.spines['bottom'].set_position(('data',0))
ax.spines['left'].set_position(('data',0))

'''
假设x,y都是小于0
1 = -x-y
y = -1-x
'''
fun2 = lambda x:-x-1

x2 = np.linspace(-1,0,50)
y2 = fun2(x2)
plt.plot(x2,y2)


'''
假设x大于0,y都是小于0
1 = x-y
y = x-1
'''
fun3 = lambda x:x-1

x3 = np.linspace(0,1,50)
y3 = fun3(x3)
plt.plot(x3,y3)

# 假设x小于0,y大于0
# 1 = -x + y
fun4 = lambda x : 1 + x
x4 = np.linspace(-1,0,50)
y4 = fun4(x4)
plt.plot(x4,y4,color ='k')

6.5.3 岭回归

6.5.4 线性回归衍生算法

1、Redge算法使用:

import numpy as np
from sklearn.linear_model import Ridge
from sklearn.linear_model import SGDRegressor
# 1、创建数据集X,y
X = 2*np.random.rand(100, 5)
w = np.random.randint(1,10,size = (5,1))
b = np.random.randint(1,10,size = 1)
y = X.dot(w) + b + np.random.randn(100, 1)

print('原始方程的斜率:',w.ravel()) 
print('原始方程的截距:',b)
ridge = Ridge(alpha= 1, solver='sag') 
ridge.fit(X, y) print('岭回归求解的斜率:',ridge.coef_) 
print('岭回归求解的截距:',ridge.intercept_)



# 线性回归梯度下降方法
sgd = SGDRegressor(penalty='l2',alpha=0,l1_ratio=0) 
sgd.fit(X, y.reshape(-1,)) 
print('随机梯度下降求解的斜率是:',sgd.coef_) 
print('随机梯度下降求解的截距是:',sgd.intercept_)

2、lasso算法使用:

import numpy as np
from sklearn.linear_model import Lasso
from sklearn.linear_model import SGDRegressor

# 1、创建数据集X,y
X = 2*np.random.rand(100, 20)
w = np.random.randn(20,1)
b = np.random.randint(1,10,size = 1)
y = X.dot(w) + b + np.random.randn(100, 1)
print('原始方程的斜率:',w.ravel()) 
print('原始方程的截距:',b)


lasso = Lasso(alpha= 0.5)
lasso.fit(X, y) 
print('套索回归求解的斜率:',lasso.coef_) 
print('套索回归求解的截距:',lasso.intercept_)


# 线性回归梯度下降方法
sgd = SGDRegressor(penalty='l2',alpha=0, l1_ratio=0) 
sgd.fit(X, y.reshape(-1,)) 
print('随机梯度下降求解的斜率是:',sgd.coef_) 
print('随机梯度下降求解的截距是:',sgd.intercept_)

3、Elastic-Net算法使用:

import numpy as np
from sklearn.linear_model import ElasticNet
from sklearn.linear_model import SGDRegressor

# 1、创建数据集X,y
X = 2*np.random.rand(100, 20)
w = np.random.randn(20,1)
b = np.random.randint(1,10,size = 1)
y = X.dot(w) + b + np.random.randn(100, 1)
print('原始方程的斜率:',w.ravel()) 
print('原始方程的截距:',b)


model = ElasticNet(alpha= 1, l1_ratio = 0.7) 
model.fit(X, y) 
print('弹性网络回归求解的斜率:',model.coef_) 
print('弹性网络回归求解的截距:',model.intercept_)


# 线性回归梯度下降方法
sgd = SGDRegressor(penalty='l2',alpha=0, l1_ratio=0) 
sgd.fit(X, y.reshape(-1,)) 
print('随机梯度下降求解的斜率是:',sgd.coef_) 
print('随机梯度下降求解的截距是:',sgd.intercept_)

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐