1

我有两个数组。一个是nby ,p另一个是dby 。我希望我的输出是by ,当我在下面构造张量时,我可以很容易地实现这一点。但是,我想在没有那个循环的情况下做到这一点。prdnrB

import numpy

X = numpy.array([[1,2,3],[3,4,5],[5,6,7],[7,8,9]]) # n x p
betas = numpy.array([[[1,2],[1,2],[1,2]], [[5,6],[5,6],[5,6]]]) # d x p x r

print X.shape
print betas.shape

B = numpy.zeros((betas.shape[0],X.shape[0],betas.shape[2]))
print B.shape

for i in range(B.shape[0]):
    B[i,:,:] = numpy.dot(X, betas[i])

print "B",B

C = numpy.tensordot(X, betas, axes=([1],[0]))
print C.shape

我尝试了各种方法来C匹配B,但到目前为止我一直没有成功。有没有不涉及调用的方法reshape

4

3 回答 3

4

由于dot规则是“A 的最后一个,B 的第二个到最后一个”,因此您可以执行X.dot(betas)并获得一个 (n,d,r) 数组(这在共享p维度上求和)。然后你只需要一个转置来得到 (d,n,r)

In [200]: X.dot(betas).transpose(1,0,2)
Out[200]: 
array([[[  6,  12],
        [ 12,  24],
        [ 18,  36],
        [ 24,  48]],

       [[ 30,  36],
        [ 60,  72],
        [ 90, 108],
        [120, 144]]])

我们也可以einsum直接从维度规范中编写版本:

np.einsum('np,dpr->dnr', X,betas)

也是如此matmul(这dot在最后 2 个轴上确实如此,而d随着骑行而来)。

X@betas
  • 如果任一参数为 ND,N > 2,则将其视为驻留在最后两个索引中的矩阵堆栈并相应地广播。
于 2018-01-30T00:06:09.757 回答
1

我们可以使用np.tensordot然后需要置换轴 -

B = np.tensordot(betas, X, axes=(1,1)).swapaxes(1,2)
# Or np.tensordot(X, betas, axes=(1,1)).swapaxes(0,1)

相关帖子了解tensordot

于 2018-01-29T22:51:21.897 回答
1

这是另一种使用 的方法numpy.dot(),它也可以根据您的要求返回一个视图,最重要的是比tensordot方法快 4 倍以上,特别是对于小型数组。但是,对于相当大的数组来说,np.tensordot它比普通的要快得多。np.dot()请参阅下面的时间安排。

In [108]: X.shape
Out[108]: (4, 3)

In [109]: betas.shape
Out[109]: (2, 3, 2)

# use `np.dot` and roll the second axis to first position
In [110]: dot_prod = np.rollaxis(np.dot(X, betas), 1)

In [111]: dot_prod.shape
Out[111]: (2, 4, 2)

# @Divakar's approach
In [113]: B = np.tensordot(betas, X, axes=(1,1)).swapaxes(1,2)

# sanity check :)
In [115]: np.all(np.equal(dot_prod, B))
Out[115]: True

现在,两种方法的性能:


# @Divakar's approach
In [117]: %timeit B = np.tensordot(betas, X, axes=(1,1)).swapaxes(1,2)
10.6 µs ± 2.1 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

# @hpaulj's approach
In [151]: %timeit esum_dot = np.einsum('np, dpr -> dnr', X, betas)
4.16 µs ± 235 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

# proposed approach: more than 4x faster!!
In [118]: %timeit dot_prod = np.rollaxis(np.dot(X, betas), 1)
2.47 µs ± 11.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)


In [129]: X = np.random.randint(1, 10, (600, 500))
In [130]: betas = np.random.randint(1, 7, (300, 500, 300))

In [131]: %timeit B = np.tensordot(betas, X, axes=(1,1)).swapaxes(1,2)
18.2 s ± 2.41 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [132]: %timeit dot_prod = np.rollaxis(np.dot(X, betas), 1)
52.8 s ± 14.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
于 2018-01-30T00:13:42.877 回答