生成对数正态样本,适合于它所产生的数据。

问题描述 投票:2回答:1

我想在其他样本的基础上创建一个新的样本,但我的理解有问题。我有34个样本,我认为是相对对数分布的。基于这些样本,我想生成2000个新样本。这是我正在运行的代码。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

samples = [480, 900, 1140, 1260, 1260, 1440, 1800, 1860, 1980, 2220, 2640, 2700,
           2880, 3420, 3480, 3600, 3840, 4020, 4200, 4320, 4380, 4920, 5160,
           5280, 6900, 7680, 9000, 10320, 10500, 10800, 15000, 21600, 25200,
           39000]
plt.plot(samples, 1 - np.linspace(0, 1, len(samples)))
std, loc, scale = stats.lognorm.fit(samples)
new_samples = stats.lognorm(std, loc=loc, scale=scale).rvs(size=2000)

a = plt.hist(new_samples, bins=range(100, 40000, 200),
             weights=np.ones(len(new_samples)) / len(new_samples))
plt.show()

这里是图,你可以看到,1000以上的样本非常少 虽然样本中包含了相当多的1000以上的样本

plotPlot2

我怎样才能最好地生成一个能更好地代表预期值的样本呢?

python matplotlib scipy distribution
1个回答
3
投票

似乎有什么地方出了问题 stats.lognorm.fit.

文件 借用 stats.norm 的对数,然后用 exp(mu) 作为比例。这样似乎好用多了。

import numpy as np
from scipy import stats
import matplotlib.pyplot as plt

samples = [480, 900, 1140, 1260, 1260, 1440, 1800, 1860, 1980, 2220, 2640, 2700,
           2880, 3420, 3480, 3600, 3840, 4020, 4200, 4320, 4380, 4920, 5160,
           5280, 6900, 7680, 9000, 10320, 10500, 10800, 15000, 21600, 25200,
           39000]
samples = np.array(samples)

std, loc, scale = stats.lognorm.fit(samples) # 2.865850745357322, 479.99969879223596, 1.1400622824414484
weird_samples = stats.lognorm(std, loc=loc, scale=scale).rvs(size=2000)

mu, std = stats.norm.fit(np.log(samples)) # 8.304837454505837, 0.9720253999925554
scale = np.exp(mu) # 4043.3848507251523
loc = 0
new_samples = stats.lognorm(std, loc=loc, scale=scale).rvs(size=2000)

plt.plot(samples, 1 - np.linspace(0, 1, len(samples)), label='given samples')
plt.plot(np.sort(weird_samples), 1 - np.linspace(0, 1, len(weird_samples)), label='using stats.lognorm.fit(samples)')
plt.plot(np.sort(new_samples), 1 - np.linspace(0, 1, len(new_samples)), label='using stats.norm.fit(log(samples))')
plt.legend()
plt.show()

resulting plot

Seaborn的kdeplot显示如下。

import seaborn as sns

bw = 1500
sns.kdeplot(samples, bw=bw, label='given samples')
sns.kdeplot(weird_samples, bw=bw, label='using stats.lognorm.fit(samples)')
sns.kdeplot(new_samples, bw=bw, label='using stats.norm.fit(log(samples))')
plt.xlim(-5000, 45000)
plt.show()

kdeplots

PS:问题似乎是使用有限的样本来拟合3个参数的效果不是很好。你可以强制 lognorm.fit 使用 loc=0,它能找到更合理的参数。该 loc 参数只是用这个量来移动样本;通常情况是 loc=0 是更好的选择。

std, loc, scale = stats.lognorm.fit(samples, floc=0) # 0.9720253999925554, 0.0, 4043.3848507251523

与其强行 locfloc,你也可以提供一个初步的猜测。这看起来更好。

std, loc, scale = stats.lognorm.fit(samples, loc=0) # 1.0527481074345748, 203.08004314932137, 3712.4903893865644

fitting with initial guess

© www.soinside.com 2019 - 2024. All rights reserved.