【问题标题】:Numpy sum of minimums of two arrays like dot product efficiently两个数组的最小值的numpy总和,如点积有效
【发布时间】:2022-01-19 13:34:57
【问题描述】:

我想用 numpy 有效地得到两个数组的最小值之和。例如;

X=np.array([[1,2,3],[1,2,0]])
Y=np.array([[0,2,0],[1,3,1]])

我的结果应该是;

result = array([[2, 4],[2, 3]])

第一个单元格的计算;

result[0,0] = min(X[0,0],Y[0,0])+ min(X[0,1],Y[0,1])+min(X[0,2],Y[0,2])

一般来说,结果应该是:

res[i,j] = sum(np.minimum(X[i, :], Y[j, :]))

但正在寻找最快的方式。

【问题讨论】:

  • 我的解释:将所有向量相互结合:result[i,j] = sum(min(X[i, :], Y[j, :])).
  • 最佳方式取决于您的内存限制、向量的大小、列表的长度、您需要/拥有的实际数据结构(例如,它是否真的是 2d np 数组) ,最后我们是否需要一个 np 数组)。对我们有什么提示吗?
  • 数组形状类似于 (1000, 40000)。暂时没有内存限制,我正在寻找最快的方法。

标签: python numpy


【解决方案1】:

dot 相当于取外积,并在适当的轴上求和。

在你的情况下相当于:

In [291]: np.minimum(X[:,None,:], Y[None,:,:])
Out[291]: 
array([[[0, 2, 0],
        [1, 2, 1]],

       [[0, 2, 0],
        [1, 2, 0]]])
In [292]: np.sum(np.minimum(X[:,None,:], Y[None,:,:]),axis=-1)
Out[292]: 
array([[2, 4],
       [2, 3]])

【讨论】:

  • 我不知道np.minimum 能够广播。美丽的! :)
  • 虽然我担心在没有任何分割策略的情况下,对于给定的长度为 40000 的向量,您会遇到内存问题。
【解决方案2】:

我能做的最好的:

import numpy as np


def sum_mins(x, y):
    mask = (X - Y) < 0
    return np.sum(X*mask + Y*np.logical_not(mask))


X=np.array([1,2,3])
Y=np.array([0,2,0])

print(sum_mins(X, Y))

【讨论】:

    【解决方案3】:

    一种接近定义的幼稚方法:

    result = np.array([[np.sum(np.minimum(v_x, v_y)) for v_y in Y] for v_x in X])
    

    【讨论】:

    • 感谢您的回复,但我需要更有效的方法,因为我的数据非常大。这种方式太费时间了。
    • 是的,我想是的。这只是直接的方法。它可以作为所有伟大解决方案的参考:)
    • 我是这样测试的。这些结果的速度是点积的两倍,但似乎可以接受。
    • 出于好奇,您如何实现基于点积的解决方案?
    • 我正在尝试获取这些数组的相似度矩阵。我想使用加权 jaccard 相似度 (static.googleusercontent.com/media/research.google.com/en/us/…)。 sklearn.metrics.pairwise_distances(余弦)在 2 秒内完成。点积为 33 秒。你的解决方案是 67 秒。
    【解决方案4】:

    hpaulj 和我以前的答案(已删除)的组合,以防内存不足:

    # maximum number of float32s in memory - determining a max. chunk size
    MAX_CHUNK_MEM_SIZE = 1000 * 1024 * 1024 / 4
    
    
    def _fast_small(x, y):
        """Process a case with small size of x and y."""
        # see answer of @hpaulj
        return np.sum(np.minimum(x[:, None, :], y[None, :, :]), axis = -1)
    
    
    def fast(x, y):
        """Process a case with potentially large size of x and y."""
        assert len(x.shape) == len(y.shape) == 2
        assert x.shape[1] == y.shape[1]
        num_chunks = int(np.ceil(x.shape[0] * y.shape[0] * x.shape[0] / MAX_CHUNK_MEM_SIZE))
        result_blocks = []
        for x_block in np.array_split(x, num_chunks):
            result_blocks_row = []
            for y_block in np.array_split(y, num_chunks):
                result_blocks_row.append(_fast_small(x_block, y_block))
            result_blocks.append(result_blocks_row)
        return np.block(result_blocks)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-18
      • 2021-02-06
      • 1970-01-01
      • 2020-11-27
      • 1970-01-01
      • 2022-09-23
      • 2017-07-08
      • 1970-01-01
      相关资源
      最近更新 更多