没有用Java替换概率的样本

时间:2015-04-06 22:38:41

标签: java sampling

我有一个包含10个概率的列表(假设它们按降序排序):<p1, p2, ..., p10>。我想抽样(没有替换)10个元素,这样选择 i -th索引的概率就是p_i。

我可以使用像Random这样的常用库中的Java方法吗?

示例:5个元素列表:&lt; 0.4,0.3,0.2,0.1,0.0&gt;

选择5个索引(无重复),以便选择概率由上面列表中该索引的概率给出。因此,索引0将以概率0.4选择,索引1选择概率0.3,依此类推。

我已经编写了自己的方法来做到这一点但感觉现有的方法会更好用。如果您知道这种方法,请告诉我。

2 个答案:

答案 0 :(得分:0)

这通常是这样做的:

function loadBoardRecords(template){
    var query = {}; 

    if($('input:text[name=localBoardTripNumSetting]').val() != ""){
        query['tripNumber'] = {$regex: new RegExp('^' + $('input:text[name=localBoardTripNumSetting]').val(), 'i')};
    }

            if($('input:text[name=localBoardPUStateSetting]').val() != ""){
        query['puState'] = {$regex: new RegExp('^' + $('input:text[name=localBoardPUStateSetting]').val(), 'i')};
    }

    if($('#localBoardPUDateSetting').val() != ""){
        puDate = moment($('#localBoardPUDateSetting').val(), "MM-DD-YYYY").toDate();
        query['puDate'] =  puDate;
    }

    if($('input:text[name=localBoardDELCitySetting]').val() != ""){
        query['delCity'] = {$regex: new RegExp('^' + $('input:text[name=localBoardDELCitySetting]').val(), 'i')};
    }

    if($('input:text[name=localBoardDELStateSetting]').val() != ""){
        query['delState'] = {$regex: new RegExp('^' + $('input:text[name=localBoardDELStateSetting]').val(), 'i')};
    }

    if($('#localBoardDELDateSetting').val() != ""){
        delDate = moment($('#localBoardDELDateSetting').val(), "MM-DD-YYYY").toDate();
        query['delDate'] =  delDate;
    }


    template.searchQuery.set( query );
}

如果要返回概率,请执行以下操作:

    static int sample(double[] pdf) {
        // Transform your probabilities into a cumulative distribution
        double[] cdf = new double[pdf.length];
        cdf[0] = pdf[0];
        for(int i = 1; i < pdf.length; i++)
            cdf[i] += pdf[i] + cdf[i-1];
        // Let r be a probability [0,1]
        double r = Math.random();
        // Search the bin corresponding to that quantile
        int k = Arrays.binarySearch(cdf, random.nextDouble());
        k = k >= 0 ? k : (-k-1);
        return k;
    }

编辑:我刚刚注意到你在标题不加替换的采样中说。快速做起来并不是那么简单(我可以给你一些代码)。无论如何,在这种情况下,你的问题没有任何意义。您无法在没有替换概率分布的情况下进行抽样。你需要绝对的频率。

即。如果我告诉你我有一个装满两个球的盒子:橙色和蓝色,比例分别为20%和80%。如果你不告诉我每个球有多少球(绝对值),我不能告诉你在几回合你将有多少球。

EDIT2:更快的版本。这不是典型的,但我在网上找到了这个建议,我也在我的项目中使用过它。

    return pdf[k];

测试一下:

    static int sample(double[] pdf) {
        double r = random.nextDouble();
        for(int i = 0; i < pdf.length; i++) {
            if(r < pdf[i])
                return i;
            r -= pdf[i];
        }
        return pdf.length-1;  // should not happen
    }

您可以看到我们得到的输出与使用的PDF非常相似:

// javac Test.java && java Test

import java.util.Arrays;
import java.util.Random;

class Test
{
    static Random random = new Random();

    public static void sample(double[] pdf) {
        ...
    }

    public static void main(String[] args) {
        double[] pdf = new double[] { 0.3, 0.4, 0.2, 0.1 };
        int[] counts = new int[pdf.length];
        final int tests = 1000000;
        for(int i = 0; i < tests; i++)
            counts[sample(pdf)]++;
        for(int i = 0; i < counts.length; i++)
            System.out.println(counts[i] / (double)tests);
    }
}

这是我在运行每个版本时得到的时间:

  • 第一版:0m0.680s
  • 第二版:0m0.296s

答案 1 :(得分:0)

使用sample [i]作为值数组的索引。

public static int [] WithoutReplacement(int m,int n){

    int[] perm = new int[n];
    for (int i = 0; i < n; i++) {
        perm[i] = i;
    }
    //take sample
    for (int i = 0; i < m; i++) {
        int r = i + (int) (Math.random() * (n - 1));
        int tmp = perm[i];
        perm[i] = perm[r];
        perm[r] = tmp;
    }
    int[] sample = new int[m];
    for (int i = 0; i < m; i++) {
        sample[i] = perm[i];
    }
    return sample;
}