概率性地随时间选择一组项目

时间:2018-06-19 10:58:07

标签: java math probability

我有一个在接受文件的服务器上运行的企业应用程序。用户每天都会提交数万个文件。客户希望每天自动选择50个这样的文件进行审核。

要求是:

  1. 文件必须在进入时选择(我们不能等待所有文件进入,然后在一天结束时选择50)
  2. 所选文件必须符合其他一些他们还没有告诉我的标准,但我确信仍会有数千个文件符合这些标准
  3. 系统一定不能“游戏化”。也就是说 - 他们不希望提交文件的用户意识到,如果他们等到下午或其他什么,他们的文件永远不会被审核。这意味着我们不能只选择进入的前50个,所选文件必须在一天中随机分布。
  4. 我们必须有50个文件。或者他们说。但是我很确定如果没有用户在一天中午之后提交了符合条件的文件,我们只收到25个文件,他们就可以了。所以我可以假设我感兴趣的文件类型在一整天内以合理的频率提交。
  5. 我想,我需要一些函数来计算文件被选中的概率,它使用当前所选文件的数量和一天中的时间作为输入。

    我已经创建了一个测试工具。请原谅狡猾的代码。在这里,“pushTask”线程通过将文件添加到堆栈来模拟进入的文件。此测试中的“文件”只是字符串,末尾有一个随机数字。

    “pullTask​​”线程模拟从堆栈中拉出的文件。它询问requirementsFunction(),如果“文件”满足所需的额外要求(并且在此测试中只是 - 它以零结尾),并且它询问probabilityFunction()是否应该选择文件。如果选择了文件,则会将其打印到System.out。

    我真的需要一些关于什么放入probabilityFunction()的帮助,因为目前那里有什么垃圾(我把它留在了所以你可以看到我尝试过的东西)。或者,如果有人知道使用项目/时间的数学概率函数也会很棒。

    package com.playground;
    
    import java.time.Duration;
    import java.time.Instant;
    import java.util.ArrayDeque;
    import java.util.Deque;
    import java.util.Random;
    
    public class ProbabilisticSelection {
    
        private static int TOTAL_FILES = 1000;
        private static int AUDIT_QUANTITY = 10;
        private static int TIME_IN_SECONDS_FOR_ALL_FILES = 10;
        private Random random = new Random();
        private Deque<String> stack = new ArrayDeque<String>();
        private boolean finished;
    
        public static void main(String[] args) throws InterruptedException {
            new ProbabilisticSelection().test();
        }
    
        private void test() throws InterruptedException {
            Instant begin = Instant.now();
    
            Runnable pushTask = () -> {
                while (!finished) {
                    int next = random.nextInt(TOTAL_FILES);
                    String item = "File: " + next;
                    stack.push(item);
                    if (Duration.between(begin, Instant.now()).getSeconds() >= TIME_IN_SECONDS_FOR_ALL_FILES) {
                        finished = true;
                    }
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
    
            Runnable pullTask = () -> {
                int itemNumber = 1;
                while (itemNumber <= AUDIT_QUANTITY && !finished) {
                    String poll = stack.poll();
                    if (requirementsFunction(poll) &&
                            probabilityFunction(itemNumber, Duration.between(begin, Instant.now()))) {
                        System.out.println(itemNumber++ + ": "+ poll);
                    } 
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                finished = true;
                Duration delta = Duration.between(begin, Instant.now());
                System.out.println();
                System.out.println("Retrieved files: " + (itemNumber - 1) + ", should be, " + AUDIT_QUANTITY);
                System.out.println("Time taken: " + delta.getSeconds() + ", should be, " + TIME_IN_SECONDS_FOR_ALL_FILES);
            };
    
            new Thread(pullTask).start();
            new Thread(pushTask).start();
        }
    
        private boolean requirementsFunction(String item) {
            return item != null && item.endsWith("0");
        }
    
        private boolean probabilityFunction(int itemNumber, Duration delta) {
            double limit = ((double)(AUDIT_QUANTITY-itemNumber)/(double)AUDIT_QUANTITY + 1); // probability goes down as number of items goes up
            double tension = (double)TIME_IN_SECONDS_FOR_ALL_FILES/((double)delta.getSeconds() + 1); // probablity goes up as time nears the end
            if (tension == 1) {
                return true;
            }
            double prob = limit * tension * 100; 
            int rand = random.nextInt(1000);
            return prob > rand;
        }
    }
    

1 个答案:

答案 0 :(得分:1)

算法称为Reservoir_sampling,可确保公平地从一些未知的大型k中抽取N个项目。 Java Java code