scipyなどの曲線適合ツールは、モデル関数のパラメータが実数であると想定する傾向があります。 複素数値のパラメータに依存するモデルを複素数値のデータセットにフィッティングする場合、最初にモデルのバージョンを作成しなければなりません。各モデルでは、各複素パラメータが2つの実数パラメータに置き換えられます。汎用関数オブジェクトの複素数値引数を2つの実数値引数で置き換える
まず、簡単な例:
# original function, representing a model where a,b may be complex-valued
def f(x, a, b):
return a+b*x
# modified function, complex parameters have been replaced by two real ones
def f_r(x, a_r, a_i, b_r, b_i):
return f(x, a_r + 1J*a_i, b_r+1J*b_i)
print(f(1,2+3J,4+5J) == f_r(1,2,3,4,5))
注:モデルの出力は、依然として複素数値であるが、これは容易に適切残留関数を定義しての世話をすることができます。
さて、代わりにすべての機能f
のための新しいコードを記述するので、私はf
の引数がにあるブール値のリストis_complex
指定と一緒に関数オブジェクトf
を渡す「機能の工場」を持っていると思います(したがって、2つの実数引数で置き換える必要があります)。 このブール値のリストは、例えば次のようにすることができる。 f
と共に提供される初期値から推定される。
私はこの種の問題に慣れていないので、ウェブ上を見て、decorator moduleを見つけました。一般的なケースに行く前に、ここでFunctionmaker
クラスを使用して、上からの例です:
import decorator
def f(x, a, b):
return a+b*x
f_r = decorator.FunctionMaker.create(
'f_r(x, a_r, a_i, b_r, b_i)',
'return f(x, a_r + 1J*a_i, b_r + 1J*b_i)',
dict(f=f))
、一つは今の機能メーカに渡される2つの文字列を合成するために想像することができます
import decorator
import inspect
def f(x, a, b):
return a+b*x
def fmaker(f,is_complex):
argspec = inspect.getargspec(f)
args = argspec.args[:]
fname = f.func_name
s1 = "{}_r(".format(fname)
s2 = "return f("
for arg, cplx in zip(args, is_complex):
if not cplx:
s1 += "{},".format(arg)
s2 += "{},".format(arg)
else:
s1 += "{}_r,".format(arg)
s1 += "{}_i,".format(arg)
s2 += "{}_r+1J*{}_i,".format(arg,arg)
s1 += ')'
s2 += ')'
return decorator.FunctionMaker.create(s1,s2,dict(f=f))
is_complex = [False, True, True]
f_r = fmaker(f,is_complex)
# prints ArgSpec(args=['x', 'a_r', 'a_i', 'b_r', 'b_i'], varargs=None, keywords=None, defaults=())
print(inspect.getargspec(f_r))
print(f(1,2+3J,4+5J) == f_r(1,2,3,4,5))
これは問題を解決すると思われます。
私の質問です:これはこれを行う妥当な方法ですか?より良い/より簡単な方法は、Pythonでですか?
P.S.私はコンピュータ科学者ではないので、技術用語を誤って使用している場合は、自由に改訂してください。
ありがとうございます。このソリューションは本当にはるかに簡単です(後で表示されます)。あなたの関数 'f_u2'の評価のスピードについてコメントできますか(確かに、私の質問の一部ではありませんでした)?ここで私が見ることのできる唯一の不利な点は、関数f_u2が呼び出されるたびに新しい引数リストを構築するオーバーヘッドです(そして、最適化問題を解決するときに頻繁に呼び出されるかもしれません)。 –
オーバーヘッドは、私とあなたの両方のソリューションの場合、ほぼ同じです。ジャンプするには、関数を呼び出す関数があります。 f_u2対f_uの場合、オーバヘッドはメモリ割り当てのみから来るので、非常に小さくする必要があります。これはf変数自体の内部での合理的な操作(ローカル変数の定義など)よりも小さくなければなりません。つまり、効率を求めているなら、Pythonではなく評価の中で単一のループのためにcythonを使うような、より大きな "咬合"を取ることができます。しかし、多くのパラメータがある場合、私の解決策は遅くなるかもしれません。 – lejlot