【问题标题】:How to approximate the xth percentile for a large unknown quantity of number如何为大量未知数字逼近第 x 个百分位数
【发布时间】:2018-02-07 16:10:37
【问题描述】:

最近遇到了这个关于如何找到给定数字流的第 x 个百分位数的问题。如果流相对较小(可以存储到内存中,排序并且可以找到第 x 个值),我对如何实现这一点有一个基本的了解,但我想知道如果数字流是相当的,如何近似百分位数大,数字的数量是未知的。

【问题讨论】:

  • 我认为如果不存储数字(不一定在内存中)就无法做到这一点。
  • 您知道这些值的粗略分布吗?还是硬限制?
  • 不,除了数字出现的范围之外,没有明确的指示值的分布。这些值本质上是服务器响应时间,因此已经说明某些响应时间可能会出现轻微的乱序(但可以丢弃过于乱序的响应)。

标签: algorithm sampling percentile approximation


【解决方案1】:

我认为您可以使用Reservoir sampling 从流S 中统一选择k 元素,然后用这些k 数字的第x 个百分位近似S 的第x 个百分位。 k 取决于你有多少内存以及近似值应该有多精确。


编辑

这是一个测试解决方案的代码示例:

// 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);

结果是:

近似百分位数:29

实际百分位数:29

我对我使用的每个 x 都有一个很好的近似值,目前我不明白为什么它不适合你的情况。

【讨论】:

  • 所以我目前正在尝试将所选元素存储到数组列表中进行水库采样。但是,该近似值似乎与所需的第 x 个百分位数相去甚远。所以,我想知道数据结构的变化是否会进一步优化这一点?此外,流元素是响应时间等,尽管某些响应时间可能出现乱序;它们通常按某种排序的顺序排列,并且可以丢弃过于乱序的响应。知道了这一点,有没有一种不同的采样算法会更好?
  • @Bruce ,我在答案中添加了一个代码示例。目前我不明白为什么这个近似值不适合你。也许你可以提供一个流的例子?
猜你喜欢
  • 2018-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-07
  • 1970-01-01
相关资源
最近更新 更多