python – 广播视图不规则numpy

假设我想要一个numpy数组(n,m),其中n非常大,但有很多重复,即. 0:n1是相同的,n1:n2是相同的等(n2%n1!= 0,即不是规则的间隔).有没有办法只为每个重复项存储一组值,同时拥有整个数组的视图?

例:

unique_values = np.array([[1,1,1], [2,2,2] ,[3,3,3]]) #these are the values i want to store in memory
index_mapping = np.array([0,0,1,1,1,2,2]) # a mapping between index of array above, with array below

unique_values_view = np.array([[1,1,1],[1,1,1],[2,2,2],[2,2,2],[2,2,2], [3,3,3],[3,3,3]]) #this is how I want the view to look like for broadcasting reasons

我打算将数组(视图)乘以一些其他大小的数组(1,m),并取这个产品的点积:

other_array1 = np.arange(unique_values.shape[1]).reshape(1,-1) # (1,m)
other_array2 = 2*np.ones((unique_values.shape[1],1)) # (m,1)
output = np.dot(unique_values_view * other_array1, other_array2).squeeze()

输出是长度为n的一维数组.

最佳答案
您的表达式允许两个重要的优化:

>最后做索引
>首先将other_array1与other_array2相乘,然后再使用
 unique_values

让我们应用这些优化:

>>> output_pp = (unique_values @ (other_array1.ravel() * other_array2.ravel()))[index_mapping]

# check for correctness
>>> (output == output_pp).all()
True

# and compare it to @Yakym Pirozhenko's approach
>>> from timeit import timeit
>>> print("yp:", timeit("np.dot(unique_values * other_array1, other_array2).squeeze()[index_mapping]", globals=globals()))
yp: 3.9105667411349714
>>> print("pp:", timeit("(unique_values @ (other_array1.ravel() * other_array2.ravel()))[index_mapping]", globals=globals()))
pp: 2.2684884609188884

如果我们观察到两件事情,很容易发现这些优化:

(1)如果A是mxn矩阵,则b是n向量

A * b == A @ diag(b)
A.T * b[:, None] == diag(b) @ A.T

(2)如果A是anmxn矩阵,而I是整数的k向量
       范围(m)然后

A[I] == onehot(I) @ A

onehot可以定义为

def onehot(I, m, dtype=int):
    out = np.zeros((I.size, m), dtype=dtype)
    out[np.arange(I.size), I] = 1
    return out

使用这些事实并缩写uv,im,oa1和oa2我们可以写

uv[im] * oa1 @ oa2 == onehot(im) @ uv @ diag(oa1) @ oa2

现在,上述优化只是选择这些矩阵乘法的最佳阶数

onehot(im) @ (uv @ (diag(oa1) @ oa2))

使用(1)和(2)向后,我们从这篇文章的开头获得优化的表达式.

转载注明原文:python – 广播视图不规则numpy - 代码日志