机器学习(2-4):线性回归之四:多元线性回归

2.4  多元线性回归

2.4.1 假设函数、样本数量、代价函数

假设函数
代数表达

比如对于多元线性回归,假设函数表示为


其中 为模型参数, 为每个样本的 个特征值。这个表示可以简化,我们增加一个特征 ,这样


矩阵表达

设向量 ,则有:


样本
代数表达

假设样本个数为m,具体为

矩阵表达

设输入特征向量 ,输出特征向量

代价函数
代数表达


矩阵表达

设矩阵 ,则有


2.4.2 多元梯度下降法

1、假设函数:  或

2、参数:

3、样本:样本数为m,具体为

输入特征向量 ,输出特征向量


4、代价函数: =12m(Xθ-y)T(Xθ-y)

5、梯度下降:

特征缩放(Fearture Scaling)——归一化

由于样本不同特征的取值范围不一样,可能导致迭代很慢,为了减少特征取值的影响,可以对特征数据归一化。

一般地而言,将每个输入的特征值限制在,n ,这就是归一化。实际中不是绝对的,经验告诉我们,当 ,就不需要归一化,否则就需要归一化。

均值归一化

就是对于每个特征 ,求出它的期望 和标准差 ,然后转化为:


这样特征的新期望为0,新方差为1,迭代速度可以大大加快。

几个概念

总体标准差:

样本标准差: 

标准误差: 

方差:方差=标准差的平方。

学习速率(Learning rate)——步长


如何选择合适的α ,使梯度下降的迭代步数更少。

步长太大,会导致迭代过快,甚至有可能错过最优解。步长太小,迭代速度太慢,很长时间算法都不能结束。所以算法的步长需要多次运行后才能得到一个较为优的值。

在前面的算法描述中,提到取步长为1,但是实际上取值取决于数据样本,可以多取一些值,从大到小,分别运行算法,看看迭代效果,如果损失函数在变小,说明取值有效,否则要增大步长。

特征和多项式回归

根据训练集的m 个样本特征数n ,我们可以得出假设函数为


我们可以创建新特征来取得更好的效果。

创造新特征降低特征数

对于一块土地的价值,


其中 表示临界宽度, 表示深度。

我们可以创建一个新特征“面积=临街宽度x深度”,则假设函数就可以变为:


其中 表示土地面积。

多项式回归

上面所提到的都是线性回归(一元,多元),当线性回归不能准确拟合样本曲线时,我们可以多项式回归。


创造新特征使多项式回归变成线性回归

对于多项式回归


在其中,我们有可以创建新特征,令 ,则多项式回归就变成了多元线性回归


创造新特征规避多项式回归中偶函数的问题

对于多项式回归


若上面的假设函数中 是房屋面积,由于 是偶函数,有可能会造成面积越大,总价越小的尴尬。我们可以对假设函数进行改造为:


也可以改造为


创建新特征 ,则多项式回归就变成了多元线性回归:


2.4.3 正规方程法(区别于迭代方法的直接解法)

之前我们都是用梯度下降法来求代价函数的最小值。这里我们用方程直接求解最小值。

通过高等数学我们知道:

极值点出现在偏导数=0的地方,求解导数方程或偏导数方程组,即可求解极值点坐标。

对于一维 ,若 ,则得

对于n+1维


求解上述n+1个方程组成的方程组,则可解出

步骤详解

房屋价格,样本数m=4,具体情况见下表:

面积(feet2)


卧室数量


层数


房龄(years)


价格($1000)


2104

5

1

45

460

1416

3

2

40

232

1534

3

2

30

315

852

2

1

36

178

第一步,在数据集中增加一列 ,其取值永远为1







1

2104

5

1

45

460

1

1416

3

2

40

232

1

1534

3

2

30

315

1

852

2

1

36

178

第二步,构建一个输入特征矩阵X和输出向量y


第三步,求解θ


梯度下降法和正规方程法的优缺点

梯度下降法需要选择学习速率,需要多次迭代;但可以工作在任意多的输入特征量n,尤其是n很大时。

正规方程法不需要选择学习速率,不需要迭代;但需要计算 ,当n很大时,计算会非常缓慢。

如何选择呢?

对于线性回归,当n为10000以下,用正规方程法,否则用梯度下降法。

当算法越来越复杂时,正规方程法就不适用了,此时选择梯度下降法。

正规方程在矩阵不可逆情况下的解决办法


不可逆怎么办?

矩阵不可逆有两种情况:

  1. 一是特征值线性相关
  2. 二是样本数量m小于特质值数量n。

解决办法有:

  1. 针对特征值线性相关,去掉线性相关的特征值
  2. 针对样本数量m小于特质值数量n,要么删除一些特征值,要么正则化(regularization),在后面会讲正则化。

2.4.5 示例:【Python】多元线性回归(梯度下降法)

一个房屋价格数据集,其中有2个变量(房子的大小,卧室的数量)和目标(房子的价格)。 我们使用我们已经应用的技术来分析数据集。

样本数据data2.txt

2104,3,399900

1600,3,329900

2400,3,369000

1416,2,232000

3000,4,539900

1985,4,299900

1534,3,314900

1427,3,198999

1380,3,212000

1494,3,242500

1940,4,239999

2000,3,347000

1890,3,329999

4478,5,699900

1268,3,259900

2300,4,449900

1320,2,299900

1236,3,199900

2609,4,499998

3031,4,599000

1767,3,252900

1888,2,255000

1604,3,242900

1962,4,259900

3890,3,573900

1100,3,249900

1458,3,464500

2526,3,469000

2200,3,475000

2637,3,299900

1839,2,349900

1000,1,169900

2040,4,314900

3137,3,579900

1811,4,285900

1437,3,249900

1239,3,229900

2132,4,345000

4215,4,549000

2162,4,287000

1664,2,368500

2238,3,329900

2567,4,314000

1200,3,299000

852,2,179900

1852,4,299900

1203,3,239500

Python代码(梯度下降法)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d

'''
  样本输入特征数为N (N=1 对于一元线性回归),输出特征为y。
  假设函数:y=theta0+theta1*x1+theta2*x2+...+thetaN*xN
      令x0 =1,
        x = [x0,x1,x2,...,xN]
        theta = [theta0,theta1,theta2,...thetaN]
      则有:
        y = x * theta.T
  样本个数为M, 样本的输入特征矩阵X为 (M行N+1列),输出特征y为向量(M行1列)
  代价函数:cost = sum((X*theta.T-y)^2)/(2*M)
  
'''

def computeCost(X, y, theta):
    '''
    作用:计算代价函数,向量化来计算参数
    :param X: 样本的输入特征,矩阵(M行N+1列)。
    :param y: 样本的输出特征,向量(M行1列)
    :param theta: parameters,一元线性回归的参数,向量(1行N+1列
    :return: 代价函数的值,浮点数
    '''
    inner = np.power(((X * theta.T) - y), 2)
    # print(inner)
    return np.sum(inner) / (2 * len(X))

def gradientDescent(X, y, theta, alpha, epoch):
    '''
    作用:获得最终梯度下降后的theta值以及cost
    :param X: 输入特性矩阵(M,N+1),二元线性回归N=2,矩阵形状(M,3)
    :param y: 输出特性矩阵(1,M)
    :param theta: 假设函数参数矩阵(1,N+1)。二元线性回归N=2,矩阵形状(1,3)
    :param alpha: 步长,又称学习速率,浮点数。
    :param epoch: 要执行的迭代次数,整数。
    :return:
    '''
    # 1 变量初始化,储存数据
    # 1.1 初始化参数矩阵为0
    np.matrix(np.zeros(theta.shape)) # 初始化一个临时矩阵(1, 3)
    # flatten()降维 即返回一个折叠成一维的数组。
    # 但是该函数只能适用于numpy对象,即array或者mat,普通的list列表是不行的。
    parameters = int(theta.flatten().shape[1]) # 参数theta的数量 3
    # print(parameters)
    # 1.2 初始化保存每一次迭代计算代价函数值的数组为0
    cost = np.zeros(epoch)  # 初始化一个ndarray, 包含每次训练后的cost #1000个0的矩阵
    # print(cost)
    # 1.3 初始化保存每一次迭代计算假设函数参数的数组(epoch,3)为0
    counterTheta = np.zeros((epoch, 3)) #1000 * 3的数组
    m = X.shape[0]  # 样本个数

    # 2 迭代计算
    for i in range(epoch):
        '''
        使用 vectorization同时更新所有的θ,可以大大提高效率,此处都是相对应的进行计算
        X.shape, theta.shape, y.shape, X.shape[0]
        ((97, 2), (1, 2), (97, 1), 97)
        '''
        # 相当于theta1 theta2不停做偏导并且更新 theta[theta1, theta2] temp是临时的theta
        temp = theta - (alpha / m) * (X * theta.T - y).T * X
        theta = temp
        counterTheta[i] = theta
        cost[i] = computeCost(X, y, theta)
        pass
    return counterTheta, theta, cost

'''
多元线性回归
'''

# 1.Prepare datasets
path = 'D:/dataAnalysis/MachineLearning/data2.txt'
# names添加列名,header用指定的行来作为标题,若原无标题且指定标题则设为None
data = pd.read_csv(path, header=None, names=['Size', 'Bedrooms', 'Price'])
print(data.head())#显示前五行
print(data.describe())

# 2.数据归一化
# 数据归一化后,最优解的寻优过程明显会变得平缓,更容易正确的收敛到最优解。简而言之,归一化的目的就是使得预处理的数据被限定在一定的范围内(比如[0,1]或者[-1,1]),从而消除奇异样本数据导致的不良影响。
temp = data  #复制一份
data = (data - data.mean()) / data.std() # data2.std()是标准差
print(data.head())#显示前五行
print(data.describe())

# 3 在数据集前增加1列,值为全1
data.insert(0, 'Ones', 1)       # 增加一条第一列,全部数值为1
# print(data)

# 4 从表中提取样本输入特征,输出特征
#   变量初始化:set X (training data) and y (target variable)
cols = data.shape[1]  # 列数
X = data.iloc[:, 0:cols - 1]        # 取前cols-1列,即输入向量
y = data.iloc[:, cols - 1:cols]     # 取最后一列作为目标向量
# print(X.head()) # 观察下 X (训练集) and y (目标变量)是否正确.
# print(y.head())

# 5 将样本输入特征,输出特征转化为矩阵
X = np.matrix(X.values)
y = np.matrix(y.values)
theta = np.matrix([0,0,0]) # theta 是一个(1,3)矩阵
computeCost(X, y, theta)

# 6 定义学习速率,迭代次数
alpha = 0.01 # 学习速率α
epoch = 3800 # 要执行的迭代次数

# 7 梯度下将法求解
counterTheta, final_theta, cost = gradientDescent(X, y, theta, alpha, epoch)
computeCost(X, y, final_theta)
print(computeCost(X, y, final_theta)) # 4.515955503078912
print(final_theta)

# 8 将归一化化后的数据还原
#data =  temp 

# 9 预测值
x1 = np.linspace(data.Size.min(), data.Size.max(), 100)  # xlabel start:返回样本数据开始点 stop:返回样本数据结束点 num:生成的样本数据量,默认为50
x2 = np.linspace(data.Bedrooms.min(), data.Bedrooms.max(), 100),# ylabel start:返回样本数据开始点 stop:返回样本数据结束点 num:生成的样本数据量,默认为50
x1 = np.matrix(x1) # 数组转换为矩阵
x2 = np.matrix(x2) # 数组转换为矩阵
f = final_theta[0, 0] + final_theta[0, 1] * x1.T + final_theta[0, 2] * x2.T  # zlabel price
# 矩阵转换为数组
#x1= x1.getA()
#x2= x2.getA()
#f= f.getA()
print(f)
print(f.shape)
print(final_theta)
print(final_theta.shape)

# 10 可视化
# 10.1 绘制样本离散图和预测曲线
fig1 = plt.subplots(figsize=(6, 4)) # 尺寸 
ax = plt.axes(projection='3d')
ax.scatter3D(data.Size, data.Bedrooms, data.Price, color="green") # 样本的离散值
ax.plot_surface(x1, x2, f,cmap='viridis', edgecolor='none') # 预测曲面:横坐标 纵坐标 颜色 标签
ax.legend(loc=2) # 2表示在左上角
ax.set_xlabel('Size')
ax.set_ylabel('Bedrooms')
ax.set_zlabel('Price')
ax.set_title('Room Price  vs. Room Size & Bedrooms')

# 10.2 绘制代价函数曲线
fig2, ax = plt.subplots(figsize=(8, 4))
ax.plot(np.arange(epoch), cost, 'r') # 横坐标 纵坐标 颜色
ax.set_xlabel('Iteration')
ax.set_ylabel('Cost')
ax.set_title('Error vs. Training Epoch')
plt.show()

2.4.6 示例:【Python】多元线性回归(正规方程法)

样本数据Adertisting.xlsx
TVradionewspapersales
230.137.869.222.1
44.539.345.110.4
17.245.969.39.3
151.541.358.518.5
180.810.858.412.9
8.748.9757.2
57.532.823.511.8
120.219.611.613.2
8.62.114.8
199.82.621.210.6
66.15.824.28.6
214.724417.4
23.835.165.99.2
97.57.67.29.7
204.132.94619
195.447.752.922.4
67.836.611412.5
281.439.655.824.4
69.220.518.311.3
147.323.919.114.6
218.427.753.418
237.45.123.512.5
13.215.949.65.6
228.316.926.215.5
62.312.618.39.7
262.93.519.512
142.929.312.615
240.116.722.915.9
248.827.122.918.9
70.61640.810.5
292.928.343.221.4
112.917.438.611.9
97.21.5309.6
265.6200.317.4
95.71.47.49.5
290.74.18.512.8
266.943.8525.4
74.749.445.714.7
43.126.735.110.1
22837.73221.5
202.522.331.616.6
17733.438.717.1
293.627.71.820.7
206.98.426.412.9
25.125.743.38.5
175.122.531.514.9
89.79.935.710.6
239.941.518.523.2
227.215.849.914.8
66.911.736.89.7
199.83.134.611.4
100.49.63.610.7
216.441.739.622.6
182.646.258.721.2
262.728.815.920.2
198.949.46023.7
7.328.141.45.5
136.219.216.613.2
210.849.637.723.8
210.729.59.318.4
53.5221.48.1
261.342.754.724.2
239.315.527.315.7
102.729.68.414
131.142.828.918
699.30.99.3
31.524.62.29.5
139.314.510.213.4
237.427.51118.9
216.843.927.222.3
199.130.638.718.3
109.814.331.712.4
26.83319.38.8
129.45.731.311
213.424.613.117
16.943.789.48.7
27.51.620.76.9
120.528.514.214.2
5.429.99.45.3
1167.723.111
76.426.722.311.8
239.84.136.912.3
75.320.332.511.3
68.444.535.613.6
213.54333.821.7
193.218.465.715.2
76.327.51612
110.740.663.216
88.325.573.412.9
109.847.851.416.7
134.34.99.311.2
28.61.5337.3
217.733.55919.4
250.936.572.322.2
107.41410.911.5
163.331.652.916.9
197.63.55.911.7
184.9212215.5
289.742.351.225.4
135.241.745.917.2
222.44.349.811.7
296.436.3100.923.8
280.210.121.414.8
187.917.217.914.7
238.234.35.320.7
137.946.45919.2
251129.77.2
90.40.323.28.7
13.10.425.65.3
255.426.95.519.8
225.88.256.513.4
241.73823.221.8
175.715.42.414.1
209.620.610.715.9
78.246.834.514.6
75.13552.712.6
139.214.325.612.2
76.40.814.89.4
125.736.979.215.9
19.41622.36.6
141.326.846.215.5
18.821.750.47
2242.415.611.6
123.134.612.415.2
229.532.374.219.7
87.211.825.910.6
7.838.950.66.6
80.209.28.8
220.3493.224.7
59.61243.19.7
0.739.68.71.6
265.22.94312.7
8.427.22.15.7
219.833.545.119.6
36.938.665.610.8
48.3478.511.6
25.6399.39.5
273.728.959.720.8
4325.920.59.6
184.943.91.720.7
73.41712.910.9
193.735.475.619.2
220.533.237.920.1
104.65.734.410.4
96.214.838.911.4
140.31.9910.3
240.17.38.713.2
243.24944.325.4
3840.311.910.9
44.725.820.610.1
280.713.93716.1
1218.448.711.6
197.623.314.216.6
171.339.737.719
187.821.19.515.6
4.111.65.73.2
93.943.550.515.3
149.81.324.310.1
11.736.945.27.3
131.718.434.612.9
172.518.130.714.4
85.735.849.313.3
188.418.125.614.9
163.536.87.418
117.214.75.411.9
234.53.484.811.9
17.937.621.68
206.85.219.412.2
215.423.657.617.1
284.310.66.415
5011.618.48.4
164.520.947.414.5
19.620.1177.6
168.47.112.811.7
222.43.413.111.5
276.948.941.827
248.430.220.320.2
170.27.835.211.7
276.72.323.711.8
165.61017.612.6
156.62.68.310.5
218.55.427.412.2
56.25.729.78.7
287.64371.826.2
253.821.33017.6
20545.119.622.6
139.52.126.610.3
191.128.718.217.3
28613.93.715.9
18.712.123.46.7
39.541.15.810.8
75.510.869.9
17.24.131.65.9
166.8423.619.6
149.735.6617.3
38.23.713.87.6
94.24.98.19.7
1779.36.412.8
283.64266.225.5
232.18.68.713.4
Python代码
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.model_selection import KFold
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
 
# 1、创建数据集
# 1.1 通过read_excel来读取我们的目的数据集
data = pd.read_excel("D:/dataAnalysis/MachineLearning/Advertising.xlsx")
# 1.2 得到我们所需要的数据集且查看其前几列以及数据形状
print('data head:\n',data.head(),'\nShape:',data.shape)
# 1.3 数据描述
print('data describe:\n',data.describe())
# 1.4 缺失值检验
print('data isnull:\n',data[data.isnull()==True].count())
# 1.5 绘图 
data.boxplot()
plt.savefig("boxplot.jpg")
plt.show()
# 1.6 计算数据集的相关系数矩阵
#     相关系数矩阵 r(相关系数) = x和y的协方差/(x的标准差*y的标准差) == cov(x,y)/σx*σy
#     相关系数0~0.3弱相关0.3~0.6中等程度相关0.6~1强相关
print(data.corr())
 
# 1.7 建立散点图来查看数据集里的数据分布
#     seaborn的pairplot函数绘制X的每一维度和对应Y的散点图。通过设置size和aspect参数来调节显示的大小和比例。
#     可以从图中看出,TV特征和销量是有比较强的线性关系的,而Radio和Sales线性关系弱一些,Newspaper和Sales线性关系更弱。
#     通过加入一个参数kind='reg',seaborn可以添加一条最佳拟合直线和95%的置信带。
sns.pairplot(data, x_vars=['TV','radio','newspaper'], y_vars='sales', size=7, aspect=0.8,kind = 'reg')
plt.savefig("pairplot.jpg")
plt.show()

# 2 将原数据集拆分训练集和测试集
#   利用sklearn里面的包来对数据集进行划分,以此来创建训练集和测试集
#   train_size表示训练集所占总数据集的比例
X_train,X_test,Y_train,Y_test = train_test_split(data[['TV','radio','newspaper']],data.sales,train_size=.80)
#X_train为训练数据标签,X_test为测试数据标签,exam_X为样本特征,exam_y为样本标签,train_size 训练数据占比
print(f'原始数据特征: {data.shape} ,训练数据特征: {X_train.shape} ,测试数据特征: {X_test.shape};')
print(f'原始数据标签: {data.sales.shape} ,训练数据标签: {Y_train.shape} ,测试数据标签: {Y_test.shape}.')

# 3 多元线性回归 
#   回归方程 y = a0 + a1*x1 + a2*x2 + a3*x3(模型建立最佳拟合线)
#   点误差 = 实际值 - 拟合值
#   误差平方和(Sum of square error) SSE = Σ(实际值-预测值)^2
#   最小二乘法 : 使得误差平方和最小(最佳拟合)
#   3.1 调用线性回归API
model = LinearRegression()
#   3.2 求优化参数
model.fit(X_train,Y_train)
a  = model.intercept_#截距
b = model.coef_#回归系数
print("最佳拟合线:截距",a,",回归系数:",b)
 
#   3.3 R方检测
#   决定系数r平方
#   对于评估模型的精确度
#   y误差平方和 = Σ(y实际值 - y预测值)^2
#   y的总波动 = Σ(y实际值 - y平均值)^2
#   有多少百分比的y波动没有被回归拟合线所描述 = SSE/总波动
#   有多少百分比的y波动被回归线描述 = 1 - SSE/总波动 = 决定系数R平方
#   对于决定系数R平方来说
#   1) 回归线拟合程度:有多少百分比的y波动刻印有回归线来描述(x的波动变化)
#   2)值大小:R平方越高,回归模型越精确(取值范围0~1),1无误差,0无法完成拟合
score = model.score(X_test,Y_test)
print(score)
 
#   3.4对线性回归进行预测
Y_pred = model.predict(X_test)
print(Y_pred)
plt.plot(range(len(Y_pred)),Y_pred,'b',label="predict")
#   显示图像
#   plt.savefig("predict.jpg")
plt.show()
 
plt.figure()
plt.plot(range(len(Y_pred)),Y_pred,'b',label="predict")
plt.plot(range(len(Y_pred)),Y_test,'r',label="test")
plt.legend(loc="upper right") #显示图中的标签
plt.xlabel("the number of sales")
plt.ylabel('value of sales')
plt.savefig("ROC.jpg")
plt.show()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值