最近遇到了关于如何找到给定数字流的第x个百分位数的问题。如果流相对较小(可以存储到内存中,排序并且可以找到xth值),我基本了解如何实现这一点但我想知道如果数字流是公平的,百分位数是如何近似的大而且数字的数量是未知的。
答案 0 :(得分:0)
我认为您可以使用Reservoir sampling从流k
中选择统一的S
元素,然后将S
的xth百分位数与这些{{1}的xth百分位近似数字。 k
取决于您拥有多少内存以及近似值的精确程度。
修改强>
以下是测试解决方案的代码示例:
k
结果是:
近似百分位数:29
真实百分位:29
对于我使用的每个// create random stream of numbers
Random random = new Random(0);
List<Integer> stream = new ArrayList<Integer>();
for (int i = 0; i < 100000; ++i) {
stream.add((int) (random.nextGaussian() * 100 + 30));
}
// get approximate percentile
int k = 1000; // sample size
int x = 50; // percentile
// init priority queue for sampling
TreeMap<Double, Integer> queue = new TreeMap<Double, Integer>();
// sample k elements from stream
for (int val : stream) {
queue.put(random.nextDouble(), val);
if (queue.size() > k) {
queue.pollFirstEntry();
}
}
// get xth percentile from k samples
List<Integer> sample = new ArrayList<Integer>(queue.values());
Collections.sort(sample);
int approxPercent = sample.get(sample.size() * x / 100);
System.out.println("Approximate percentile: " + approxPercent);
// get real value of the xth percentile
Collections.sort(stream);
int percent = stream.get(stream.size() * x / 100);
System.out.println("Real percentile: " + percent);
,我得到了一个非常好的近似值,目前我不明白为什么它不适合你的情况。