我正在用下面的 python 代码计算欧氏距离:
def getNeighbors(trainingSet, testInstance, k, labels):
distances = []
for x in range(len(trainingSet)):
dist = math.sqrt(((testInstance[0] - trainingSet[x][0]) ** 2) + ((testInstance[1] - trainingSet[x][1]) ** 2))
distances.append([dist, labels[x]])
distances = np.array(distances)
return distances
用于计算给定点与其他 10 个点的距离,这很好。但是当我计算一个点与 18563 个其他点的距离时,计算机会挂起并且在大约 3 小时内没有响应。
如何更快地计算 18563 点?
请您参考如下方法:
您可以通过先转换为 NumPy,然后使用向量运算来加快此过程,而不是在循环中执行工作,然后再转换为 NumPy。像这样:
trainingArray = np.array(trainingSet)
distances = ((testInstance[0] - trainingArray[:, 0]) ** 2 +
(testInstance[1] - trainingArray[:, 1]) ** 2).sqrt()
(这显然是未经测试的,因为没有足够的上下文来了解我不得不猜测的那些变量中的实际内容,但它会接近那个。)
您还可以做一些其他事情来挤出一些额外的 %——尝试用自乘替换 ** 2 或用 * 替换 ,或者(可能是最好的)用 sqrt * .5np.hypot 替换整个文件。 (如果您不知道如何使用 timeit — 或者更好的是,IPython 和它的 %timeit 魔法 — 现在是学习的好时机。)
但最终,这只会为您提供大约一个数量级的常数乘数加速。也许需要 15 分钟而不是 3 小时。很好,但是……为什么一开始就花了 3 个小时?您在这里所做的应该以秒为单位,甚至更短。这里显然有一些更大的错误,比如当你认为你只调用它一次时,你可能调用了这个函数 N**2 次。你真的需要修复那个部分。
当然这样做还是值得的。首先,逐元素操作比循环更简单、更易读,也更不容易出错。其次,即使您将整个程序缩短到 3.8 秒,您也会为 0.38 秒的数量级加速而感到高兴,对吗?
