Logo
Section 1 / 6

增加更多维度

探索当我们处理越来越多维度的数据时会发生什么。

导入

增加更多维度

探索当我们处理越来越多维度的数据时会发生什么。

我们目前所涵盖的内容

在前面两章中,我们根据输入预测输出,例如根据餐厅的预订人数预测披萨销量。然而,大多数现实世界中的问题并不仅仅依赖一个输入变量。即便是披萨销量这种看似简单的问题,也不太可能只由预订量决定。例如,如果城里游客较多,即使预订数量和昨天一样,餐厅的披萨销量也可能更高。

如果披萨销量受多个变量影响,那么当我们进入更复杂的领域(如图像识别)时,需要考虑的变量数量将更加庞大。一个仅支持单个变量的学习程序永远无法解决这些复杂问题。如果我们希望应对这类挑战,就必须升级程序,使其能够支持多个输入变量。

我们可以使用线性回归的一种高级形式——多元线性回归(multiple linear regression),来从多个输入变量中进行学习。在本章中,我们将扩展程序以支持多元线性回归。同时,我们还将掌握一些实用技巧,包括几种重要的矩阵运算和 NumPy 函数。现在就开始吧!

这可能是整个课程中最难的一章,原因有两个:第一,它在一定程度上高度依赖数学知识;第二,本章的代码虽然简洁,但内涵深刻。在某个部分,我们会用大量篇幅来解释一行代码。

请不要被这些挑战吓退。本章介绍的概念和技术是机器学习的核心,非常值得深入学习。而且可以预见的是,学完这一章后,课程其余部分的内容都会显得轻松许多。

变量越多,维度越高

在上一章中,我们编写了一个基于梯度下降的学习程序版本。这个进阶版程序理论上可以扩展到包含多个变量的复杂模型。

有一次我们一时心软,向朋友罗伯托提到了这一点,结果酿成了“错误”。现在罗伯托热情高涨,想要利用除预订量之外的多种输入变量(如天气、城内游客数量等)来预测披萨销量。

这无疑会给我们带来更多的工作量。不过我们也不能怪披萨店老板想往模型里添加更多变量,毕竟考虑的变量越多,就越有可能准确预测披萨销量。

让我们先来看一个更详细的 pizza.txt 文件版本。以下是新数据集的前几行内容:

预订量温度(℃)披萨销量
132644
21423
142028

店主怀疑天气越暖和,进店消费的人越多,因此记录了每日摄氏温度(作为参考:2℃接近冰点,26℃属于常温)。现在第三列是标签(即披萨销量),前两列则是输入变量。

首先,我们来看看当输入变量从一个增加到两个时,线性回归会发生什么变化。我们知道,线性回归的本质是用一条直线去拟合样本数据,如下图所示:

...
对数据应用线性回归模型

回顾一下,这条直线的公式为:

y^=x∗w+b\hat{y} = x * w + b

当我们加入第二个输入变量(温度)后,数据点就不再落在二维平面上,而是分布在三维空间中。为了拟合这些点,我们可以使用“平面”——即比直线多一个维度的几何对象,如下图所示:

...
尝试为数据集拟合一个平面

以下代码用于生成上述图形:

1# 绘制一个大致拟合双输入变量数据集的平面 2import numpy as np 3import matplotlib.pyplot as plt 4from matplotlib import cm 5from mpl_toolkits import mplot3d 6import seaborn as sns 7 8# 导入数据集 9x1, x2, x3, y = np.loadtxt("pizza_3_vars.txt", skiprows=1, unpack=True) 10 11# 这些权重来自训练阶段的结果 12w = np.array([-3.98230894, 0.37333539, 1.69202346]) 13 14# 设置绘图背景 15sns.set(rc={"axes.facecolor": "white", "figure.facecolor": "white"}) 16fig = plt.figure() 17ax = plt.axes(projection='3d') 18ax.set_xlabel("温度", labelpad=15, fontsize=15) 19ax.set_ylabel("预订量", labelpad=15, fontsize=15) 20ax.set_zlabel("披萨销量", labelpad=5, fontsize=15) 21 22# 绘制数据点 23ax.scatter3D(x1, x2, y, color='b') 24 25# 绘制平面 26MARGIN = 10 27edges_x = [np.min(x1) - MARGIN, np.max(x1) + MARGIN] 28edges_y = [np.min(x2) - MARGIN, np.max(x2) + MARGIN] 29xs, ys = np.meshgrid(edges_x, edges_y) 30zs = np.array([w[0] + x * w[1] + y * w[2] for x, y in 31 zip(np.ravel(xs), np.ravel(ys))]) 32ax.plot_surface(xs, ys, zs.reshape((2, 2)), alpha=0.2) 33 34plt.show()

我们可以使用平面方程来计算预测值 y^\hat{y}。该方程与直线方程类似,但包含两个输入变量 x1x_1 和 x2x_2,以及对应的两个权重 w1w_1 和 w2w_2:

y^=x1∗w1+x2∗w2+b\large{\hat{y} = x_1 * w_1 + x_2 * w_2 + b}

需要注意的是,在罗伯托的数据集中,x1x_1 表示预订量,x2x_2 表示温度。显然,预订量和温度对披萨销量的影响程度不同,因此它们应具有不同的权重。

在线性方程中,偏置项 bb 的作用是将直线从原点移开。对于平面也是如此:如果没有偏置项 bb,平面将被迫经过坐标系原点。要验证这一点,只需将所有输入变量设为 00。此时若无偏置项,则 y^\hat{y} 也为 00。而有了偏置项后,平面就可以自由地沿垂直方向移动,从而找到最佳拟合位置。

现在设想一下,如果披萨店老板又在数据集中添加了新的一列:

预订量温度(℃)游客密度披萨销量
1326944
214623
1420328

这个新输入变量表示城内游客密度,数据来源于当地旅游局网站,取值范围为 1(无人问津)到 10(游客爆满)。

我们最初是用一维模型(直线)去拟合二维数据点;接着用二维模型(平面)去拟合三维数据点;现在面对四维数据,我们必须使用三维模型来拟合。随着输入变量的增加,这一过程持续延伸下去:要拟合 nn 维的数据,就需要一个 (n−1)(n−1) 维的几何结构。

人类无法直观感知超过三个空间维度,但数学对此毫无障碍。数学将这些超越直觉的高维空间称为 超空间(hyperspaces),并使用与二维、三维空间相同的方程来描述它们。无论维度多高,我们都可以通过不断向直线和平面的公式中添加输入变量及其对应权重来扩展模型:

y^=x1∗w1+x2∗w2+x3∗w3+⋯+b\large{\hat{y} = x_1 * w_1 + x_2 * w_2 + x_3 * w_3 + \dots + b}

这个表达式被称为 输入的加权和(weighted sum of the inputs)。直线方程只是这个通用公式的特例——即仅有一个输入变量时的加权和。因此,我们将采用一个简单的升级策略:把原来基于直线方程的程序,改为使用更通用的加权和公式,从而支持多个输入变量。

批量处理

矩阵数学