请考虑以下示例:
from numpy import array, exp, linspace, meshgrid
import matplotlib.pyplot as plt
x = array([1, 2, 3, 4, 5, 6])
y = array([10, 5.49, 0.89, -0.14, -1.07, 0.84])
a1, a2 = 1, 4
def model(x, a1, a2):
return a1 * exp(-a2 * x)
def residuen(x, y, a1, a2):
return modell(x, a1, a2) - y
def S(x, y, a1, a2):
return 0.5 * sum(residuen(x, y, a1, a2) ** 2)
输入值x
和y
是固定的。我想为S
,a1
的不同值计算函数a2
的值,并将结果显示为3D表面图。在matplotlib tutorial中,我找到了一个使用meshgrid
功能的示例。我尝试针对此问题应用此功能:
a1 = linspace(-100, 100, 1000)
a2 = linspace(-100, 100, 1000)
A1, A2 = meshgrid(a1, a2)
Z = S(x, y, A1, A2)
当我运行此代码时,出现错误
ValueError: operands could not be broadcast together with shapes (1000,1000) (6,)
很明显,上面的代码为什么不起作用,但是我不知道如何修复/重新定义函数S
,因此我可以应用meshgrid
函数来获得表面图的所需值Z。有人知道如何解决此问题吗?
正如您的错误所指示,您的问题确实与matplotlib无关。您正在尝试计算模型与每个1e6位置的6个数据点之间的残差。由于残差是一个和,因此可以想象在某个点处有一个1000x1000x6的数组,并将其与最后一个维度相加。您也可以制作一个6x1000x1000数组,并在第一个维度上求和,但我将显示前一种情况。
您要使用的技术称为broadcasting。这意味着将形状从最后的尺寸开始对齐,并填写单位尺寸以进行匹配。进行广播的最简单的更改是在model
中:
a1[..., None] * exp(-a2[..., None] * x)
...
中的省略号([..., None]
)表示“采用所有现有尺寸”。在这种情况下,它是执行[:, :]
的简写,但是对于特定数组而言,则需要多次。 None
等效于np.newaxis
,表示“添加单位尺寸”。总的来说,索引表达式是将尺寸附加到形状的惯用方式。另一种方法是执行类似np.newaxis
的操作。
现在您可以执行以下操作:
将形状a1.reshape(a1.shape + (1,))
乘以形状(1000, 1000, 1)
(a2
)->将形状乘以(6,)
->结果形状:x
。 (1000, 1000, 6)
的最后一个维度是broadcasted。给a2
两个隐含的尺寸为x
的前导尺寸,这些尺寸也broadcasted。
这是您发生错误的地方。您不能以有意义的方式逐个元素地将形状为1
和(1000, 1000)
的数组相乘,但是可以使用新的单位维度。
(6,)
的指数保留形状。(1000, 1000, 6)
(展开的(1000, 1000, 1)
)。最后一个维度是broadcasted。现在a1
中的残差非常好:residuen
查找modell(x, a1, a2) - y
数组和(1000, 1000, 6)
数组之间的差。最终尺寸完美对齐,其余部分由广播负责。
唯一的区别是,由于数组不再平坦,您必须告诉(6,)
要在哪个轴上进行操作:
sum
尽管这不是正确的RMS计算。我本来希望看到
sum
查找数组均方根的更简单方法是使用0.5 * sum(residuen(x, y, a1, a2)**2, axis=1)
:
sum(residuen(x, y, a1, a2)**2, axis=-1)**0.5
TL; DR
您的节目需要使用广播:
np.linalg.norm