将bsxfun的@times转换为numpy
这是我在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 个回答
虽然有点晚了,但我想给大家举个例子,说明在Python中如何实现和bsxfun
、repmat
相同的功能。这段代码是我刚把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]])
对于那些不太了解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的形状。
bsxfun
在 Matlab 中代表的是二元单例扩展,而在 numpy 中叫做广播,这个过程通常是自动进行的。解决方案会根据你的 X
的维度而不同,也就是说,它是行向量还是列向量,但这个回答展示了一种实现方法:
我认为这里的问题在于,广播要求其中一个维度必须是 1
,而与 Matlab 不同的是,numpy 会区分一维的两个元素的向量和二维的两个元素的向量,也就是形状为 (2,)
的矩阵和形状为 (2,1)
的矩阵之间的区别,广播需要后者才能发生。