【问题标题】:Given a min, max, mean and standard deviation, generate a random value from a distribution using Java给定最小值、最大值、平均值和标准差,使用 Java 从分布中生成随机值
【发布时间】:2021-12-22 21:52:12
【问题描述】:

鉴于 min = 0.00,max = 1400.00,mean = 150.50,标准差 = 25.00,如何根据这些统计数据生成随机值?据我了解,该图是一个倾斜图,但是我不太确定它是否是对数正态分布的。但是,据我目前的理解,以下代码返回一个来自正态分布的值。

private static int generateValue(double mean, double stdDev) {
    return (rand.nextGaussian() * stdDev) + mean);
}

【问题讨论】:

  • 这是一个统计建模问题,而不是编程问题。您的分布既不能是正态分布也不能是对数正态分布,因为它们都有无限的支持,并且您指定了有限的最小值和最大值。您需要确定一个能够同时满足所有四个约束的分布,这是不平凡的并且可能不可行。示例:我们可以排除三角分布,因为mean = (min + mode + max) / 3。使用您的约束求解模式会产生 -948.5,但模式必须是介于最小值和最大值之间的值,因此不存在这样的三角形。
  • 明白,但是,鉴于以上这些值,有没有办法正确获取随机生成的值?
  • 不知道要从哪个发行版生成。这就是为什么我说“你需要确定一个分布......”
  • 嗨@pjs,鉴于分布是连续分布,有可能吗?
  • 找到了一种使用缩放的 beta 发行版的方法。在过去的 15 年里,我不是 java 人(甚至没有在我的系统上安装它),但如果你有兴趣,我可以用 python 解释。

标签: java statistics distribution


【解决方案1】:

一种方法是找到一个自然有界分布,该分布具有由两个参数表征的均值和方差。这将问题从试图同时满足四个约束(最小值、最大值、平均值和 s.d.)减少到根据两个参数求解两个方程(平均值和 s.d.)。 beta distribution 满足这些需求。它是在 [0, 1] 范围内定义的,但是可以通过将结果缩放 1400 来轻松调整到您的问题。我使用上面提供的 Wikipedia 链接来刷新我对 beta 均值和方差公式的记忆,然后前往Wolfram|Alpha 的求解器,使用平均值 150.5/1400 和标准差 25/1400 输入公式。这产生了 α=32.237057 和 β=267.642543 的解,因此您可以通过使用派生参数值生成值 X = 1400 * beta(α, β) 来满足您的要求。

我已经超过 15 年没有使用 Java 并且没有在我的机器上安装它,所以我使用 python 对其进行了测试以确认参数化:

from scipy.stats import beta
import math

a = 32.237057
b = 267.642543
n = 100_000_000

mean, var = beta.stats(a, b, moments='mv')
print( f"mean = {mean * 1400}, std dev = {math.sqrt(var) * 1400}" )

产生

平均值 = 150.50000000000003,标准差 = 25.000000000000004

我会说这与使用浮点运算的要求差不多。然后我尝试了实际的生成:

r = beta.rvs(a, b, size=n) * 1400
print( f"For n={n} min and max are {min(r)} and {max(r)}, respectively")

带输出:

对于 n=100000000,最小值和最大值分别为 45.22697720545599 和 327.87270125710194

您可能认为经验最大值较低,但请注意,1400 仅比平均值高 50σ。 Chebyshev's inequality 给出了一个非常弱的非参数上限,用于获得这样一个值的概率——它小于 1/2500。在许多情况下,包括这一次,实际概率远小于切比雪夫的界限。也就是说,得到接近1400的结果的概率基本上为零。

通过 Apache Commons 库可以通过 Google 快速搜索找到类 BetaDistribution,因此您应该可以直接将此方法映射到 Java。

【讨论】:

  • 嗨@pjs,我非常感谢您的详尽解释。我将查看您提供的链接并使用 BetaDistribution 来解决我的问题。非常感谢
【解决方案2】:

您可以使用 do while 或 just while 循环,然后您可以简单地使用 if 语句为您的数字设置参数并生成一个随机数!

import java.util.Random;
class GenerateRandom {
public static void main( String args[] ) {
  Random rand = new Random(); //instance of random class
  int upperbound = 25;
    //generate random values from 0-24
  int int_random = rand.nextInt(upperbound); 
  double double_random=rand.nextDouble();
  float float_random=rand.nextFloat();
  
  System.out.println("Random integer value from 0 to" + (upperbound-1)       + " : "+ int_random);
  System.out.println("Random float value between 0.0 and 1.0 :  "+float_random);
  System.out.println("Random double value between 0.0 and 1.0 : "+double_random);
}

【讨论】:

  • 谢谢,但这段代码是用于正常生成随机数,我正在查看的是对数正态分布值
猜你喜欢
  • 2018-11-10
  • 2020-08-30
  • 1970-01-01
  • 2012-08-16
  • 2020-09-18
  • 1970-01-01
  • 1970-01-01
  • 2018-07-01
  • 2014-08-04
相关资源
最近更新 更多