Apache独立Gamma分布

3

你好,我注意到Apache Maths库(版本2.2)中的一些奇怪行为,特别是在org.apache.commons.math.distribution.GammaDistributionImpl类中,尽管我认为这可能也适用于其他分布。

我想按照以下方式从不同的伽玛分布中取样:

public static final double[] gammaSamples(final double[] shapeParameters)
{
    double[] samples = new double[shapeParameters.length];
    for (int i = 0; i < shapeParameters.length; i++)
    {
        GammaDistributionImpl gd = new GammaDistributionImpl(shapeParameters[i], 1.0d);
        try
        {
            samples[i] = gd.sample();
        }
        catch (MathException e)
        {
            e.printStackTrace();
        }
    }
    return samples;
}

然而当我运行代码时,我发现样本都异常相似,即给定:
public static void main(String[] args)
{
    System.out.println(Arrays.toString(gammaSamples(new double[] { 2.0d, 2.0d, 2.0d})));
}

一些示例输出如下:
[0.8732612631078758, 0.860967116242789, 0.8676088095186796]
[0.6099133517568643, 0.5960661621756747, 0.5960661621756747]
[2.1266766239021364, 2.209383544840242, 2.209383544840242]
[0.4292184700011395, 0.42083613304362544, 0.42083613304362544]

我认为问题是默认的随机数生成器对于每个分布使用相同/相似的种子,我进行了如下测试:

public static final double[] gammaSamples(final double[] shapeParameters, final Random random)
{
    double[] samples = new double[shapeParameters.length];
    for (int i = 0; i < shapeParameters.length; i++)
    {
        GammaDistributionImpl gd = new GammaDistributionImpl(shapeParameters[i], 1.0d);
        gd.reseedRandomGenerator(random.nextLong());
        try
        {
            samples[i] = gd.sample();
        }
        catch (MathException e)
        {
            e.printStackTrace();
        }
    }
    return samples;
}

这似乎解决了问题,即给定:
public static void main(String[] args)
{
    System.out.println(Arrays.toString(gammaSamples(new double[] { 2.0d, 2.0d, 2.0d }, new Random())));
}

一些示例输出如下:
[2.7506981228470084, 0.49600951917542335, 6.841476090550152]
[1.7571444623500108, 1.941865982739116, 0.2611420777612158]
[6.043421570871683, 0.8852269293415297, 0.6921033738466775]
[1.3859078943455487, 0.8515111736461752, 3.690127105402944]

我的问题是:

发生了什么?这是一个错误还是Apache Maths发行版故意这样做的?

如果我创建单独的分布对象,似乎很奇怪我必须担心它们被赋予什么种子,并确保它们足够不同。

另一个小烦恼是,我似乎无法将自己的Random对象传递给这些分布,而是只允许通过reseedRandomGenerator(long seed)方法更改种子。在尝试重现结果时,能够传递自己的Random对象将非常有用。

感谢任何帮助。

1个回答

2
通过查看javadoc,我发现以下类: 其中有一个方法public double[] sample(int sampleSize) throws MathException可以产生分布的随机样本。在默认实现中,通过循环调用sample()方法来生成样本。您尝试过吗?请注意,要保留HTML标记。
double[] samples = sample(shapeParameters.length);

编辑: 对不起,我看到你每次都使用一个新的alpha参数计算一个新的GammaDistributionImpl。我猜这是因为种子值是从系统时钟中派生出来的,具有有限的分辨率,接近构造函数的调用将产生相同的结果。请参阅此SO问题

以下是一些输入,让您进行更深入的调查:


谢谢,我认为你说得对,这可能是由于从系统时钟派生的种子值。我刚刚查看了库的3.1版本,他们有一个额外的构造函数GammaDistribution(RandomGenerator rng, double shape, double scale, double inverseCumAccuracy),这正是我想要的(能够传递自己的随机数生成器)。我觉得应该在某个地方发出警告,不要在循环中创建“随机”对象,因为它们可能会被赋予相同的种子,考虑到现代系统的速度。 - Richy
这只是感觉上像是一个种子问题,不是吗! - Lucas
这很明显是一个种子问题,而不仅仅是感觉上的。看一下我发布的代码,原始的“gammaSamples”方法无法正常工作并且使用默认种子,修改后的“gammaSamples”方法设置了自己的种子但在其他方面是等效的,并解决了问题。 - Richy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接