【问题标题】:Generating lognormal samples that fitts the data it was generated from生成适合其生成数据的对数正态样本
【发布时间】:2020-10-05 16:57:15
【问题描述】:

我正在尝试基于其他一些示例创建一个新示例,但我做错了/理解错误。我有 34 个样本,我认为它们是相对 lognorm 分布的。基于这个样本,我想生成 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 的样本。

如何最好地生成更能代表预期值的样本?

【问题讨论】:

    标签: python matplotlib scipy distribution


    【解决方案1】:

    stats.lognorm.fit 似乎出了点问题。

    docs 通过拟合样本日志的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()
    

    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()
    

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

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

    除了用floc 强制loc,您还可以提供初始猜测。这看起来更好:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-17
      • 2019-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-28
      相关资源
      最近更新 更多