机器学习的线性回归与非线性回归

一元线性回归

回归分析用来建立方程模拟两个或者多个变量之间如何关联

一元线性回归包括一个自变量和一个因变量

如果包含两个以上的自变量,则称为多元线性回归

机器学习的线性回归与非线性回归_第1张图片

代价函数(损失函数)

机器学习的线性回归与非线性回归_第2张图片

损失函数的最终目的是为了使得误差平方和最小

用梯度下降法求解线性回归

机器学习的线性回归与非线性回归_第3张图片

 训练模型过程中不断重复这个语句机器学习的线性回归与非线性回归_第4张图片

 学习率的值不能太小,也不能太大

机器学习的线性回归与非线性回归_第5张图片

机器学习的线性回归与非线性回归_第6张图片

 右边同一个颜色的线上任意一点,最终取得的损失函数的值是相等的

最中间的线上取得的损失函数值是最小的

 梯度下降法 一元线性回归

import numpy as np
import matplotlib.pyplot as plt
# 载入数据
data = np.genfromtxt("data.csv",delimiter=",")
x_data = data[:,0]
y_data = data[:,1]
# plt.scatter()函数用于创建一个散点图
plt.scatter(x_data,y_data)
plt.show()

 最小二乘法

# 最小二乘法
def compute_error(b, k, x_data, y_data):
    # 代价函数的初始值
    totalError = 0
    for i in range(0, len(x_data)):
        totalError += (y_data[i] - (k * x_data[i] + b)) ** 2
    return totalError / float(len(x_data)) / 2.0

 梯度下降法

def gradient_descent_runner(x_data, y_data, b, k, lr, epochs):
    # 计算总数据量
    m = float(len(x_data))
    # 循环epochs次
    for i in range(epochs):
        b_grad = 0
        k_grad = 0
        # 计算梯度的总和再求平均
        for j in range(0, len(x_data)):
            b_grad += (1/m) * (((k*x_data[j]) + b) - y_data[j])
            k_grad += (1/m) * x_data[j] * (((k*x_data[j]) + b) - y_data[j])
        # 更新b和k
        b = b - (lr * b_grad)
        k = k - (lr * k_grad)

    return b,k

输出和图象

print("Starting b = {0}, k = {1}, error = {2}".format(b, k, compute_error(b, k, x_data, y_data)))
print("Running……")
b, k = gradient_descent_runner(x_data, y_data, b, k, lr, epochs)
print("After{0} iterations b = {1}, k = {2}, error = {3}".format(epochs, b, k, compute_error(b, k, x_data, y_data)))

# 画图
plt.plot(x_data, y_data, 'b.') # 用蓝色的点画出来
plt.plot(x_data, k*x_data + b, 'r')
plt.show()

 sklearn-一元线性回归

from sklearn.linear_model import LinearRegression
import numpy as np
import matplotlib.pyplot as plt
# 载入数据
data = np.genfromtxt("data.csv",delimiter=",")
x_data = data[:,0]
y_data = data[:,1]
plt.scatter(x_data,y_data)
plt.show()
print(x_data.shape)

画出散点图;最后输出值为(100,) 

 创建并拟合模型

# 从 data 中选择所有行和第一列,然后增加一个维度,形成一个二维数组
x_data = data[:,0,np.newaxis]
y_data = data[:,1,np.newaxis]
# 创建并拟合模型
model = LinearRegression()
model.fit(x_data, y_data)

 LinearRegression模型通常需要输入二维数组形式的数据来进行拟合。这是因为线性回归模型通常表示为矩阵形式。

np.newaxis增加一个维度是为了将一维数组转换为二维数组,使得数据可以以矩阵的形式输入到模型中。

x_data 和 y_data 分别表示输入数据和目标数据。通过增加一个维度,它们被转换为二维数组,可以作为线性回归模型的输入。这样,模型就可以通过拟合这些数据来学习输入和输出之间的关系,并预测新的数据

 画图

# 画图
plt.plot(x_data, y_data, 'b.') # 用蓝色的点画出来
plt.plot(x_data, model.predict(x_data), 'r')
plt.show()

 多元线性回归

机器学习的线性回归与非线性回归_第7张图片

 梯度下降法-多元线性回归

import numpy as np
from numpy import genfromtxt
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# 载入数据
# 使用r前缀表示一个字符串是原始字符串,即不会对其中的转义字符进行解析
data = np.genfromtxt(r"Delivery.csv",delimiter=",")
print(data)

切分数据

# 切分数据
# 取到最后一个列,但不包括最后一个列
x_data = data[:,:-1]
y_data = data[:,-1]
print(x_data)
print(y_data)

 最小二乘法

# 最小二乘法
def compute_error(theta0, theta1, theta2, x_data, y_data):
    totalError = 0
    for i in range(0, len(x_data)):
        totalError += (y_data[i] - (theta1 * x_data[i,0] + theta2 * x_data[i,1] + theta0)) ** 2
    return totalError / float(len(x_data)) / 2.0

 梯度下降法

def gradient_descent_runner(x_data, y_data, theta0, theta1, theta2, lr, epochs):
    # 计算总数据量
    m = float(len(x_data))
    # 循环epochs次
    for i in range(epochs):
        theta0_grad = 0
        theta1_grad = 0
        theta2_grad = 0
        # 计算梯度的总和再求平均
        for j in range(0, len(x_data)):
            theta0_grad += (1/m) * ((theta1 *x_data[j,0] + theta2*x_data[j,1] + theta0)- y_data[j])
            theta1_grad += (1/m) * x_data[j,0] * ((theta1 *x_data[j,0] + theta2*x_data[j,1] + theta0)- y_data[j])
            theta2_grad += (1/m) * x_data[j,1] * ((theta1 *x_data[j,0] + theta2*x_data[j,1] + theta0)- y_data[j])
        # 更新b和k
        theta0 = theta0 - (lr*theta0_grad)
        theta1 = theta1 - (lr*theta1_grad)
        theta2 = theta2 - (lr*theta2_grad)
    return theta0, theta1, theta2

 输出

print("Starting theta0 = {0}, theta1 = {1}, theta2 = {2}, error = {3}".format(theta0, theta1, theta2, compute_error(theta0, theta1, theta2, x_data, y_data)))
print("Running...")
theta0, theta1, theta2 = gradient_descent_runner(x_data, y_data, theta0, theta1, theta2, lr, epochs)
print("After {0} iterations theta0 = {1}, theta1 = {2}, theta2 = {3}, error = {4}".format(epochs, theta0, theta1, theta2, compute_error(theta0, theta1, theta2, x_data, y_data)))

Starting theta0 = 0.006971416196678632, theta1 = 0.08021042690771771, theta2 = 0.07611036240566814, error = 0.3865635716109059

Running...

After 1000 iterations theta0 = 0.012105936219977274, theta1 = 0.07783523865497854, theta2 = 0.14266718993616928, error = 0.34191327566030316

 画3D图

# 画3D图
# 在图形上添加一个子图,其中'111'表示这是一个占据整个图形的子图
#(即,它覆盖了从左上角开始的第一行、# 第一列和第一页的网格的单元格)。
# projection = '3d'表示我们想要创建一个3D的子图
ax = plt.figure().add_subplot(111, projection = '3d')
ax.scatter(x_data[:,0],x_data[:,1],y_data, c = 'r', marker = 'o', s = 100)
# 格式是圆点,每个点的大小为100
x0 = x_data[:,0]
x1 = x_data[:,1]
# 生成网格矩阵
x0, x1 = np.meshgrid(x0, x1)
z = theta0 + x0*theta1 + x1*theta2
#画3D图
#这个函数能创建三维曲面图
ax.plot_surface(x0, x1, z)
# 设置坐标轴
ax.set_xlabel('Miles')
ax.set_ylabel('Num of Deliveries')
ax.set_zlabel('Time')

# 显示图象
plt.show()

sklearn-多元线性回归

import numpy as np
from numpy import genfromtxt
from sklearn import linear_model
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# 读入数据
data = np.genfromtxt(r"Delivery.csv",delimiter=",")
print(data)

 切分数据

# 切分数据
# 取到最后一个列,但不包括最后一个列
x_data = data[:,:-1]
y_data = data[:,-1]
print(x_data)
print(y_data)

创建模型

# 创建模型
model = linear_model.LinearRegression()
model.fit(x_data, y_data)

 输出

# 系数
print("coefficients:",model.coef_)

# 截距
print("intercept:",model.intercept_)

画3D图

# 画3D图
ax = plt.figure().add_subplot(111, projection = '3d')
ax.scatter(x_data[:,0],x_data[:,1],y_data, c = 'r', marker = 'o', s = 100)
# 格式是圆点,大小为100
x0 = x_data[:,0]
x1 = x_data[:,1]
# 生成网格矩阵
x0, x1 = np.meshgrid(x0, x1)
z = model.intercept_ + x0*model.coef_[0] + x1*model.coef_[1]
#画3D图
ax.plot_surface(x0, x1, z)
# 设置坐标轴
ax.set_xlabel('Miles')
ax.set_ylabel('Num of Deliveries')
ax.set_zlabel('Time')

# 显示图象
plt.show()

多项式回归

机器学习的线性回归与非线性回归_第8张图片

sklearn-多项式回归 

import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
# 载入数据
data = np.genfromtxt("job.csv", delimiter=",")
# 从 data 数组的第二行开始,选择所有行的第一列数据
x_data = data[1:,1]
y_data = data[1:,2]
print(x_data)
plt.scatter(x_data, y_data)
plt.show()

 创建并拟合模型

x_data = data[1:,1,np.newaxis]
y_data = data[1:,2,np.newaxis]
# 创建并拟合模型
model = LinearRegression()
model.fit(x_data, y_data)

 线性图

# 画图
plt.plot(x_data, y_data, 'b.')
plt.plot(x_data, model.predict(x_data), 'r')
plt.show()

 定义多项式回归

# 定义多项式回归,degree的值可以调节多项式的特征
# 当 degree=1 时,PolynomialFeatures 实际上不会生成新的特征,
# 而是会生成一个包含常数项 1 的特征,生成的第一列都是 1.0

# degree参数代表多项式的次数
# fit_transform()可以将输入数据转换为指定的数据类型,并返回转换后的数据
ploy_reg = PolynomialFeatures(degree=3)
# 特征处理
x_ploy = ploy_reg.fit_transform(x_data)
# 定义回归模型
lin_reg = LinearRegression()
# 训练模型
lin_reg.fit(x_ploy, y_data)

 degree的值越大,模型会更加拟合

 画图

# 画图
plt.plot(x_data, y_data, 'b.')
plt.plot(x_data, lin_reg.predict(ploy_reg.fit_transform(x_data)), c='r')
plt.title('Truth or Bluff (Polynomial Regression)')
plt.xlabel('Position level')
plt.ylabel('Salary')
plt.show()

标准方程法(梯度下降法的变化)

机器学习的线性回归与非线性回归_第9张图片

机器学习的线性回归与非线性回归_第10张图片

矩阵微积分(维基百科)

https://en.wikipedia.org/wiki/Matrix_calculus#Scalar-by-vector_identities 

 机器学习的线性回归与非线性回归_第11张图片

机器学习的线性回归与非线性回归_第12张图片

机器学习的线性回归与非线性回归_第13张图片

时间复杂度约为O(n^3) ;n是特征数量

 w是线性模型参数,用于计算结果。一般用theta代替。权重值越大,对于结果的影响越大。

b表示偏差。线性回归的目标是找到一组最佳的w和b值,使得预测值与实际值之间的误差平方和最小。因此,要求w的值是为了找到这组最佳的w和b值,使得预测值与实际值之间的误差平方和最小

矩阵不可逆的情况

1.线性相关的特征

2.特征数据太多(样本数m<=特征数量n) 

线性回归-标准方程法

import numpy as np
from numpy import genfromtxt
import matplotlib.pyplot as plt
# 载入数据
data = np.genfromtxt("data.csv", delimiter=",")
x_data = data[:,0,np.newaxis]
y_data = data[:,1,np.newaxis]
plt.scatter(x_data,y_data)
plt.show()

 添加偏置项的作用

  1. 改善模型的泛化能力:在机器学习模型中,如果特征矩阵X中存在一些特征的取值为0或者大部分为0,那么在训练过程中,这些特征将无法对模型的训练产生任何贡献。这是因为在标准线性回归模型中,偏置项b的存在使得模型可以适应那些取值为0或者大部分为0的特征。当特征的取值范围更大时,添加偏置项可以使得模型更好地拟合训练数据,提高模型的泛化能力。
  2. 避免模型过拟合:在一些情况下,当特征的取值范围很大时,如果不添加偏置项,模型可能会过度拟合训练数据,导致在测试集上的表现很差。而添加偏置项可以使得模型的训练更加稳定,避免模型过拟合。
# np.mat函数接受一个数组作为参数,并返回一个矩阵对象
# shape属性是一个元组,描述了矩阵的行数和列数
print(np.mat(x_data).shape)
print(np.mat(y_data).shape)
# 给样本添加偏置项
# 创建一个长度为100的一维数组,全部元素都是1(np.ones((100,1))),
# 然后将其与原数组x_data在列方向上拼接(即第一列前面加一列全是1的列)
X_data = np.concatenate((np.ones((100,1)),x_data),axis=1)
print(X_data.shape)

标准方程法求解回归参数

# 标准方程法求解回归参数
def weights(xArr, yArr):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr)
    xTx = xMat.T*xMat  #矩阵乘法
    # 计算矩阵的值,如果值为0,说明该矩阵没有逆矩阵
    if np.linalg.det(xTx) == 0.0:
        print("This matrix cannot do inverse")
        return
    # xTx.I为xTx的逆矩阵
    ws = xTx.I*xMat.T*yMat
    return ws
ws = weights(X_data,y_data)
print(ws)

 画图

# 画图
# 该数组包含两个元素,每个元素都是一个包含单个整数的列表。
x_test = np.array([[20],[80]])
y_test = ws[0] + x_test*ws[1]
plt.plot(x_data, y_data, 'b.')
plt.plot(x_test, y_test, 'r')
plt.show()

特征缩放

数据归一化

把数据的取值范围处理为0--1或者-1--1之间;

任意数据转化为0--1之间:

newValue = (oldValue-min)/(max-min)

任意数据转化为-1--1之间:

newValue = ((oldValue-min)/(max-min)-0.5)*2

 均值标准化

x为特征数据,u为数据的平均值,s为数据的方差

newValue = (oldValue-u)/s

 一般是-0.5左右到0.5左右

交叉验证法

通过将原始数据集进行切分,得到不同的训练集和测试集,用训练集训练模型,用测试集评估模型的泛化能力。交叉验证法可以有效地防止过拟合和欠拟合,评估模型的泛化能力,选择最佳的模型和参数

过拟合、正确拟合和欠拟合

机器学习的线性回归与非线性回归_第14张图片

过拟合的主要表现是:在训练集中表现得很好,但是在测试集中表现得不够好

机器学习的线性回归与非线性回归_第15张图片

 防止过拟合的方法

1.减少特征(简化模型)

2.增加数据量

3.正则化

正则化代价函数 

机器学习的线性回归与非线性回归_第16张图片

 θj指的就是多项式的系数;也就是权重

岭回归(标准方程法、有偏估计)

岭回归最早使用处理特征数多于样本的情况,现在也用于在估计中加入偏差,从而得到更好的估计。同时也可以解决多重共线性的问题。

机器学习的线性回归与非线性回归_第17张图片

岭回归在估计中加入偏差

如果数据的特征数量比样本还多,则计算逆矩阵时会出错。 

机器学习的线性回归与非线性回归_第18张图片

θj指的就是多项式的系数,也就是w 

机器学习的线性回归与非线性回归_第19张图片

岭回归的代价函数 ,其中λ是正则项的系数,不是岭系数

λ和残差平方和之间的关系是,当λ越大,正则化项的权重就越大,模型的复杂性就越低,越倾向于选择更简单的模型,从而降低过拟合的风险

随着λ的增大,特征的系数会被"压缩",即每个特征的系数都会比没有正则化时更接近于0。这种"压缩"效应会导致模型的复杂性降低,从而降低过拟合的风险。然而,这种"压缩"效应也会导致模型的预测能力下降,因此残差平方和也会随之增加。

sklearn-岭回归

import numpy as np
from numpy import genfromtxt
from sklearn import linear_model
import matplotlib.pyplot as plt
# 读入数据
data = genfromtxt(r"longley.csv",delimiter=',')
# 因为第一列的第一个是空值,所以默认填充为Nan
print(data)
# 切分数据
x_data = data[1:,2:]
y_data = data[1:,1]
print(x_data)
print(y_data)

 创建模型

# 创建模型
# 默认生成50个值
alphas_to_test = np.linspace(0.001, 1)
print(alphas_to_test)
# 创建模型,保存误差值
# Ridge指的是岭回归,CV指的是交叉验证
# alphas指的是岭回归系数,主要就是用交叉验证去验证这些数字是否正确
model = linear_model.RidgeCV(alphas=alphas_to_test, store_cv_values=True)
# store_cv_values=True: 设置为True时会存储交叉验证过程中每个阿尔法值的评分。
# 这可以用于后续评估和比较不同阿尔法值的性能
model.fit(x_data, y_data)

# 岭系数
print(model.alpha_)
# loss值
print(model.cv_values_.shape)
# 16次测试集,50个岭系数

画图

# 画图
# 岭系数和loss值的关系      .mean(axis=0)指的是16个测试集loss值的平均值
plt.plot(alphas_to_test, model.cv_values_.mean(axis=0))
# 选取的岭系数值的位置
plt.plot(model.alpha_, min(model.cv_values_.mean(axis=0)),'ro')
plt.show()

标准方程法-岭回归

import numpy as np
from numpy import genfromtxt
import matplotlib.pyplot as plt

# 读入数据
data = genfromtxt(r"longley.csv",delimiter=',')
# 因为第一列的第一个是空值,所以默认填充为Nan
print(data)

# 切分数据
x_data = data[1:,2:]
y_data = data[1:,1,np.newaxis]
print(x_data)
print(y_data)
print(np.mat(x_data).shape)
print(np.mat(y_data).shape)
# 给样本添加偏置项
X_data = np.concatenate((np.ones((16,1)),x_data),axis=1)
print(X_data.shape)

 标准方程法求解回归参数

# 岭回归标准方程法求解回归参数
def weights(xArr, yArr, lam=0.2):
    xMat = np.mat(xArr)
    yMat = np.mat(yArr)
    xTx = xMat.T*xMat  #矩阵乘法
    # xMat.shape[1]获取矩阵xMat的列数,然后np.eye()用这个列数来创建一个相应大小的单位矩阵
    rxTx = xTx + np.eye(xMat.shape[1])*lam
    # 计算矩阵的值,如果值为0,说明该矩阵没有逆矩阵
    if np.linalg.det(rxTx) == 0.0:
        print("This matrix cannot do inverse")
        return
    # xTx.I为xTx的逆矩阵
    ws = rxTx.I*xMat.T*yMat
    return ws
ws = weights(X_data,y_data)
print(ws)

 LASSO算法

通过构造一个一阶惩罚函数获得一个精炼的模型;通过最终确定一些指标(变量)的系数为零(岭回归估计系数等于零的机会微乎其微)

擅长处理具有多重共线性的数据,与岭回归一样是有偏估计

机器学习的线性回归与非线性回归_第20张图片

sklearn-LASSO

import numpy as np
from numpy import genfromtxt
from sklearn import linear_model

# 读入数据 
data = genfromtxt(r"longley.csv",delimiter=',')
print(data)

# 切分数据
x_data = data[1:,2:]
y_data = data[1:,1]
print(x_data)
print(y_data)

 创建模型

# 创建模型
model = linear_model.LassoCV()
model.fit(x_data, y_data)

# lasso系数
print(model.alpha_)
# 相关系数
print(model.coef_)

弹性网

机器学习的线性回归与非线性回归_第21张图片

 而具体的弹性网指的是

机器学习的线性回归与非线性回归_第22张图片

 sklearn-弹性网

import numpy as np
from numpy import genfromtxt
from sklearn import linear_model

# 读入数据 
data = genfromtxt(r"longley.csv",delimiter=',')
print(data)

# 切分数据
x_data = data[1:,2:]
y_data = data[1:,1]
print(x_data)
print(y_data)

创建模型

# 创建模型
model = linear_model.ElasticNetCV()
model.fit(x_data, y_data)

# 弹性网系数
print(model.alpha_)
# 相关系数
print(model.coef_)

 相关系数

机器学习的线性回归与非线性回归_第23张图片

线性函数的值越接近1,整个的线性相关性就越强

相关系数是用来描述两个变量之间的线性关系的,但决定系数的适用范围更广,可以用于描述非线性或者有两个及两个以上自变量的相互关系

机器学习的线性回归与非线性回归_第24张图片

非凸函数和凸函数

机器学习的线性回归与非线性回归_第25张图片

 线性回归的代价函数是凸函数

单位矩阵

机器学习的线性回归与非线性回归_第26张图片

你可能感兴趣的:(Pytorch,Python,机器学习,回归,线性回归)