在涉及线性代数的功能上应用Numpy广播
我想在数学函数上使用numpy
广播功能,该功能涉及线性代数(没有分母部分的双变量高斯分布)。 我代码的最小,可再现的示例是:
我有以下功能
import numpy as np
def gaussian(x):
mu = np.array([[2],
[2]])
sigma = np.array([[10, 0],
[0, 10]])
xm = x - mu
result = np.exp((-1/2) * xm.T @ np.linalg.inv(sigma) @ xm)
return result
该函数假设x
是2x1数组。 我的目的是使用该函数生成一个2D数组,其中各个元素是该功能的产品。 我将此功能应用如下:
x, y = np.arange(5), np.arange(5)
xLen, yLen = len(x), len(y)
z = np.zeros((yLen, xLen))
for y_index in range(yLen):
for x_index in range(xLen):
element = np.array([[x[x_index]],
[y[y_index]]])
result = gaussian(element)
z[y_index][x_index] = result
这有效,但是如您所见,我使用两个用于索引。我知道这是不良的做法,当使用更大的阵列时,它非常慢。我想用numpy
广播功能解决此问题。我尝试了以下代码:
X, Y = np.meshgrid(x, y, indexing= 'xy')
element = np.array([[X],
[Y]])
Z = gaussian(element)
但是我遇到了此错误:valueerror:操作数无法与形状(2,1,5,5)(2,1,1)(2,1)(2,1)
for Line xm = x -mu
该功能的。我在一定程度上理解了这个错误。
此外,即使我解决了这个问题,我也会遇到另一个错误:value eRror:matmul:输入操作数1在其核心维度0中具有不匹配,带有gufunc签名(n?,k),(k,m?) - >(n?,m?)(尺寸5与2不同)
result = np.exp(( - 1/2) * xm.t @ np @ np.linalg.inv( sigma) @ xm) fuction的行。再次,我明白为什么。 XM
不再是2x1数组,并将其乘以Sigma
(即2x2)是行不通的。
有人对如何修改我的功能有建议,以便广播实现有效吗?
I would like to use numpy
broadcasting feature on mathematical function which involves linear algebra (bivariate gaussian distribution without the denominator part).
The Minimal, Reproducible Example of my code is this:
I have the following function
import numpy as np
def gaussian(x):
mu = np.array([[2],
[2]])
sigma = np.array([[10, 0],
[0, 10]])
xm = x - mu
result = np.exp((-1/2) * xm.T @ np.linalg.inv(sigma) @ xm)
return result
The function assumes that x
is a 2x1 array.
My aim is to use the function to generate a 2D array where the individual elements are products of the function.
I apply this function as follows:
x, y = np.arange(5), np.arange(5)
xLen, yLen = len(x), len(y)
z = np.zeros((yLen, xLen))
for y_index in range(yLen):
for x_index in range(xLen):
element = np.array([[x[x_index]],
[y[y_index]]])
result = gaussian(element)
z[y_index][x_index] = result
This works but as you can see, I use two for loops for indexing. I am aware that this is bad practise and when working with bigger arrays it is terribly slow. I would like to solve this with numpy
broadcasting feature. I attempted the following code:
X, Y = np.meshgrid(x, y, indexing= 'xy')
element = np.array([[X],
[Y]])
Z = gaussian(element)
But I am getting this error: ValueError: operands could not be broadcast together with shapes (2,1,5,5) (2,1)
for line xm = x - mu
of the function. I understand this error to a certain extent.
In addition, even if I solved this I would be getting another error: ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 5 is different from 2)
for the result = np.exp((-1/2) * xm.T @ np.linalg.inv(sigma) @ xm)
line of the fuction. Again, I understand why. xm
would no longer be 2x1 array and multiplying it with sigma
, which is 2x2, would not work.
Does anyone have a suggestion on how to modify my function so the broadcasting implementation works?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
以下可能有效。
要注意的两件事:
np.einsum
用于矢量 - 矩阵向量乘法。可能会有更快的方法,但这可以很好地处理要播放的其他维度。设置代码
新功能
,然后致电:
显然,请仔细检查。我做了一项简短的检查,这似乎是正确的,但是转录错误可能已交换了尺寸。
The following may work.
Two things to note:
np.einsum
for the vector-matrix-vector multiplication. There may be faster ways, but this can nicely handle the other dimensions that are to be broadcasted.Setup code
New function
And then call:
Obviously, please double check. I did one brief check, which seems to be correct, but transcription errors may e.g. have swapped dimensions.
因此,(2,1)输入返回a(1,1)结果:
添加一些领先维度:
x-mu
有效,因为(3,4,2,1)广播(2,1)该错误发生在
( - 1/2) * xm.t @ np.linalg.inv(sigma)
np.linalg.inv(sigma)
is(2,2) )xm
是(3,4,2,1)
,因此其转置为(1,2,4,3)。相反,如果数组为(3,4,1,2) @(2,2) @(3,4,2,1)结果应为(3,4,1,1)。
因此,让我们完善转言:
现在它适用于原始(2,1)和任何其他(N,M,2,1)形状:
So a (2,1) input returns a (1,1) result:
Adding some leading dimensions:
x-mu
works because (3,4,2,1) broadcasts with (2,1)The error occurs in
(-1/2) * xm.T @ np.linalg.inv(sigma)
np.linalg.inv(sigma)
is (2,2)xm
is(3,4,2,1)
, so its transpose is (1,2,4,3).If instead the arrays are (3,4,1,2) @ (2,2) @ (3,4,2,1) the result should be (3,4,1,1).
So let's refine the transpose:
Now it works for both the original (2,1), and any other (n,m,2,1) shape: