5

私はmatplotlibのhist関数を使って分布に統計モデルを当てはめています。例えば、私のコードは次のコードを使用して指数分布をフィット:scipy.optimize.curve_fitに渡された関数は、実行するためにどのような要件を満たす必要がありますか?

try: 

     def expDist(x, a, x0): 
      return a*(exp(-(x/x0))/x0) 

     self.n, self.bins, patches = plt.hist(self.getDataSet(), self.getDatasetSize()/10, normed=1, facecolor='blue', alpha = 0.55) 
     popt,pcov = curve_fit(expDist,self.bins[:-1], self.n, p0=[1,mean]) 
     print "Fitted gaussian curve to data with params a %f, x0 %f" % (popt[0], popt[1]) 
     self.a = popt[0] 
     self.x0 = popt[1] 

     self.fitted = True 
    except RuntimeError: 
     print "Unable to fit data to exponential curve" 

細かい動作しますが、私は、a & bの間で一様分布のために同じことを行うには、それを修正するとき

def uniDist(x, a, b): 
     if((x >= a)and(x <= b)): 
      return float(1.0/float(b-a)) 
     else: 
      return 0.000 

    try: 



     self.n, self.bins, patches = plt.hist(self.getDataSet(), self.getDatasetSize()/10, normed=1, facecolor='blue', alpha = 0.55) 
     popt,pcov = curve_fit(uniDist,self.bins[:-1], self.n, p0=[a, b]) 
     print "Fitted uniform distribution curve to data with params a %f, b %f" % (popt[0], popt[1]) 
     self.a = popt[0] 
     self.b = popt[1] 

     self.fitted = True 
    except RuntimeError: 
     print "Unable to fit data to uniform distribution pdf curve" 

コードがクラッシュし、

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

curve_fit、thのどこかにあるようですe関数は、(expDistとこの場合はuniDist)反復可能な値のセットでフィッティングする関数を呼び出そうとしていますが、expDist関数がどのようにしてクラッシュすることなく繰り返し実行できるのか分かりません。

+1

https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html – user2357112

答えて

2

あなたの疑惑は部分的に正しいです。 curve_fit実際にはiterableを関数に渡しますが、反復可能なものだけではありません:numpy.ndarray。 (正しい出力で)をこれらは、ベクトル化算術演算子を有することが起こるので、

a*(exp(-(x/x0))/x0) 

は単にエラーなし要素単位入力アレイにわたって動作します。関数の各評価では、パラメータax0はスカラーであり、xは配列にすぎません。

uniDistの問題は、算術演算子だけでなく、比較演算子も含んでいることです。これらの作業は細かい限り、単一のアレイは、スカラーと比較される。

>>> import numpy as np 
>>> a = np.arange(5) 
>>> a 
array([0, 1, 2, 3, 4]) 
>>> a>2 
array([False, False, False, True, True], dtype=bool) 

上記アレイとスカラーで比較演算子を使用して再度要素単位で結果を生成することを実証します。これらの論理配列の2つに論理演算子を適用しようとすると、表示されるエラーが発生します。

>>> a>2 
array([False, False, False, True, True], dtype=bool) 
>>> a<4 
array([ True, True, True, True, False], dtype=bool) 
>>> (a>2) and (a<4) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 

エラーメッセージは少し混乱します。これは、Pythonがarray1 and array2(ネイティブのPythonでは空に基づいていずれかの配列を返す)の単一の結果を出そうとしているという事実に戻ることができます。しかし、numpyはこれがあなたがしたいことではないと思って、推測する誘惑に抵抗します。

2つのブール値の配列(比較演算に由来)で関数を要素ごとに動作させたいので、&演算子を使用する必要があります。これはネイティブのPythonでは "binary and"ですが、配列がnumpyの場合、これは配列の要素的な "論理的"を与えます。あなたはまた、より明確であることをnumpy.logical_and(またはscipy.logical_and、あなたのケースで)を使用することもできます&場合のために、いつでも再びa>2&a<4があいまいになるので、(プログラマに)、あなたの比較を括弧していることを

>>> (a>2) & (a<4) 
array([False, False, False, True, False], dtype=bool) 
>>> np.logical_and(a>2,a<4) 
array([False, False, False, True, False], dtype=bool) 

は注意して間違っている(あなたがを望むことを考えると、が必要です)。ブール値の "バイナリ"は正確に動作するので、2つの比較を比較する場合はandの代わりに&を使用するように関数を書き換えることは安全です。

ただし、変更する必要があるステップはまだあります。ndarrayの入力の場合、ifの動作も異なります。 Pythonはifで単一の選択をすることはできませんが、配列を置く場合も同様です。しかし、あなたが実際にやりたいことは、出力の要素を要素の賢さ(再び)に制限することです。だからあなたはあなたの配列をループしなければならない(そうしない)か、この選択をベクトル化してやり直さなければならない。後者はnumpyの/ scipyのダウンロードを使用して慣用的である:

import scipy as sp 
def uniDist(x, a, b): 
    return sp.where((a<=x) & (x<=b), 1.0/(b-a), 0.0) 

この(すなわちnumpy.where)はxとして配列同じサイズを返します。条件がTrueの要素の場合、出力の値は1/(b-a)になります。残りの出力は0です。スカラーxの場合、戻り値はnumpyスカラーです。上記の例ではfloatの変換を取り除いたことに注意してください。分子に1.0を入れると、python 2を使用しているにもかかわらず、真の除算が確実に得られることに注意してください。私はpython 3や少なくともfrom __future__ import divisionを使用することをお勧めします。


マイナー注:でも、スカラの場合のために、私はこの目的のために自分自身を貸す比較のために連鎖するPythonの演算子を使用することを示唆しています。私が意味することは、あなたが単にif a <= x <= b: ...を行うことができ、ほとんどの言語とは異なり、これは機能的にあなたが書いたものと機能的に同等です(しかし、よりきれいです)。