【问题标题】:Peek at a value from an array with a probabilistic quantity查看具有概率量的数组中的值
【发布时间】:2019-05-11 19:05:34
【问题描述】:

我有一个包含 10 个元素的数组。

|1|2|3|4|5|6|7|8|9|10|

这个想法是从这个数组中随机查看一个值,但要使用一些概率量。

元素的概率选择如下:

|5%|10%|15%|30%|20%|4%|6%|1%|3%|6%|

这意味着选择第一个元素有 5% 的机会,第二个元素有 10% 的机会等等。

我的解决方案:

import java.util.*;

public class Example {
     public static void main( String[] args ) {

         int [] values = {1,2,3,4,5,6,7,8,9,10};
         double [] probabilities = {0.05,0.1,0.15,0.3,0.2,0.04,0.06,0.01,0.03,0.06};


         double cumulativeSum = 0;
         double r = new Random().nextDouble();//random number between 0 and 1
         int index=0;// index of the chosen value
         for (double prob:probabilities) {
             cumulativeSum += prob;
             if (cumulativeSum >= r) {
                 break;
             }
             index++;
         }
         System.out.println(index);
         System.out.println("the value picked "+values[index]);

     }
}

我正在寻找比我更快的解决方案。我做的数组只是一个小例子,通常我可以有 10000 个单元格的数组。

【问题讨论】:

  • 你的概率总和为 101%
  • stackoverflow.com/questions/1761626/weighted-random-numbers 有一个很好的答案。因此,如果您将拥有包含大量数字的数组,则可以使用具有累积权重的二叉搜索树
  • @vlad324 您链接的答案与OP的解决方案几乎相同。
  • @P.Soutzikevich 是的,但是 OP 提到他有很大的输入数组,我建议他使用具有累积权重的二叉搜索树而不是数组,因为它会更快,这是预期结果使他的代码更快。二叉搜索树的想法不是我的,所以我附上链接,因为它有更多的细节

标签: java arrays random


【解决方案1】:

看起来您正在实现一种轮盘赌选择算法。

您可以查看stack-overflow question了解RWS的详细说明。

至于您要求的更快的解决方案,我认为使用其他算法不会大幅提高执行速度。您的解决方案似乎非常快,我看不出您需要“更快”的东西的原因。代码总是可以优化的,但这取决于你想要优化什么以及为什么你需要尽可能快的东西。如果在您的情况下计算速度很关键,可以考虑在Assembly 中实现您的代码,而不是Java

还有其他类似于 RWS选择算法,例如 随机通用选择 (SUS),如果您想这样做会更合适例如,查看多个元素。

【讨论】:

  • 在提供的链接中选择的遮阳篷与我的解决方案几乎相同。就我而言,这个解决方案的问题是,当我们应该查看数组的最后一个元素时,我们应该遍历整个数组。由于我的项目是使用 Java 编写的,因此使用另一种语言不符合我的需要。
  • 您可以对您的列表进行排序,以便概率最高的项目位于列表的开头(开始时)。否则,我想不出一种算法来优化你想要的东西
【解决方案2】:

alias method 是一种针对一般问题的算法,该算法采用一组可能值的概率并预先计算一些表,以便能够在 O(1) 中选择具有指定概率分布的元素,而不是在)。这几乎可以肯定是您的用例的最佳算法。

【讨论】:

  • 是的,这就是我想要的。一个实现keithschwarz.com/interesting/code/?dir=alias-method
  • 问题是在我的项目中我偷看一个值 -> 我改变了概率值 -> 偷看另一个值 -> 我改变了......一个这样的。这个解决方案会提供更好的性能吗?
  • @zakzak 如果你一直在改变概率,那么别名方法会非常昂贵——你必须一直重建表
【解决方案3】:

如果您的程序使用这些精确值 (1-10),那么它就相当简单了 - 只需创建一个数组,其中每个条目根据其概率出现多次。

public static void main(String[] args) {
    int[] values = {
            1, 1, 1, 1, 1,
            2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
            3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
            4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
            5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
            5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
            6, 6, 6, 6,
            7, 7, 7, 7, 7, 7, 8, 9, 9, 9,
            10, 10, 10, 10, 10, 10, 10
    };

    int value = values[new Random().nextInt(values.length)];
    int index = value - 1; // values 1-10 are in indices 0-9

    System.out.println(index);
    System.out.println("the value picked " + value);
}

就像我说的,这适用于静态值。如果您有动态值,则需要不同的方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-14
    • 1970-01-01
    • 2020-07-20
    • 2015-02-01
    • 1970-01-01
    • 2021-12-07
    • 1970-01-01
    相关资源
    最近更新 更多