我有一个包含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,依此类推。
我已经编写了自己的方法来做到这一点但感觉现有的方法会更好用。如果您知道这种方法,请告诉我。
答案 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);
}
}
这是我在运行每个版本时得到的时间:
答案 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;
}