您好我注意到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对象在尝试重现结果时非常有用。
感谢您的帮助。
答案 0 :(得分:2)
通过查看javadoc:
我看到方法public double[] sample(int sampleSize) throws MathException
从分布中生成随机样本。默认 实现通过在循环中调用sample()来生成样本。
你试过吗?
double[] samples = sample(shapeParameters.length);
修改:很抱歉,我看到您每次使用新的GammaDistributionImpl
参数计算新的alpha
。我猜这是因为种子值是从具有有限分辨率的系统时钟导出的,而对构造函数的近距离调用将产生相同的结果。看看这个SO question。
以下是一些输入,可让您进行更深入的调查: