web-dev-qa-db-ja.com

scipy、対数正規分布-パラメータ

python scipy.stats.lognormal.fitを使用して、データに対数正規分布を適合させたいと思っています。 manual によれば、fitshape、loc、scaleパラメータですが、通常、対数正規分布は 2つのパラメータ :平均と標準偏差のみを必要とします。

Scipy fit関数の結果を解釈するにはどうすればよいですか?どうすれば平均とstd.devを取得できますか?

29
Jakub M.

Scipyの分布は、2つのパラメーターの場所とスケールに対して一般的な方法でコード化されているため、場所はパラメーター(loc)であり、分布は左または右にシフトしますが、scaleはパラメーターです分布を圧縮または伸ばします。

2つのパラメーターの対数正規分布の場合、「平均」と「標準偏差」は、log(scale)とshapeに対応します(loc=0)。

以下は、関心のある2つのパラメーターを見つけるために対数正規分布を近似する方法を示しています。

In [56]: import numpy as np

In [57]: from scipy import stats

In [58]: logsample = stats.norm.rvs(loc=10, scale=3, size=1000) # logsample ~ N(mu=10, sigma=3)

In [59]: sample = np.exp(logsample) # sample ~ lognormal(10, 3)

In [60]: shape, loc, scale = stats.lognorm.fit(sample, floc=0) # hold location to 0 while fitting

In [61]: shape, loc, scale
Out[61]: (2.9212650122639419, 0, 21318.029350592606)

In [62]: np.log(scale), shape  # mu, sigma
Out[62]: (9.9673084420467362, 2.9212650122639419)
31
ars

私はこれを解決するために少し時間を費やして、それをここに文書化したいと思います:lognorm.fitの3つの戻り値から(点xで)確率密度を取得したい場合(それらを(shape, loc, scale))、次の式を使用する必要があります:

x = 1 / (shape*((x-loc)/scale)*sqrt(2*pi)) * exp(-1/2*(log((x-loc)/scale)/shape)**2) / scale

したがって、(locµshapeσscaleα)という式になります。

x = \frac{1}{(x-\mu)\cdot\sqrt{2\pi\sigma^2}} \cdot e^{-\frac{log(\frac{x-\mu}{\alpha})^2}{2\sigma^2}}

9
Chronial

これは役立つと思います。 私は長い間同じ問題を探していましたが、最終的に私の問題の解決策を見つけました。私の場合、_scipy.stats.lognorm_モジュールを使用して、いくつかのデータを対数正規分布に適合させようとしていましたしかし、最終的にモデルパラメーターを取得したとき、yデータの平均と標準を使用して結果を複製する方法が見つかりませんでした。

以下のコードでは、scipy.stats.normモジュールを使用して、正規分布のデータサンプルを作成する方法を平均および標準パラメーターから説明します。これらのデータを使用して、正規モデル(_norm_dist_fitted_)を近似し、データから抽出した平均と標準偏差(_mu, sigma_)を使用して正規モデルを作成します。

データを生成する元のモデル、フィットされ、(mu-sigma)で生成されたペアがグラフで比較されます。

図1


コードの次のセクションでは、通常のデータを使用して対数正規分布サンプルを生成します。これを行うには、対数正規サンプルが元のサンプルの指数関数になることに注意してください。したがって、指数サンプルの平均と標準偏差は(exp(mu)exp(sigma))になります。

作成したデータをlognormalに適合させました(サンプルのログ(exp(x))は正規分布しているため、対数正規モデルの仮定に従います。

元のデータ(x)の平均と標準偏差から対数正規モデルを作成するには、コードは次のようになります。

_lognorm_dist = scipy.stats.lognorm(s=sigma, loc=0, scale=np.exp(mu))
_

ただし、データがすでに指数空間(exp(x))にある場合は、以下を使用する必要があります。

_muX = np.mean(np.log(x))
sigmaX = np.std(np.log(x))
scipy.stats.lognorm(s=sigmaX, loc=0, scale=muX)
_

図2

_import scipy
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

mu = 10 # Mean of sample !!! Make sure your data is positive for the lognormal example 
sigma = 1.5 # Standard deviation of sample
N = 2000 # Number of samples

norm_dist = scipy.stats.norm(loc=mu, scale=sigma) # Create Random Process
x = norm_dist.rvs(size=N) # Generate samples

# Fit normal
fitting_params = scipy.stats.norm.fit(x)
norm_dist_fitted = scipy.stats.norm(*fitting_params)
t = np.linspace(np.min(x), np.max(x), 100)

# Plot normals
f, ax = plt.subplots(1, sharex='col', figsize=(10, 5))
sns.distplot(x, ax=ax, norm_hist=True, kde=False, label='Data X~N(mu={0:.1f}, sigma={1:.1f})'.format(mu, sigma))
ax.plot(t, norm_dist_fitted.pdf(t), lw=2, color='r',
        label='Fitted Model X~N(mu={0:.1f}, sigma={1:.1f})'.format(norm_dist_fitted.mean(), norm_dist_fitted.std()))
ax.plot(t, norm_dist.pdf(t), lw=2, color='g', ls=':',
        label='Original Model X~N(mu={0:.1f}, sigma={1:.1f})'.format(norm_dist.mean(), norm_dist.std()))
ax.legend(loc='lower right')
plt.show()


# The lognormal model fits to a variable whose log is normal
# We create our variable whose log is normal 'exponenciating' the previous variable

x_exp = np.exp(x)
mu_exp = np.exp(mu)
sigma_exp = np.exp(sigma)

fitting_params_lognormal = scipy.stats.lognorm.fit(x_exp, floc=0, scale=mu_exp)
lognorm_dist_fitted = scipy.stats.lognorm(*fitting_params_lognormal)
t = np.linspace(np.min(x_exp), np.max(x_exp), 100)

# Here is the magic I was looking for a long long time
lognorm_dist = scipy.stats.lognorm(s=sigma, loc=0, scale=np.exp(mu))

# The trick is to understand these two things:
# 1. If the EXP of a variable is NORMAL with MU and STD -> EXP(X) ~ scipy.stats.lognorm(s=sigma, loc=0, scale=np.exp(mu))
# 2. If your variable (x) HAS THE FORM of a LOGNORMAL, the model will be scipy.stats.lognorm(s=sigmaX, loc=0, scale=muX)
# with:
#    - muX = np.mean(np.log(x))
#    - sigmaX = np.std(np.log(x))


# Plot lognormals
f, ax = plt.subplots(1, sharex='col', figsize=(10, 5))
sns.distplot(x_exp, ax=ax, norm_hist=True, kde=False,
             label='Data exp(X)~N(mu={0:.1f}, sigma={1:.1f})\n X~LogNorm(mu={0:.1f}, sigma={1:.1f})'.format(mu, sigma))
ax.plot(t, lognorm_dist_fitted.pdf(t), lw=2, color='r',
        label='Fitted Model X~LogNorm(mu={0:.1f}, sigma={1:.1f})'.format(lognorm_dist_fitted.mean(), lognorm_dist_fitted.std()))
ax.plot(t, lognorm_dist.pdf(t), lw=2, color='g', ls=':',
        label='Original Model X~LogNorm(mu={0:.1f}, sigma={1:.1f})'.format(lognorm_dist.mean(), lognorm_dist.std()))
ax.legend(loc='lower right')
plt.show()
_
0
nenetto

まず、locは分布の単純な線形シフトではありません。実際、「loc」には独自の統計上の意味があります。つまり、サンプルが「loc」を減算すると、「標準化された」対数正規値が得られます。非常に重要です。

したがって、「loc」または「floc」を指定した場合、実際には非常に強い催眠術を課し、これらのサンプルには下限があり、下限は「loc」の値であると想定しています。したがって、scipyは異なるアルゴリズムを使用してフィッティングを行いました。つまり、位置情報を提供した場合、scipyは最尤法を使用してフィッティングパラメーターを計算します。そうでない場合は、数値ソルバーを使用します。

また、あなたはコードを読むことができます:scipyパッケージのstats/_continuous_distns.py行:3889。

    def fit(self, data, *args, **kwds):
        floc = kwds.get('floc', None)
        if floc is None:
            # loc is not fixed.  Use the default fit method.
            return super(lognorm_gen, self).fit(data, *args, **kwds)

        f0 = (kwds.get('f0', None) or kwds.get('fs', None) or
              kwds.get('fix_s', None))
        fscale = kwds.get('fscale', None)

        if len(args) > 1:
            raise TypeError("Too many input arguments.")
        for name in ['f0', 'fs', 'fix_s', 'floc', 'fscale', 'loc', 'scale',
                     'optimizer']:
            kwds.pop(name, None)
        if kwds:
            raise TypeError("Unknown arguments: %s." % kwds)

        # Special case: loc is fixed.  Use the maximum likelihood formulas
        # instead of the numerical solver.

さらに、Rコミュニティの誰かが、なぜpython=からの出力がRと異なるのか疑問に思うかもしれません。実際、Rを「参照」として使用することに同意しません。それは単なるソフトウェアであり、異なるソフトウェアにはさまざまなアルゴリズムの種類があります。

たとえば、次のようなRからの出力はエラーではなく、PythonまたはFortranのような他のソフトウェアは完全に異なるアルゴリズムを使用しました:

round(3.5)
[1] 4
round(2.5)
[1] 2
0
Chao Sun