わかりました、あなたはいくつかのことについてかなり混乱しているようです。最初から始めましょう。「多次元関数」について言及しましたが、その後、通常の 1 変数ガウス曲線について説明します。これは多次元関数ではありません。積分すると、1 つの変数 (x) だけが積分されます。真の多次元関数である「多変量ガウス分布」と呼ばれるモンスターがあり、統合する場合、2つ以上の変数を統合する必要があるため、区別することが重要です(前述の高価なモンテカルロ法を使用します)。しかし、あなたは通常の1変数ガウスについて話しているだけのようです。これは、操作、統合などがはるかに簡単です。
1 変数のガウス分布には と の 2 つのパラメーターがsigma
ありmu
、 と で表す単一変数の関数ですx
。また、正規化パラメーターを持ち歩いているようn
です (これは、いくつかのアプリケーションで役立ちます)。正規化パラメーターは通常、計算に含まれません。これは、最後に追加するだけでよいためです (積分は線形演算子であることを思い出してください: int(n*f(x), x) = n*int(f(x), x)
)。ただし、必要に応じて持ち運びできます。正規分布について私が好む表記法は、次のとおりです。
N(x | mu, sigma, n) := (n/(sigma*sqrt(2*pi))) * exp((-(x-mu)^2)/(2*sigma^2))
x
(「与えられたsigma
, mu
,の正規分布はn
... で与えられる」と読みます) これまでのところ、とても良いです。これはあなたが持っている機能と一致します。ここでの唯一の真の変数x
は であることに注意してください: 他の 3 つのパラメーターは、特定のガウス分布に対して固定されています。
ここで、数学的な事実として、すべてのガウス曲線が同じ形状を持っていることは確かに真実であり、わずかにずれているだけです。したがってN(x|0,1,1)
、「標準正規分布」と呼ばれる を使用して、結果を一般的なガウス曲線に戻すことができます。したがって、 の積分があればN(x|0,1,1)
、任意のガウス分布の積分を自明に計算できます。この積分は非常に頻繁に現れるため、エラー関数 erf
という特別な名前が付けられています。いくつかの古い慣習のため、正確にはそうではありません erf
。いくつかの加法的および乗法的要因も持ち運ばれています。
もしPhi(z) = integral(N(x|0,1,1), -inf, z)
; つまり、Phi(z)
は負の無限大から までの標準正規分布の積分でありz
、誤差関数の定義により真です。
Phi(z) = 0.5 + 0.5 * erf(z / sqrt(2))
.
同様にPhi(z | mu, sigma, n) = integral( N(x|sigma, mu, n), -inf, z)
、つまり、は、パラメータ、、およびマイナス無限大から までPhi(z | mu, sigma, n)
の正規分布の積分です。誤差関数の定義により、次のようになります。mu
sigma
n
z
Phi(z | mu, sigma, n) = (n/2) * (1 + erf((x - mu) / (sigma * sqrt(2))))
.
この事実の詳細または証明が必要な場合は、通常の CDF に関するウィキペディアの記事を参照してください。
わかりました、それで十分な背景説明になるはずです。(編集済みの) 投稿に戻ります。「scipy.special の erf(z) では、最初に t が何であるかを正確に定義する必要があります」とあなたは言います。これが何を意味するのかわかりません。(時間?) はこれにどこt
から入るのですか?うまくいけば、上記の説明でエラー関数が少し分かりやすくなり、エラー関数がジョブに適した関数である理由がより明確になりました。
あなたの Python コードは問題ありませんが、ラムダよりもクロージャの方が好きです。
def make_gauss(N, sigma, mu):
k = N / (sigma * math.sqrt(2*math.pi))
s = -1.0 / (2 * sigma * sigma)
def f(x):
return k * math.exp(s * (x - mu)*(x - mu))
return f
クロージャーを使用すると、定数k
との事前計算が可能s
になるため、返される関数は呼び出されるたびに必要な作業が少なくなります (これは、関数を統合する場合に重要になる可能性があります。つまり、何度も呼び出されることになります)。また、指数演算子の使用を避けました**
、これは二乗を書くよりも遅く、内側のループから除算を巻き上げ、それを乗算に置き換えました。私は Python でのそれらの実装をまったく見ていませんが、生の x87 アセンブリを使用して純粋な速度のために内部ループを最後に調整したときから、加算、減算、または乗算にはそれぞれ約 4 CPU サイクルがかかり、除算には約36、累乗は約 200 です。これは数年前のことです。それでも、それはそれらの相対的な複雑さを示しています。同様にexp(x)
、力ずくで計算するのは非常に悪い考えです。の優れた実装を作成するときに、一般的なスタイルのべき乗exp(x)
よりも大幅に高速かつ正確にすることができるトリックがあります。a**b
定数 pi と e の numpy バージョンを使用したことはありません。私はいつも昔ながらの数学モジュールのバージョンに固執してきました。どちらかを好む理由がわかりません。
quad()
電話で何をしようとしているのかわかりません。quad(gen_gauss, -inf, inf, (10,2,0))
再正規化されたガウスをマイナスの無限大からプラスの無限大まで積分する必要があり、ガウスは実線上で 1 に積分されるため、常に 10 (正規化係数) を出力する必要があります。10 からかけ離れた答え (正確には10とは思わないでしょうquad()
) は、どこかで何かがおかしくなっていることを意味します...実際の戻り値と、おそらく の内部の仕組みを知らずに、何がおかしくなったかを言うのは難しいですquad()
。
うまくいけば、混乱の一部が解明され、エラー関数が問題に対する正しい答えである理由と、興味があればそれをすべて自分で行う方法が説明されました. 私の説明が明確でない場合は、まずウィキペディアをざっと見てみることをお勧めします。まだ質問がある場合は、遠慮なく質問してください。