机器学习中维度的诅咒
许多机器学习从业者可能已经到了一个十字路口,他们必须选择他们想要包含在他们的机器学习模型中的特征的数量。这个决定实际上取决于许多因素。例如,您可能需要了解数据的性质,特征是否有贡献(是某种ID)?特征是multi-collinear吗?你有多少个样品?机器学习从业者经常使用高维向量来创建模型。由于高于k = 3的维度无法可视化,因此我们通常很难知道我们的机器学习模型构造是对还是错。在这篇文章中,我将说明维度的诅咒,这是一个强大的概念,其中向量空间的体积随着维度呈指数增长,导致我们的数据非常稀疏并且彼此远离。
高维空间
让我们通过考虑超立方体内部的超球面来说明高维空间的广阔性。在二维或三维中,它们看起来像这样
虽然在更高维度上不可视化,但我们可以在任何N维中概括超立方体内的超球面的概念。
现在让我们考虑一个边s = 2r的超立方体,其中r是超球面的半径。为了显示空间增长的速度,我将考虑超立方体与超球面比的体积。如果超球面随着维度的增长消耗了更多的体积,那么比值应该收敛到1。相反地,如果超球面随着维度的增长而消耗的体积更小,那么比值应该收敛到0。(解析解是比率应该收敛到0.)
在这里,我们将进行蒙特卡罗模拟,以证明这是真的。首先,我们从k维的均匀随机分布中采样数据点。然后我们从原点计算出这个点的欧几里德距离; 如果距离低于r,则该点位于半球r的超球面内,反之亦然。我们计算这种情况发生的次数的分数。Python实现如下:
import numpy as np from scipy.spatial.distance import euclidean import matplotlib.pyplot as plt def simulate(N=int(1e6), r=1, k=2): unif = np.random.uniform(0, 1, size=(N, k)) count = 0 for i in range(N): if euclidean(np.zeros((1,k)), unif[i]) < r: count += 1 hypercube_volume = (2*r)**k print("Volume of hypercube = ", hypercube_volume) print("Fraction of points inside hypersphere = ", ((count / N) * 4) / hypercube_volume) print("-----------------------------------------") return ((count / N) * 4) / hypercube_volume R = range(1, 100) lst = [] for r in R: frac = simulate(r=r) lst.append(frac) plt.plot(lst) plt.show()
结果如下:
在上图中,x轴是维数,y轴是超球面与超立方体体积的体积。具有来自k维均匀随机分布的100万个样本的简单运行,其中k的范围从1到100,给出以下统计。
k = 2
Volume of hypercube = 4
Fraction of points inside hypersphere = 0.784581
-----------------------------------------
k = 3
Volume of hypercube = 16
Fraction of points inside hypersphere = 0.25
-----------------------------------------
k=4
Volume of hypercube = 36
Fraction of points inside hypersphere = 0.1111111111111111
...
k=99
Volume of hypercube = 38416
Fraction of points inside hypersphere = 0.00010412328196584757
-----------------------------------------
k=100
Volume of hypercube = 39204
Fraction of points inside hypersphere = 0.00010203040506070809
-----------------------------------------
如上所示,该分数呈指数减小并收敛于零。这对数据科学家来说具有强大的意义,如果你增加数据的维数,你需要指数级更多的数据来弥补空间的巨大(即数据的稀疏性)。因此,下次当您考虑向数据/模型添加更多特征时,请考虑当维度变得过大时可能出现的潜在问题。最后,我鼓励您使用代码并更改一些参数以便自己查看此效果!