当我使用元素乘法 (*) 时,R 和 Python 之间的不同广播规则

Different broadcasting rules between R and Python when I use elementwise multiplication (*)

我在 R 和 Python 中尝试了矩阵和向量的逐元素乘法 (*),并收到了如下不同的结果。

这是R:

#R input
a=matrix(c(1,2,3,4,5,6,7,8),byrow=T,nrow=4)
b=c(9,10)
print(a)
print(b)
print(a*b)

#R output
# a
     [,1] [,2]
[1,]    1    2
[2,]    3    4
[3,]    5    6
[4,]    7    8
# b
[1]  9 10
# a*b
 [,1] [,2]
[1,]    9   18
[2,]   30   40
[3,]   45   54
[4,]   70   80

这是Python:

#Python input
a=np.array([[1,2],[3,4],[5,6],[7,8]])
b=np.array([9,10])
print(a)
print(b)
print(a*b)

#Python output
# a
[[1 2]
 [3 4]
 [5 6]
 [7 8]]
# b
[ 9 10]
# a*b
[[ 9 20]
 [27 40]
 [45 60]
 [63 80]]

看来R和Python在执行*的时候展开vector b的方式不同。 R 使用以下矩阵逐个元素相乘:

     [,1] [,2]
[1,]    9    9
[2,]    10   10
[3,]    9    9
[4,]    10   10

而 Python 使用以下矩阵:

[[ 9 10]
 [ 9 10]
 [ 9 10]
 [ 9 10]]

谁能解释一下为什么他们对 * 有不同的广播方式? Python 是否有任何函数或运算符导致 R 的相同结果?

谢谢!

我不知道 R,所以不会尝试解释它的行为。

In [130]: a=np.array([[1,2],[3,4],[5,6],[7,8]])
     ...: b=np.array([9,10])
In [131]: a.shape
Out[131]: (4, 2)
In [132]: b.shape
Out[132]: (2,)
In [133]: a*b
Out[133]: 
array([[ 9, 20],
       [27, 40],
       [45, 60],
       [63, 80]])

numpy的广播规则是

  • 根据需要添加主要尺寸
  • 根据需要调整尺寸 1。

在您的情况下,这相当于:

(4,2) * (2,) => (4,2) * (1,2) => (4,2) * (4,2) => (4,2)

b 被视为一个 (4,2) 数组,910 在 2 列中:

In [134]: a*b.reshape(1,2)
Out[134]: 
array([[ 9, 20],
       [27, 40],
       [45, 60],
       [63, 80]])

numpy 广播不会像 R 那样复制值,但您可以使用 repeattile 来这样做:

In [139]: b1 = np.tile(b[:,None],(2,1))
In [140]: b1
Out[140]: 
array([[ 9],
       [10],
       [ 9],
       [10]])
In [141]: a*b1
Out[141]: 
array([[ 9, 18],
       [30, 40],
       [45, 54],
       [70, 80]])

这里的尺寸是

(4,2) * (4,1) => (4,2)

即使我将 b 设为 (2,1),numpy 也不会像 R 那样重复:

In [144]: b[:,None]
Out[144]: 
array([[ 9],
       [10]])
In [145]: a*b[:,None]
Traceback (most recent call last):
  File "<ipython-input-145-a2236f333443>", line 1, in <module>
    a*b[:,None]
ValueError: operands could not be broadcast together with shapes (4,2) (2,1) 

R 代码使用 recycling rule, which says that if a vector is too short, it will be repeated as many times as needed to match the other operands. The Python code uses the numpy broadcasting rules 描述如果操作涉及不同形状的 numpy 数组会发生什么。这些规则不一样,结果不一样。

您可以通过多种方式使用 numpy 获得与 R 中相同的结果。例如:

a * np.tile(b, (1,2)).T 

它给出:

array([[ 9, 18],
       [30, 40],
       [45, 54],
       [70, 80]])