0

確率分布を表すために、このような (簡略化された) クラスを作成しています。私が望むのは、オブジェクト Distribution をそのタイプとパラメーターのみで初期化し、そのタイプに応じて割り当てられたいくつかの機能を持たせることです。

functions = {'exp':{
                 'parameters': ['l'],
                 'pdf': lambda x,p: exp(x/p[0])*p[0],
                 'cdf': lambda x,p: 1-exp(x/p[0]) },
             'uniform':{
                 'parameters': ['x1','x2'],
                 'pdf': lambda x,p: 1/(p[1]-p[0]),
                 'cdf': lambda x,p: (x-p[0])/(p[1]-p[0]) }
            }
class Distribution:
    def __init__(self,dist_type,**parameters):
        self.dist_type = dist_type
        self.parameters = parameters
        self.p = [ self.parameters[z] for z in functions[dist_type]['parameters'] ]

        for key,val in functions[dist_type].items():
            if key == 'parameters':
                pass
            else
                setattr(self, key, lambda x:val(x,self.p))


dist = Distribution('exp',l=3.5)

今、 type(dist.pdf) を実行すると、ラムダ関数であることがわかりますが、関数を実行すると、 dist.pdf(4.0) TypeError: 'list' object is not a callable.

余談ですが、コードのスタイル/複雑さはどうですか?

4

3 に答える 3

1

Python のスコーピングの問題に悩まされています。この行で:

setattr(self, key, lambda x:val(x,self.p))

valは、が定義されたときに参照するオブジェクトではなく、lambdaが最終的に呼び出されるときに参照される単なる名前です。1 つの回避策は、定義時にバインドされるlambdaデフォルト値を持つ 2 番目の引数を追加することです。

for key,val in functions[dist_type].items():
    if key == 'parameters':
        pass
    else:
        setattr(self, key, lambda x,val=val: val(x,self.p))

あなたが試みているように、サブクラス定義を辞書に埋め込もうとするかどうかはわかりません。次のような適切なクラスを生成できるいくつかの手法 (クラス ファクトリ、メタクラス) が利用可能です。

exp_dist = make_distribution('exp')
d = exp_dist(l=3.5)
d.pdf(4.0)

functionsこのようなソリューションの複雑さは、ユース ケースと、現在の方法でディクショナリを構築することを選択した理由によって異なります。たとえば、名前付きパラメーターはpdfandcdf関数には必要ありませんが、イントロスペクションには役立つ場合があります。pdfまた、作成されたディストリビューションには と の 2 つのメソッドがあると仮定できますcdfか? またはインスタンスに追加のメソッドもある可能性はありますか?

于 2013-11-14T16:43:50.673 に答える