根据帕累托原则

时间:2016-03-29 10:36:08

标签: java random distribution

我有一个List<T>,并尝试根据Pareto Principle随机选择项目,因此前20%的项目将被挑选80%的次数,剩下的80%的项目将被挑选20%的次数。到目前为止,我有一个简单的实现:

static <T> T pickPareto(List<T> list) {
    int n = list.size();
    int first = n * 0.2;
    return rnd.nextFloat() < 0.8            
           ? list.get(rnd.nextInt(first))                // pick one of first 20%
           : list.get(first + rnd.nextInt(n - first));   // pick one of remaining 80%
}

效果很好,但根据步骤函数的分布选择项目。

有没有人知道如何根据平滑功能的分布来选择项目(可能不是Pareto,但持有20/80属性)?

2 个答案:

答案 0 :(得分:2)

在研究上花了一些时间后,我发现这个问题可以解决为找到函数的问题,该函数应用于产生均匀随机分布的函数(例如.nextFloat()),从而得到所需的分布。 / p>

此类函数f(x)必须符合以下所有条件:

  1. f(0) = 0

  2. f(x) → 1 x → 1

  3. [0, 1)

  4. 的间隔内不减少,更严格地增加
  5. 间隔为[0, 1)

  6. f(0.8) = 0.2 - 80/20帕累托原则的条件,或者,共同的f(p) = 1 - p

  7. 最后,我成功完成了这样的功能。它可以是:

    f(x)=(x a + 1 - (1 - x) 1 / a )/ 2,
    a = log p (1 - p)

    这里,参数p ∈ (0, 1)正是它在条件5中的含义:它是一个调整参数,显示了结果分布与统一的不同之处。例如,如果p = 0.8f(0.8) = 0.2。如果p = 0.5,则a = 1,则函数会折叠为f(x) = x

    p = 0.8的图表:

    enter image description here

    所以从列表中选择的方法如下:

    public static <T> T pickRandomly(List<T> list, float p) {
        if (p <= 0 || p >= 1.0)
            throw new IllegalArgumentException();
        double a = Math.log(1.0 - p) / Math.log(p);
        double x = rnd.nextDouble();
        double y = (Math.pow(x, a) + 1.0 - Math.pow(1.0 - x, 1.0 / a)) / 2.0;
        return list.get((int) (list.size() * y));
    }
    

    例如,从10个整数列表中选取1000次p = 0.8

    0: 646
    1: 153  // 0 or 1 occured 799 times
    2: 60
    3: 57
    4: 32
    5: 26
    6: 18
    7: 7
    8: 1
    9: 0
    

答案 1 :(得分:-1)

使用nextFloat(),它将从这个随机数生成器的序列中为您提供下一个伪随机数,均匀分布的浮点值介于0.0和1.0之间。

return rnd.nextFloat() < 0.8            
       ? list.get(rnd.nextInt(first))                // pick one of first 20%
       : list.get(first + rnd.nextInt(n - first));   // pick one of remaining 80%

另外,我认为rnd是浮动的。