将bsxfun的@times转换为numpy

12 投票
3 回答
8640 浏览
提问于 2025-04-18 05:50

这是我在Octave中写的代码:

sum(bsxfun(@times, X*Y, X), 2)

代码中的bsxfun部分实现了逐元素相乘,所以我以为用numpy.multiply(X*Y, X)也能达到同样的效果,但结果却出现了异常。经过一些研究,我发现逐元素相乘在Python数组上是行不通的(特别是当X和Y是“numpy.ndarray”类型时)。所以我想问问有没有人能多解释一下这个问题——也就是说,把类型转换成其他对象会有效吗?Octave的代码是可以工作的,所以我知道我没有线性代数方面的错误。我在想bsxfun和numpy.multiply实际上并不等价,但我不太明白为什么,所以任何解释都非常欢迎。

我找到一个网站!这个网站提供了Octave到Matlab的函数转换,但在我的情况下似乎没有帮助。

3 个回答

0

虽然有点晚了,但我想给大家举个例子,说明在Python中如何实现和bsxfunrepmat相同的功能。这段代码是我刚把Matlab的代码转换成Python numpy的。

Matlab代码:

x =

    -2
    -1
     0
     1
     2

n =

 2

M = repmat(x,1,n+1)

M =

    -2    -2    -2
    -1    -1    -1
     0     0     0
     1     1     1
     2     2     2


M = bsxfun(@power,M,0:n)

M =

     1    -2     4
     1    -1     1
     1     0     0
     1     1     1
     1     2     4

在Python中的等效代码:

In [8]: x
Out[8]: 
array([[-2],
       [-1],
       [ 0],
       [ 1],
       [ 2]])

In [9]: n=2

In [11]: M = np.tile(x, (1, n + 1))

In [12]: M
Out[12]: 
array([[-2, -2, -2],
       [-1, -1, -1],
       [ 0,  0,  0],
       [ 1,  1,  1],
       [ 2,  2,  2]])



In [13]:  M = np.apply_along_axis(pow, 1, M, range(n + 1))

In [14]: M
Out[14]: 
array([[ 1, -2,  4],
       [ 1, -1,  1],
       [ 1,  0,  0],
       [ 1,  1,  1],
       [ 1,  2,  4]])
3

对于那些不太了解Numpy的人,我想说,Numpy中和Octave(还有Matlab)里的*运算符(矩阵乘法)相对应的是numpy.dot(还有争议的numpy.outer)。Numpy的*运算符类似于Octave中的bsxfun(@times,...),后者其实是.*的一个推广。

在Octave中,使用bsxfun时,操作数的“真实”大小右边会有一些隐含的单例维度;也就是说,一个n1 x n2 x n3的数组可以看作是n1 x n2 x n3 x 1 x 1 x 1 x...。而在Numpy中,隐含的单例维度是在左边;所以一个m1 x m2 x m3的数组可以看作是... x 1 x 1 x m1 x m2 x m3。这在考虑操作数的大小时很重要:在Octave中,bsxfun(@times,a,b)会在a是2 x 3 x 4,b是2 x 3时正常工作。但在Numpy中,不能直接把这两个数组相乘,不过可以把一个2 x 3 x 4的数组和一个3 x 4的数组相乘。

最后,Octave中的bsxfun(@times, X*Y, X)大概看起来像是numpy.dot(X,Y) * X。不过还是有一些需要注意的地方:比如,如果你期待的是外积(也就是在Octave中X是列向量,Y是行向量),你可以考虑使用numpy.outer,或者要小心X和Y的形状。

14

bsxfun 在 Matlab 中代表的是二元单例扩展,而在 numpy 中叫做广播,这个过程通常是自动进行的。解决方案会根据你的 X 的维度而不同,也就是说,它是行向量还是列向量,但这个回答展示了一种实现方法:

如何将 numpy 的二维数组与一维数组相乘?

我认为这里的问题在于,广播要求其中一个维度必须是 1,而与 Matlab 不同的是,numpy 会区分一维的两个元素的向量和二维的两个元素的向量,也就是形状为 (2,) 的矩阵和形状为 (2,1) 的矩阵之间的区别,广播需要后者才能发生。

撰写回答