【问题标题】:Pairwise Distance with Large NumPy Arrays (Chunking?)大型 NumPy 数组的成对距离(分块?)
【发布时间】:2020-09-10 04:52:25
【问题描述】:

问题: 我有一个大约 [350000, 1] 的向量,我希望计算成对距离。这会导致不适合 RAM 的整数数据类型的 [350000, 350000] 矩阵。我最终想得到一个布尔值(适合 RAM),所以我目前一次只做一个元素,但这不是很省时。

编辑:由于数据的大小,标准的 sklearn 和 scipy 函数不起作用——但如果我能以某种方式将其分块以使用硬盘,那么我应该能够使用这些。

问题可视化: [a_1, a_2, a_3]^t -> [[a_1 - a_1, a_1 - a_2, a_1 - a_3], [a_2 - a_1, a_2 - a_2, a_2 - a_3], [a_3 - a_1, a_3 - a_2, a_3 - a_3]]

注意,取abs值时,只需要计算上三角形,因为它是对称的。

需要分块或替代解决方案的矢量化代码: 我找到了一种方法来计算所有点之间的距离(减法),该方法使用广播在一个小矩阵上工作,但需要一种能够在更大的矩阵上执行此操作而不会遇到 RAM 限制的方法。

或者也许可以建议一种更快的 MWE 下面的更好方法?

distMatrix = np.absolute((points[np.newaxis, :, :] - points[:, np.newaxis, :])[:, :, 0])

其他尝试: 我尝试过使用 dask 和 memmap,但仍然出现内存错误,所以一定是做错了什么。我也尝试过 memmap 并手动分块数据,但没有获得完整的结果集,因此非常感谢任何帮助。

当前方法的 MWE:


## Data ##
#Note that the datatype and code may not match up exactly as just creating to demonstrate. Essentially want to take first column and create distance matrix with itself through subtracting, and then take 2nd and 3rd column and create euclidean distance matrix.

data = np.random.randint(1, 5, size=[350001,3])
minTime = 3
maxTime = 4
minDist = 1
maxDist = 2

### CODE ###
n = len(data)

for i in trange(n):
    for j in range(i+1, n):
        #Within time threshold?
        if minTime <= (data[j][idxT] - data[i][idxT]) <= maxTime:
            #Within distance threshold?
            xD = math.pow(data[j][idxX] - data[i][idxX], 2)
            yD = math.pow(data[j][idxY] - data[i][idxY], 2)
            d = math.sqrt(xD + yD)
            #If within  threshold then
            if minDist <= d <= maxDist:
                #DO SOMETHING

原因: 我有大约 350000 个点的时间、x_coordinate、y_coordinate 向量。我想计算所有时间点之间的距离(简单减法)和每个(x,y)点之间的欧几里得距离。然后,我希望能够识别在彼此的时间和距离发生阈值内的所有点对,从而产生一个布尔值。

【问题讨论】:

  • 这能回答你的问题吗? Fastest pairwise distance metric in python
  • 您对欧几里得距离还是基于绝对距离的距离感兴趣?
  • @Divakar 对两者都感兴趣,但如果我得到基于绝对值的工作,那么我可以从那里计算欧几里得
  • 你能用示例数据添加最少的可运行代码吗?
  • @Divakar 已修改。

标签: python numpy distance chunking


【解决方案1】:

您可以将数组拆分为更小的数组,并分别计算每对数组的距离。

splits = np.array_split(data, 10)
for i in range(len(splits)):
    for j in range(i, len(splits)):
        m = scipy.spatial.distance.cdist(splits[i], splits[j])
        # do something with m

因为大多数计算发生在 scipy 中,python 循环的开销将是最小的。

如果您的布尔数组适合内存,并且您尝试查找在特定范围内可以执行的值

import numpy as np
import scipy.spatial.distance


boolean = np.zeros((350, 350), dtype=np.bool_)
a = np.random.randn(350, 2)
splits = np.array_split(a, 10)
shift = splits[0].shape[0]
minDist = -0.5
maxDist = +0.5
for i in range(len(splits)):
    for j in range(i, len(splits)):
        m = scipy.spatial.distance.cdist(splits[i], splits[j])
        masked = (minDist <= m) & (m <= maxDist)
        boolean[i * shift: (i + 1) * shift, j * shift : (j + 1) * shift] = masked
        boolean[j * shift : (j + 1) * shift, i * shift: (i + 1) * shift] = masked.T

【讨论】:

  • @v-ayrat 如何将 m 个矩阵连接在一起,使其产生与不拆分相同的结果?
  • @DanielJ 我更新了答案。是你需要的吗?
  • 不完全是,但足以让我得到我需要的东西来让我上路。干杯!
  • @v-ayrat 当我使用 350,000 的向量运行它时,速度非常慢 - 我以这个速度计算了大约 90 小时,这只是一个布尔值,不包括我的其他操作,总共目前需要20个小时。我也玩过调整块的大小。有没有办法加快速度?单独遍历每个会更快:(
  • 我怀疑这是计算时间。根据您的系统,它最多需要半小时。您可以尝试用boolean = ...boolean[j * ... 注释掉行,这意味着您只计算而不将值存储在内存中。如果它快得多,那么问题出在内存上。即使是这种大小的布尔矩阵也应该是大约 100 Gb,因此它不会存储在您的 RAM 中,它会在您的计算过程中不断交换。在这种情况下,您有 2 个选项:关闭所有辅助程序并希望该数组适合您的 RAM - 我怀疑这会有所帮助。第二:你是否对每个进一步计算
猜你喜欢
  • 1970-01-01
  • 2020-02-21
  • 2017-06-15
  • 2020-10-29
  • 1970-01-01
  • 2015-06-05
  • 2015-11-13
  • 1970-01-01
  • 2017-04-21
相关资源
最近更新 更多