在数据分析中,经常需要确定变量X和Y之间的关系,并用一条直线来表示这种关系。但是,问题在于如何确定这条直线能够最好地代表X和Y之间的关系。为了解决这个问题,可以使用均方误差(Mean Squared Error,简称MSE)作为衡量标准。在线性回归中,MSE实际上就是成本函数。均方误差是预测值与真实值之间差的平方和,输出是一个单一数值,代表成本。因此,具有最小成本函数或MSE的直线就是X和Y之间关系的最佳表示。一旦找到了斜率和截距,使得这条直线的误差最小,就可以使用这条直线来预测Y值。
本文将介绍如何计算不同直线的误差/成本,并找到成本函数,进而用于预测。如果对以音视频形式学习概念更感兴趣,有整个文章的视频解释。如果不感兴趣,可以继续阅读。
知道任何直线都可以用两个参数表示:斜率(β)和截距(b)。一旦有了直线,总是可以计算这条直线与底层数据点之间的误差(也称为成本或损失),目标是找到误差最小的直线。这基本上变成了一个优化问题。让通过一个练习来看看不同值的β和b的误差是多少,然后问题是如何找到这两个参数的最优化值。
首先,将导入必要的库,包括matplotlib、pandas和scikit-learn来计算误差:
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.metrics import mean_squared_error as mse
创建了一个关于经验和薪水的数据集。创建了一个列表,然后简单地将其转换为Pandas DataFrame:
import pandas as pd
# 创建样本数据集
experience = [1.2,1.5,1.9,2.2,2.4,2.5,2.8,3.1,3.3,3.7,4.2,4.4]
salary = [1.7,2.4,2.3,3.1,3.7,4.2,4.4,6.1,5.4,5.7,6.4,6.2]
data = pd.DataFrame({ "salary" : salary, "experience" : experience })
print(data.head())
可以看到数据集的前五行。
现在让通过探索薪水和经验之间的关系来探索数据集。让使用Matplotlib绘制这个关系:
plt.scatter(data.experience, data.salary, color = 'red', label = '数据点')
plt.xlim(1,4.5)
plt.ylim(1,7)
plt.xlabel('经验')
plt.ylabel('薪水')
plt.legend()
可以看到经验和薪水之间的线性关系。这就是预期的。那么现在让开始绘制使用不同β和b值的直线。
首先,将取β=0.1和b=1.1,将使用这两个参数创建一条直线,并将其绘制在散点图上。现在,取值并应用这种关系来创建每条直线,然后将这些直线绘制在上述创建的散点图上。
beta = 0.1
# 保持截距不变
b = 1.1
# 存储预测点
line1 = []
# 为每个数据点生成预测
for i in range(len(data)):
line1.append(data.experience[i]*beta + b)
# 绘制直线
plt.scatter(data.experience, data.salary, color = 'red')
plt.plot(data.experience, line1, color = 'black', label = '直线')
plt.xlim(1,4.5)
plt.ylim(1,7)
plt.xlabel('经验')
plt.ylabel('薪水')
plt.legend()
MSE = mse(data.salary, line1)
已经为β=0.1和b=1.1绘制了这条直线,这条直线的MSE是2.69。现在可以看到直线的斜率非常小,所以想尝试一个更大的斜率,而不是β=0.1,让将其改为β=1.5:
beta = 1.5
这是β=1.5和b=1.1的直线,这条直线的MSE是6.40。可以看到更好的斜率,但它可能比实际想要的要大。所以正确的值可能在0.1和1.5之间,让试试β=0.8:
beta = 0.8
这是β=0.8和b=1.1的直线,可以看到均方误差已经降到了0.336。已经尝试了三条不同的直线,每条直线都有不同的MSE;第一条是2.69,第二条是6.4,第三条是0.33。现在可以继续尝试各种β值。所以现在可以尝试不同的Beta值,并看看β和均方误差(MSE)之间的关系,对于固定值的截距即b。所以不改变b。
让创建一个称之为Error的函数,这个函数的作用是对于给定的β值,它基本上给了这些数据点的MSE。这里b是固定的,尝试不同的Beta值。
def Error(Beta, data):
# b是常数
b = 1.1
salary = []
experience = data.experience
# 循环计算预测薪水变量
for i in range(len(data.experience)):
tmp = data.experience[i] * Beta + b
salary.append(tmp)
MSE = mse(data.salary, salary)
return MSE
现在要尝试所有0到1.5之间的Beta值,增量为0.01,然后将所有内容附加到一个列表中:
slope = [i/100 for i in range(0,150)]
Cost = []
for i in slope:
cost = Error(Beta = i, data = data)
Cost.append(cost)
当这个完成后,只需将其转换为这个就是数据框架:
Cost_table = pd.DataFrame({
'Beta' : slope,
'Cost' : Cost
})
Cost_table.head()
这个数据框架显示,对于Beta值为0.00,得到的成本或MSE是3.72,对于beta=0.04,得到的成本=3.29。让快速可视化这个:
plt.plot(Cost_table.Beta, Cost_table.Cost, color = 'blue', label = '成本函数曲线')
plt.xlabel('Beta值')
plt.ylabel('成本')
plt.legend()
这是得到的图表。所以如所见,成本在0时大约是3.72,这是起始值。之后,随着Beta值的增加,误差降低,达到最小值,然后开始增加。
现在的问题是,知道这种关系,如何找到β和b的值,以便可以找到成本最小化的具体位置。
现在,当有两个参数时,意思是,现在假设b是0.1,但实际上想要做的是随着b和β的变化而变化,在这种特定情况下,得到的曲线是:
所以再次,这只是3D图表,所以有两个维度,但它将再次有一个最小值,想法是找到这个最小值。但不能像以前那样迭代地做。所以需要找到一种更聪明的方式来找到这个最小值,这就是梯度下降技术发挥作用的地方。
在本文中,学习了如何计算不同直线的误差以及如何找到最优直线。