波士顿房价预测
波士顿房屋数据集:
可视化数据集的重要特征:
探索性数据分析(Exploratory Data Analysis,EDA)是机器学习模型训练之前的一个重要步骤。
在本节的后续内容中,借助EDA图形工具箱中那些简单且有效的技术,可以帮助我们直观地发现数据中的异常情况、数据的分布情况,以及特征间的相互关系。
首先,借助散点图矩阵,我们以可视化的方法汇总显示各不同特征两两之间的关系。为了绘制散点图矩阵,我们需要用到seaborn库中的pairplot函数,
它是在matplotlib基础上绘制统计图像的Python库。
sns.pairplot(df[cols],size=2.5)
导入seaborn库后,会覆盖当前Python会话中matplotlib默认的图像显示方式。
如果读者不希望使用seaborn风格的设置,可以通过如下命令重设为matplotlib的风格:
sns.reset_orig()
散点图矩阵以图形的方式对数据集中特征间关系进行了描述
通过此散点图矩阵,我们可以快速了解数据是如何分布的,以及其中是否包含异常值。
例如,我们可直观看出RM和房屋价格MEDV(第5列和第4行)之间存在线性关系。
此外,从MEDV直方图(散点图矩阵的右下角子图)中可以发现:MEDV看似呈正态分布,但包含几个异常值。
请注意,不同于人们通常的理解,训练一个线性回归模型并不需要解释数量或者目标变量呈正态分布。正态假设仅适用于某些统计检验和假设检验。
为了量化特征之间的关系,我们创建一个相关系数矩阵。相关系数矩阵与我们第5章“主成分分析”一节中讨论过的协方差矩阵是密切相关的。
直观上来看,我们可以把相关系数矩阵看作协方差矩阵的标准化版本。实际上,相关系数矩阵就是在将数据标准化后得到的协方差矩阵。
相关系数矩阵是一个包含皮尔逊积矩相关系数(Pearson product-moment correlation coefficient,通常记为Pearson抯r)的方阵,
它用来衡量两两特征间的线性依赖关系。相关系数的取值范围为-1到1。
如果r=1,代表两个特征完全正相关;如果r=0,则不存在相关关系;如果r=-1,则两个特征完全负相关。
如前所述,皮尔逊相关系数可用两个特征x和y间的协方差(分子)除以它们标准差的乘积(分母)来计算。
r = σxy/σx*σy
可以证明:经标准化各特征间的协方差实际上等价于它们的线性相关系数。
使用NumPy的corrcoef函数计算前面散点图矩阵中5个特征间的相关系数矩阵,并使用seaborn的heatmap函数绘制其对应的热度图:
cm = np.corrcoef(df[cols].values.T)
sns.set(font_scale=1.5)
hm = sns.heatmap(cm,cbar=True,annot=True,square=True,fmt='.2f',annot_kws={'size':15},yticklabels=cols,xticklabels=cols)
从结果图像中可见,相关系数矩阵为我们提供了另外一种有用的图形化数据描述方式,由此可以根据各特征间的线性相关性进行特征选择:
为了拟合线性回归模型,我们主要关注那些跟目标变量MEDV高度相关的特征。观察前面的相关系数矩阵,可以发现MEDV与变量LSTAT的相关性最大(-0.74)。
大家应该还记得,前面的散点图矩阵显示LSTAT和MEDV之间存在明显的非线性关系。另一方面,正如散点图矩阵所示,RM和MEDV间的相关性也较高(0.70),
考虑到从散点图中观察到了这两个变量之间的线性关系,因此,在后续小节,中使用RM作为解释变量进行简单线性回归模型训练,是一个较好的选择。
基于最小二乘法构建线性回归模型:
在本章开始时讨论过,可将线性回归模型看作通过训练数据的样本点来寻找一条最佳拟合直线。
不过,在此既没有对最佳拟合做出定义,也没有研究拟合类似模型的各种技术。
在接下来的小节中,我们将消除读者对上述问题的疑惑:通过最小二乘法(Ordinary Least Squares,OLS)估计回归曲线的参数,
使得回归曲线到样本点垂直距离(残差或误差)的平方和最小。
通过梯度下降计算回归参数:
第2章中介绍的自适应线性神经元(Adaptive Linear Neuron,Adaline):人工神经元中使用了一个线性激励函数,同时还定义了一个代价函数J(·),
通过梯度下降(Gradient Descent,GD)、随机梯度下降(Stochastic Gradient Descent,GD)等优化算法使得代价函数最小,从而得到相应的权重。
Adaline中的代价函数就是误差平方和(Sum of Squared Error,SSE),它等同于我们这里定义的OLS代价函数
注意,此处的系数1/2仅是为了方便推导GD更新规则
本质上,OLS线性回归可以理解为无单位阶跃函数的Adaline,这样我们得到的是连续型的输出值,而不是以-1和1来代表的类标。
为了说明两者的相似程度,使用第2章中实现的GD方法,并且移除其单位阶跃函数来实现我们第一个线性回归模型
def predict(self,X):
return self.net_input(X) # np.where(self.activation(X)>=0.0,1,-1)
为了在实践中熟悉LinearRegressionGD类,我们使用了房屋数据集中的RM(房间数量)作为解释变量来训练模型以预测MEDV(房屋价格)。
此外,为了使得梯度下降算法收敛性更佳,在此对相关变量做了标准化处理。
第2章中曾介绍过,梯度下降算法能够进行收敛性检查,使用这类优化算法时,
将代价看作迭代次数的函数(基于训练数据集),并将其绘制成图是个非常好的做法。
简而言之,我们将再次绘制迭代次数对应的代价函数的值,以检查线性回归是否收敛:
接下来,我们将线性回归曲线与训练数据拟合情况绘制成图。
为达到此目的,我们定义了一个辅助函数用来绘制训练样本的散点图,同时绘制出相应的回归曲线
def lin_regplot(X,y,model):
plt.scatter(X,y,c="blue")
plt.plot(X,model.predict(X),color='red')
上述结论是基于直觉观察得到的,但是数据也同样告诉我们,房间数在很多情况下并不能很好地解释房价。
本章后续内容将讨论如何量化回归模型的性能。有趣的是,我们观察到一条奇怪的直线y=3,这意味着房价被限定了上界。
在某些应用中,给出变量在原始取值区间上的预测值也是非常重要的。
为了将预测价格缩放到以1000美元为价格单位的坐标轴上,我们使用了StandardScaler的inverse_transform方法:
num_rooms_std = sc_x.transform(np.array([5.0]).reshape(-1,1))
price_std = lr.predict(num_rooms_std)
print(sc_y.inverse_transform(price_std))
值得一提的是:对于经过标准化处理的变量,我们无需更新其截距的权重,因为它们在y轴上的截距始终为0。我们可以通过输出其权重来快速确认这一点
使用scikit-learn估计回归模型的系数:
上一小节中,我们实现了一个可用的回归分析模型。不过在实际应用中,我们可能会更关注如何高效地实现模型,
例如,scikit-learn中的LinearRegression对象使用了LIBLINEAR库以及先进的优化算法,可以更好地使用经过标准化处理的变量。
slr = LinearRegression()
slr.fit(X,y)
执行上述代码后可见,使用经过标准化处理的RM和MEDV数据拟合scikit-learn中的LinearRegression模型得到了不同的模型系数。
在大多数介绍统计科学的教科书中,都可以找到使用最小二乘法求解线性方程组的封闭方法:
w_1 = (XTX)^-1 XTy
w_0 = uy-uy^uy^
这种方法的优点在于:它一定能够分析找到最优解。
不过,如果要处理的数据集量很大,公式中逆矩阵的计算成本会非常高,或者矩阵本身为奇异矩阵(不可逆),
这就是在特定情况下我们更倾向于使用交互式方法的原因。