KNN算法与大数据集处理

KNN(K-Nearest Neighbors)算法是经典的人工智能算法之一,它通过寻找最近的邻居来实现分类或相似性查找。KNN算法在处理低维小数据集时表现出色,但随着数据维度的增加或数据量的增大,其效率急剧下降。维度的增加导致所谓的“维度灾难”,而数据点数量的增加则导致测试时间变得异常长。本文将不探讨维度灾难,而是聚焦于如何将KNN算法应用于大数据集。

深入分析KNN的时间复杂度,发现KNN的训练时间为O(1),而测试时间为O(nd*m)(其中n代表训练样本数量,d代表数据维度,m代表测试样本数量)。对于大数据集来说,这个时间复杂度会急剧增加。以测试为例,一个训练样本大小为(240000 x 728)和一个测试样本大小为(40000 x 728),计算测试集中每个向量与训练集中每个向量的欧几里得距离需要大约12小时。这突显了寻找更优策略来计算最近邻居的重要性。本文讨论了一种通过近似距离计算来找到最近邻居的策略,即产品量化,它利用查找表的概念,从而节省了冗余计算并大幅提升了速度。

要识别K的最近邻居,首先需要创建一个距离矩阵,其中计算每个测试向量与每个训练向量的距离。然后,这个矩阵可以用来选择具有最低值的K个最近邻居。需要的是类似于下图所示的距离矩阵。初步看来,要计算这个矩阵,需要运行两个循环;一个循环遍历训练样本,另一个循环遍历测试样本。

for test_sample in Test { for ele in train { dist[i][j] = dist(ele, test_sample) } }

但是,在小标题中提到,这个问题可以不使用任何循环来解决。让回顾一些基本的数学知识来解决这个问题,而不需要循环。欧几里得距离的计算公式为:Sqrt((a1-a2)² + (b1-b2)² + … + (n1-n2)²)。为了填充上述矩阵,可以工作在平方距离上,因为目标是找到最近的邻居,而不是在线性尺度上计算距离。

让使用一些基本的数学来修改距离方程:(a-b)² = a² + b² - 2ab。有趣的是,Python可以通过NumPy比使用循环更快地执行乘法运算。在系统上,对于两个随机矩阵的大小为(100×100),使用循环需要0.47秒,而直接矩阵乘法只需要0.003秒。这意味着矩阵乘法在不使用循环的情况下快了156倍。上述公式也可以很容易地应用于矩阵。下面给出了计算距离矩阵的最快方法。

def compute_distances_no_loops(self, X): dists = -2 * np.dot(X, self.X_train.T) + np.sum(self.X_train**2, axis=1) + np.sum(X**2, axis=1)[:, np.newaxis] return dists

这种方法是完美的,但对于大数据集来说,由于极高的内存需求,这是不切实际的。训练样本大小为(240000 x 728),测试样本大小为(40000 x 728),需要72GB的RAM来计算距离矩阵。

可以通过在测试向量的每个样本上运行循环来解决内存问题,将每个测试向量视为一个完整的矩阵,并使用上述公式来计算距离。

def compute_distances_one_loop(self, X): dists = np.zeros((num_test, num_train)) for i in xrange(num_test): dists[i, :] = np.sum((self.X_train - X[i, :])**2, axis=1) return dists

上述技术可能适用于相当大的数据集,但当涉及到实际拥有数十亿行的数据集时,使用这些技术变得不可能。这时,产品量化技术应运而生,用于近似最近邻居。

以下是需要遵循的步骤:

  1. 将每个训练向量分成等大小的块。以情况为例,将每个大小为(1×600)的训练向量分成(6次1×100)。总共有n个训练向量。
  2. 为每个块运行一个单独的K-means算法。以情况为例,K=3。将为每个块得到3个中心点。让称它们为(A1, A2, A3),(B1, B2, B3)…,(F1, F2, F3)。
  3. 为每个块分配其最近的聚类。这是训练矩阵的象征性表示。
  4. 为每个块创建一个距离图。所有这些块将存储两个(1×100)大小向量之间的距离。例如,如果想计算中心点A1和A2之间的距离,只需要使用基本的欧几里得距离或其他距离,如平方距离或L1距离。
  5. 现在可以为测试数据找到K个最近邻居。从测试数据中取一个样本,称之为Test[0],并将其分成相同数量的块。
  6. 使用与所有三个中心点的最小欧几里得距离为每个块分配一个ID。块1将被分配给A1、A2或A3。块2将被分配给B1、B2或B3。其他块也适用。
  7. 现在,使用距离图将象征性测试向量(Test[0])与所有训练向量进行比较,并存储它们之间的距离。
  8. 一旦有了总距离,选择具有最低总距离的前k个索引。给定Test[0]向量的最近邻居将仅出现在这些索引处。

有些人可能仍在思考这如何节省时间。它节省时间是因为它只需要将块与中心点进行比较以分配ID,然后使用距离图来计算距离,距离图的时间复杂度为O(1)。让为情况做一些计算。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485