单位和数量支持#

备注

这里介绍的功能是最近添加的。如果您遇到任何问题,请不要犹豫在 issue tracker .

这个 astropy.modeling 该软件包包括对模型参数、模型和拟合期间使用单位和数量的部分支持。在这个时候,只有一些内置的模型(如 Gaussian1D )支持单位,但这将在将来扩展到所有适当的型号。

将参数设置为数量#

模型可以 Quantity 对象作为参数:

>>> from astropy import units as u
>>> from astropy.modeling.models import Gaussian1D
>>> g1 = Gaussian1D(mean=3 * u.m, stddev=2 * u.cm, amplitude=3 * u.Jy)

然后访问该参数将返回一个包含值和单位的参数对象:

>>> g1.mean
Parameter('mean', value=3.0, unit=m)

然后可以访问参数的各个属性:

>>> g1.mean.name
'mean'
>>> g1.mean.value
3.0
>>> g1.mean.unit
Unit("m")

如果参数已初始化为数量,则应始终将其设置为数量,但单位不必与初始单位兼容:

>>> g1.mean = 3 * u.s
>>> g1  
<Gaussian1D(amplitude=3. Jy, mean=3. s, stddev=2. cm)>

要更改参数的值而不是单位,只需设置value属性:

>>> g1.mean.value = 2
>>> g1  
<Gaussian1D(amplitude=3. Jy, mean=2. s, stddev=2. cm)>

将最初设置为数量的参数设置为标量不起作用,因为用户是想只更改值并保留单位,还是删除单位,这是不明确的:

>>> g1.mean = 2  
Traceback (most recent call last):
...
UnitsError : The 'mean' parameter should be given as a Quantity because it
was originally initialized as a Quantity

另一方面,如果先前定义的没有单位的参数被赋予一个带有单位的数量,这是因为它是明确的:

>>> g2 = Gaussian1D(mean=3)
>>> g2.mean = 3 * u.m

换句话说,一旦单位被附加到一个参数上,它们就不能被删除,因为含义不明确。

用数量评估模型#

在评估期间可以将数量传递到模型:

>>> g3 = Gaussian1D(mean=3 * u.m, stddev=5 * u.cm)
>>> g3(2.9 * u.m)  
<Quantity 0.1353352832366122>
>>> g3(2.9 * u.s)  
Traceback (most recent call last):
...
UnitsError : Units of input 'x', s (time), could not be converted to
required input units of m (length)

在这种情况下,由于平均值和标准差都有单位,因此在评估过程中通过的值也需要单位:

>>> g3(3)  
Traceback (most recent call last):
...
UnitsError : Units of input 'x', (dimensionless), could not be converted to
required input units of m (length)

等价物#

等价性需要特别注意——例如,在频率空间定义的高斯函数不是波长空间中的高斯函数。出于这个原因,我们不允许将等价性附加到参数本身。相反,我们采取了将输入数据转换为参数空间的方法,并且在计算时应将任何等价性应用于数据(而不是参数)。

让我们考虑一个波长空间中的高斯模型:

>>> g4 = Gaussian1D(mean=3 * u.micron, stddev=1 * u.micron, amplitude=3 * u.Jy)

默认情况下,传递频率将不起作用:

>>> g4(1e2 * u.THz)  
Traceback (most recent call last):
...
UnitsError : Units of input 'x', THz (frequency), could not be converted to
required input units of micron (length)

但是,您可以将等效字典传递给equivalences参数(这需要是一个字典,因为有些模型可以包含多个输入):

>>> g4(110 * u.THz, equivalencies={'x': u.spectral()})  
<Quantity 2.888986819525229 Jy>

字典的键应该是输入的名称,根据:

>>> g4.inputs
('x',)

也可以使用input_units_equivalences属性为输入参数设置默认等效值:

>>> g4.input_units_equivalencies = {'x': u.spectral()}
>>> g4(110 * u.THz)  
<Quantity 2.888986819525229 Jy>

用单位拟合模型到数据#

如果模型支持使用单位拟合,那么将带单位的模型与带单位的数据拟合应该是无缝的。为了证明这一点,我们从生成合成数据开始:

import numpy as np
from astropy import units as u
import matplotlib.pyplot as plt

x = np.linspace(1, 5, 30) * u.micron
y = np.exp(-0.5 * (x - 2.5 * u.micron)**2 / (200 * u.nm)**2) * u.mJy
plt.plot(x, y, 'ko')
plt.xlabel('Wavelength (microns)')
plt.ylabel('Flux density (mJy)')

(png, svg, pdf)

../_images/units-1.png

然后,我们定义拟合的初始猜测值,然后按照不使用任何单位的方式进行拟合:

from astropy.modeling import models, fitting

g5 = models.Gaussian1D(mean=3 * u.micron, stddev=1 * u.micron, amplitude=1 * u.Jy)

fitter = fitting.LevMarLSQFitter()

g5_fit = fitter(g5, x, y)

plt.plot(x, y, 'ko')
plt.plot(x, g5_fit(x), 'r-')
plt.xlabel('Wavelength (microns)')
plt.ylabel('Flux density (mJy)')

(png, svg, pdf)

../_images/units-2.png

具有等效性#

现在让我们考虑这样一种情况:数据与参数不等价,但它们可以通过等价物进行转换。在这种情况下,等价性可以通过字典传递,如上面的求值示例所示:

g6 = models.Gaussian1D(mean=110 * u.THz, stddev=10 * u.THz, amplitude=1 * u.Jy)

g6_fit = fitter(g6, x, y, equivalencies={'x': u.spectral()})

plt.plot(x, g6_fit(x, equivalencies={'x': u.spectral()}), 'b-')
plt.xlabel('Wavelength (microns)')
plt.ylabel('Flux density (mJy)')

(png, svg, pdf)

../_images/units-3.png

在这种情况下,拟合(蓝色)稍差,因为频率空间(蓝色)中的高斯不是波长空间中的高斯(红色)。如前所述,您还可以在模型本身上设置input_units_等效性,以避免将额外的参数传递给装配工:

g6.input_units_equivalencies = {'x': u.spectral()}
g6_fit = fitter(g6, x, y)

支持其他无单位模型中的单元#

有些模型,如多项式,在本质上不适用于单位。取而代之的是 coerce_units() 方法提供了一种向无单位模型添加输入和返回单位的方法,方法是用 UnitsMapping . 在内部,输入在传递到模型之前从单元中剥离出来,如果 return_units 已指定。该方法返回一个新的复合模型:

>>> from astropy.modeling import models
>>> from astropy import units as u
>>> model = models.Polynomial1D(1, c0=1, c1=2)
>>> new_model = model.coerce_units(input_units={'x': u.Hz}, return_units={'y': u.s},
... input_units_equivalencies={'x':u.spectral()})
>>> new_model(10 * u.Hz)
<Quantity 21. s>