我有一个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属性)?
答案 0 :(得分:2)
在研究上花了一些时间后,我发现这个问题可以解决为找到函数的问题,该函数应用于产生均匀随机分布的函数(例如.nextFloat()
),从而得到所需的分布。 / p>
此类函数f(x)
必须符合以下所有条件:
f(0) = 0
f(x) → 1
x → 1
在[0, 1)
间隔为[0, 1)
f(0.8) = 0.2
- 80/20帕累托原则的条件,或者,共同的f(p) = 1 - p
最后,我成功完成了这样的功能。它可以是:
f(x)=(x a + 1 - (1 - x) 1 / a )/ 2,
a = log p (1 - p)
这里,参数p ∈ (0, 1)
正是它在条件5中的含义:它是一个调整参数,显示了结果分布与统一的不同之处。例如,如果p = 0.8
则f(0.8) = 0.2
。如果p = 0.5
,则a = 1
,则函数会折叠为f(x) = x
。
p = 0.8
的图表:
所以从列表中选择的方法如下:
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
是浮动的。