3

我想在 Java 中创建一个函数,在给定平均到达率 (lambda) 和平均服务率 (mu) 的情况下生成泊松到达。

在我的示例中,我有:每天 2.2 次请求,换句话说,每天 2.2 次到达,平均服务时间为 108 小时。考虑到我的程序在 t=0 分钟开始,我想创建一个返回到达 [] 的函数,该函数将包含 t1、t2 和可能的 t3。T1、t2 和 t3 是一天中发生此到达的时刻(以分钟为单位)。我有以下限制:

t1 < t2 < t3 < 1440 minutes (24 hours*60 minutes/hour)

t2-t1 > 108 minutes

t3-t2 > 108 minutes

t3+ 108 minutes < 1440 minutes

有人可以帮帮我吗?

谢谢,

安娜

4

4 回答 4

6

您可以使用D. Knuth 提出的这个算法

private static int getPoissonRandom(double mean) {
    Random r = new Random();
    double L = Math.exp(-mean);
    int k = 0;
    double p = 1.0;
    do {
        p = p * r.nextDouble();
        k++;
    } while (p > L);
    return k - 1;
}

要了解这是如何工作的,请注意在k次迭代后循环条件变为

p 1 * p 2 * ... * p k > L

这相当于

-ln(p 1 )/均值 -ln(p 2 )/均值 ... -ln(p k )/均值 > 1

请注意,如果p是均匀分布的,则 -ln(p)/mean 具有给定均值的指数分布。具有泊松分布的随机变量等于当事件之间的间隔长度是具有指数分布的独立随机变量时,给定事件在固定间隔内发生的次数。由于我们使用泊松分布的平均值作为事件间隔的指数分布的平均值,因此我们计算发生次数的固定内部是单位长度。因此,循环条件总结了事件之间的间隔长度,并检查我们是否超出了单位间隔。如果我们在计算第 k 个事件时超出了单位间隔,则在该间隔内发生了 k-1 个事件,因此我们返回 k-1。

于 2012-03-23T01:26:22.133 回答
3

我找到了这个解决方案,使用逆变换采样:

http://preshing.com/20111007/how-to-generate-random-timings-for-a-poisson-process

它不使用拒绝抽样方法,高效且准确。

它利用了事件之间的时间分布是指数分布的事实,参数 lambda 是到达率。指数分布是 lambda exp(-lambda x)。为了从该分布中采样值并避免拒绝采样,使用其累积分布函数 (CDF) 更容易:1 - exp(-lambda x)。CDF 是一个函数,从 0.0 开始,随着参数的增大到 1.0。直观地说,随着时间的流逝,您获得事件的概率会增加。

为了对 CDF 进行采样并再次避免拒绝采样,更容易在 [0,1] 之间选择一个统一的随机数 U,并将该值插入 CDF 的反函数中,得到: nextEvent = - Ln(U) /拉姆达。因为 Ln(0) 是未定义的,并且大多数随机数生成器都包含 0.0 并排除 1.0,所以使用起来更安全:nextEvent = -Ln(1.0-U)/lambda。如果您的代码使用基于毫秒的时间/睡眠函数,您可以使用:

双倍率 = 20.0/1000.0;// 平均每秒 20 个

睡眠(地板(-1.0 * log(1.0 - rand()*1.0/RAND_MAX) / rate));

于 2012-11-01T19:45:21.103 回答
1

您可以将其添加到 build.gradle

implementation 'org.kie.modules:org-apache-commons-math:6.5.0.Final'

并使用类 PoissonDistribution更详细

于 2019-05-17T11:49:40.737 回答
0

这是一些简化的代码,用于生成具有给定均值的泊松数:

private static int poisson(double mean) {
    int r = 0;
    double a = random.nextDouble();
    double p = Math.exp(-mean);

    while (a > p) {
        r++;
        a = a - p;
        p = p * mean / r;
    }
    return r;
}

您应该能够使用这个或类似的东西来生成每个时间段的到达次数:输入应该是您在该期间预计到达的平均次数。

请注意,如果您的平均值非常大(例如 500+),您将希望使用正态分布来近似到达数量。这更有效,而且它避免了上面代码中固有的数值溢出问题(在某些时候 Math.exp(-mean) 被四舍五入为零......哎呀!)

于 2012-03-23T01:20:57.983 回答