新しいモデルクラスを定義する

本稿では、モデルをパッケージに追加したり、カスタムモデルを作成したりする方法を紹介します。簡単に言うと,すべてのモデルパラメータを定義し,モデルを評価する関数,すなわちモデルを実現する数学関数を計算する必要がある.モデルが適合可能である場合,線形適合アルゴリズムを用いるためには,パラメータに関する微分係数の関数を計算する必要があり,非線形フィッティングを用いる場合にはオプションの関数が必要となる。

基本カスタマイズモデル

ほとんどの場合 custom_model 装飾者は新しいものを作るための簡単な方法を提供します Model 既存のPythonからオブジェクトの初期化を呼び出すことができます。以下の例では、2つのガウスモデルからなるモデルを設定する方法を示す。

import numpy as np
import matplotlib.pyplot as plt
from astropy.modeling.models import custom_model
from astropy.modeling.fitting import LevMarLSQFitter

# Define model
@custom_model
def sum_of_gaussians(x, amplitude1=1., mean1=-1., sigma1=1.,
                        amplitude2=1., mean2=1., sigma2=1.):
    return (amplitude1 * np.exp(-0.5 * ((x - mean1) / sigma1)**2) +
            amplitude2 * np.exp(-0.5 * ((x - mean2) / sigma2)**2))

# Generate fake data
np.random.seed(0)
x = np.linspace(-5., 5., 200)
m_ref = sum_of_gaussians(amplitude1=2., mean1=-0.5, sigma1=0.4,
                         amplitude2=0.5, mean2=2., sigma2=1.0)
y = m_ref(x) + np.random.normal(0., 0.1, x.shape)

# Fit model to data
m_init = sum_of_gaussians()
fit = LevMarLSQFitter()
m = fit(m_init, x, y)

# Plot the data and the best fit
plt.plot(x, y, 'o', color='k')
plt.plot(x, m(x))

(png, svg, pdf)

../_images/new-model-1.png

この修飾器はモデルを設定することもサポートしています fit_deriv 複数の入力を持つモデルを作成する.通常の出荷機能としても使用することができます(例えば SumOfGaussians = custom_model(sum_of_gaussians) )ではなく、装飾師としてである。ご参照ください custom_model より多くの例の文書については、参照されたい。

一次元ガウスモデルの逐次定義

中に記載された例 Basic custom models 多くの簡単な場合に利用可能であるが,次節ではモデルクラスをどのように構築するかを述べる.完全なモデルクラスを定義することは、例えば、より専用のパラメータを提供するために、または実質的にサポートされていない特別な機能を実現するために必要である可能性がある custom_model 工場機能。

以下,一次元ガウスモデルを例に詳細に説明する.モデルには2つの基底類がある.もしモデルが適切であれば、それは継承すべきです FittableModel そうでなければサブクラスであるべきである Model それがそうです。

モデルがパラメータを用いる場合は,モデルのクラス定義に用いるべきである. Parameter 記述子。Parameter構造関数のすべてのパラメータは任意であり、パラメータのデフォルト値、パラメータのテキスト説明(適用可能)を含むことができる。 help 文書生成),およびパラメータ値のデフォルト制約とカスタムgetter/setter.また、カスタムコードがモデル定義に従ってパラメータ値が有効であるかどうか(例えば、非負の値でなければならないかどうか)を検査することができるように、各パラメータについて1つの“ベリファイア”方法を定義することができる。中の例を参照されたい Parameter.validator もっと細かいことを知っています。

from astropy.modeling import Fittable1DModel, Parameter

class Gaussian1D(Fittable1DModel):
    n_inputs = 1
    n_outputs = 1

    amplitude = Parameter()
    mean = Parameter()
    stddev = Parameter()

♪the n_inputs そして n_outputs クラス属性は整数でなければならず,モデルを評価するために入力される引数の数とその返す出力数を示す.入力と出力のラベルは inputs そして outputs ,自動生成される.デフォルト値は、クラスに必要な値を割り当てることでカバーすることができます __init__ メソッド、呼び出しています super それがそうです。 outputs そして inputs 長さの文字列のタプルでなければなりません n_outputs そして n_inputs それぞれです。出力は、入力と同じラベルを有する場合がある(例えば、 inputs = ('x', 'y') そして outputs = ('x', 'y') )である。しかしながら、入力は互いに衝突することはできない(例えば、 inputs = ('x', 'x') 正しくない),出力についても同様である.

There are two helpful base classes in the modeling package that can be used to avoid specifying n_inputs and n_outputs for most common models. These are Fittable1DModel and Fittable2DModel. For example, the actual Gaussian1D model is a subclass of Fittable1DModel. This helps cut down on boilerplate by not having to specify n_inputs, n_outputs, inputs and outputs for many models (follow the link to Gaussian1D to see its source code, for example).

回帰的には、適合可能なモデルは線形であってもよいし、非線形であってもよい。属性のデフォルト値 linear 属性は False それがそうです。線形モデルは定義すべきです linear 類属性は True それがそうです。このモデルは非線形であるため,デフォルト値を用いることができる.

自己を継承する. Fittable1DModel Vbl.ある Model._separable 属性は設定されています True それがそうです。他のすべてのモデルはこの属性を定義して指示すべきである モデル分離性 それがそうです。

次に名前を提供します evaluate このモデルを評価し fit_deriv パラメータに対する微分係数を計算する.これらは正常な方法かもしれません classmethod あるいは、あるいは staticmethod 約束したにもかかわらず staticmethod 関数がオブジェクトの他の属性に依存しない場合(すなわち、参照しない self )やクラスの他の属性、例えば classmethod それがそうです。求め方は,すべての入力座標を単独のパラメータとし,すべてのモデルパラメータのリスト順序が同じである. param_names それがそうです。

この例の場合:

@staticmethod
def evaluate(x, amplitude, mean, stddev):
    return amplitude * np.exp((-(1 / (2. * stddev**2)) * (x - mean)**2))

明確にすべきは evaluate 手法は,モデルのパラメータ値をパラメータとするように設計しなければならない.これは、パラメータ値がモデルの属性を通過しているように見える(例えば、 model.amplitude )である。ただし,パラメータ値を直接渡す. evaluate 多くの場合、それを使用するより効果的な方法、例えばアクセサリである。

あなたのモデルのユーザーは通常使用しません evaluate 直接行きましょう。代わりに、彼らはモデルの一例を作成し、いくつかの入力でそれをアップグレードする。♪the __call__ モデル使用方法 evaluate 内部では,ユーザはこれを意識する必要はない.デフォルト設定 __call__ モデルの評価を試みる前に、実装は、入力されたフォーマットが正しいかどうか、Numpyのブロードキャストルールに従うかどうかをチェックするなど、いくつかの詳細を扱う。

evaluate vt.的 fit_deriv 方法すべての座標とすべてのパラメータ値をパラメータとして入力とする.非線形モデルを計算する数値微分係数を選択することができる場合 fit_deriv 方法はすべきである. None **

@staticmethod
def fit_deriv(x, amplitude, mean, stddev):
    d_amplitude = np.exp(- 0.5 / stddev**2 * (x - mean)**2)
    d_mean = (amplitude *
              np.exp(- 0.5 / stddev**2 * (x - mean)**2) *
              (x - mean) / stddev**2)
    d_stddev = (2 * amplitude *
                np.exp(- 0.5 / stddev**2 * (x - mean)**2) *
                (x - mean)**2 / stddev**3)
    return [d_amplitude, d_mean, d_stddev]

私たちは確かにやったことに注意してください not 定義しなければなりません __init__ 方法や1つ __call__ 手法は我々のモデルに用いた.ほとんどのモデルでは __init__ 同じパターンに従い,パラメータ値を位置パラメータとし,いくつかの選択可能なキーワードパラメータ(制約など)を後にする.モデリングフレームワーク自動生成 __init__ 正しい呼び出しを持つ署名を持つクラス(呼び出しにより) help(Gaussian1D.__init__) 先ほど定義したモデル例では).

場合によってはカスタムを定義する必要があるかもしれません __init__ それがそうです。例えば Gaussian2D model takes an optional cov_matrix argument which can be used as an alternative way to specify the x/y_stddev and theta parameters. This is perfectly valid so long as the _ _init__゚`実際のパラメータのために適切な値を決定し、スーパーを呼び出します。 ``__init__ 標準的な論拠を用いる。概略的には、以下のように見える。

def __init__(self, amplitude, x_mean, y_mean, x_stddev=None,
             y_stddev=None, theta=None, cov_matrix=None, **kwargs):
    # The **kwargs here should be understood as other keyword arguments
    # accepted by the basic Model.__init__ (such as constraints)
    if cov_matrix is not None:
        # Set x/y_stddev and theta from the covariance matrix
        x_stddev = ...
        y_stddev = ...
        theta = ...

    # Don't pass on cov_matrix since it doesn't mean anything to the base
    # class
    super().__init__(amplitude, x_mean, y_mean, x_stddev, y_stddev, theta,
                     **kwargs)

完全な例

import numpy as np
from astropy.modeling import Fittable1DModel, Parameter

class Gaussian1D(Fittable1DModel):
    amplitude = Parameter()
    mean = Parameter()
    stddev = Parameter()

    @staticmethod
    def evaluate(x, amplitude, mean, stddev):
        return amplitude * np.exp((-(1 / (2. * stddev**2)) * (x - mean)**2))

    @staticmethod
    def fit_deriv(x, amplitude, mean, stddev):
        d_amplitude = np.exp((-(1 / (stddev**2)) * (x - mean)**2))
        d_mean = (2 * amplitude *
                  np.exp((-(1 / (stddev**2)) * (x - mean)**2)) *
                  (x - mean) / (stddev**2))
        d_stddev = (2 * amplitude *
                    np.exp((-(1 / (stddev**2)) * (x - mean)**2)) *
                    ((x - mean)**2) / (stddev**3))
        return [d_amplitude, d_mean, d_stddev]

線形モデルの完全な例

この例は、モデルクラスの別のオプション機能、すなわち 逆に. それがそうです。一個 inverse 実現は…。 property これは、逆を有するいくつかのモデルインスタンスについて、そのモデルの逆を計算する新しいモデルインスタンス(必ずしも逆されているモデルと同じクラスを有する必要はない)に戻る。 model.inverse(model(*input)) == input それがそうです。

import numpy as np
from astropy.modeling import Fittable1DModel, Parameter

class LineModel(Fittable1DModel):
    slope = Parameter()
    intercept = Parameter()
    linear = True

    @staticmethod
    def evaluate(x, slope, intercept):
        return slope * x + intercept

    @staticmethod
    def fit_deriv(x, slope, intercept):
        d_slope = x
        d_intercept = np.ones_like(x)
        return [d_slope, d_intercept]

    @property
    def inverse(self):
        new_slope = self.slope ** -1
        new_intercept = -self.intercept / self.slope
        return LineModel(slope=new_slope, intercept=new_intercept)

注釈

上の例は内蔵のものとほぼ同じです Linear1D モデルです。