如何将numpy元组数组乘以标量数组

3
我有一个形状为(N,2)的numpy数组A和一个形状为(N)的numpy数组S。
我该如何将两个数组相乘?目前我正在使用以下代码:
tupleS = numpy.zeros( (N , 2) )
tupleS[:,0] = S
tupleS[:,1] = S
product = A * tupleS

我是一名Python初学者。有没有更好的方法来解决这个问题?

5个回答

6
Numpy使用行优先顺序,因此您需要显式地创建列。如下所示:
>> A = numpy.array(range(10)).reshape(5, 2)
>>> B = numpy.array(range(5))
>>> B
array([0, 1, 2, 3, 4])
>>> A * B
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: shape mismatch: objects cannot be broadcast to a single shape
>>> B = B.reshape(5, 1)
>>> B
array([[0],
       [1],
       [2],
       [3],
       [4]])
>>> A * B
array([[ 0,  0],
       [ 2,  3],
       [ 8, 10],
       [18, 21],
       [32, 36]])

值得注意的是,reshape 创建的是一个视图,而不是一个副本: >>> s = numpy.arange(5); s.reshape(5, 1)[3,0] = 99; repr(s) -> 'array([ 0, 1, 2, 99, 4])'. 因此,您可以只需执行 A * B.reshape(5, 1) 而不更改 B - senderle

3

实际上与@senderle的答案基本相同,但不需要对S进行原地操作。您可以通过在索引None处添加轴的方式来获取数组的切片,并且这将使它们相乘:A * S [:,None]

>>> S = np.arange(5)
>>> S
array([0, 1, 2, 3, 4])
>>> A = np.arange(10).reshape((5,2))
>>> A
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7],
       [8, 9]])
>>> S[:,None]
array([[0],
       [1],
       [2],
       [3],
       [4]])
>>> A * S[:,None]
array([[ 0,  0],
       [ 2,  3],
       [ 8, 10],
       [18, 21],
       [32, 36]])

1

你试过这个吗:

product = A * S

+1,始终使用numpy的广播特性是最佳选择。 - lafras
@Stiefel,@MRAB,我认为问题在于您必须为广播工作重新塑造S - senderle
对,A*S由于形状不匹配而无法工作。重新塑形确实是解决方案。 - Stiefel

1

虽然你的问题标题有点不准确,但我认为你遇到的问题主要与 numpybroadcasting规则有关。因此,以下操作是无效的(就像你已经发现的那样):

In []: N= 5
In []: A= rand(N, 2)
In []: A.shape
Out[]: (5, 2)

In []: S= rand(N)
In []: S.shape
Out[]: (5,)

In []: A* S
------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython console>", line 1, in <module>
ValueError: operands could not be broadcast together with shapes (5,2) (5) 

然而,现在使S与广播规则(即A*S的逐元素乘积)兼容的简单方法是扩展其维度,例如:
In []: A* S[:, None]
Out[]: 
array([[ 0.54216549,  0.04964989],
       [ 0.41850647,  0.4197221 ],
       [ 0.03790031,  0.76744563],
       [ 0.29381325,  0.53480765],
       [ 0.0646535 ,  0.07367852]])

但这实际上只是expand_dims的语法糖,例如:

In []: expand_dims(S, 1).shape
Out[]: (5, 1)

无论如何,我个人更喜欢这种简单而不费力的方法:
In []: S= rand(N, 1)
In []: S.shape
Out[]: (5, 1)

In []: A* S
Out[]: 
array([[ 0.40421854,  0.03701712],
       [ 0.63891595,  0.64077179],
       [ 0.03117081,  0.63117954],
       [ 0.24695035,  0.44950641],
       [ 0.14191946,  0.16173008]])

因此,使用Python编程时,显式比隐式更为直观。


谢谢,我已经修改了标题。很好的答案。我接受了senderles的答案,因为它是最简单的。所有的答案都以某种方式旨在将形状修改为(N,1)。 - Stiefel

-1

我能想到:

product = A * numpy.tile(S, (2,1)).T

一个更快的解决方案可能是:
product = [d * S for d in A.T]

虽然这不会给你一个numpy数组作为输出,并且它是转置的。所以要得到一个类似的numpy数组(请注意,这比第一个解决方案慢):
product = numpy.array([d * S for d in A.T]).T

可能还有十几种其他有效的解决方案,其中包括比这些更好的方案...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接