【问题标题】:Generate Poisson Arrival in Java在 Java 中生成泊松到达
【发布时间】:2012-04-07 15:24:55
【问题描述】:

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

在我的示例中,我有:每天 2.2 次请求,即每天 2.2 次到达,平均服务时间为 108 小时。考虑到我的程序从 t=0 分钟开始,我想创建一个返回arrivals[] 的函数,它将包含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

有人可以帮帮我吗?

谢谢,

安娜

【问题讨论】:

  • 阻止您这样做的具体问题是什么?
  • 欢迎来到 SO。请阅读faqHow to Ask,了解如何在此处发布问题的详细信息。在没有证据表明您已尝试解决问题的情况下发布问题被视为超出范围。 SO 用户提供特定问题的答案,但通常不会为您完成工作。此外,您应该在发布之前在网络和 SO 上搜索过答案。
  • 我用这个答案来实现类 PoissonDistribution link
  • 我用这个答案来实现类 PoissonDistribution link

标签: java poisson


【解决方案1】:

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

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) 被四舍五入为零......哎呀!)

【讨论】:

    【解决方案2】:

    你可以使用this algorithm proposed by 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 次迭代之后循环条件变为

    p1 * p2 * ... * pk > L

    相当于

    -ln(p1)/均值 -ln(p2)/均值 ... -ln(pk)/均值 > 1

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

    【讨论】:

    【解决方案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,所以使用起来更安全: 下一个事件 = -Ln(1.0-U)/λ。 如果您的代码使用基于毫秒的时间/睡眠函数,您可以使用:

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

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

    【讨论】:

    • 迄今为止最好的方法
    【解决方案4】:

    你可以把它添加到 build.gradle

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

    并使用类 PoissonDistribution more detail

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-24
      • 1970-01-01
      • 2012-10-17
      • 1970-01-01
      • 2010-11-12
      • 1970-01-01
      • 1970-01-01
      • 2022-08-16
      相关资源
      最近更新 更多