Javascript 获得均匀采样的数学上完美的方法;连锁店;项目数量
假设我想通过从0到9随机选取一个数字开始,然后(可选地)随机选取x+1和9之间的另一个数字来递归创建一个数字列表,其中x是最后选取的数字,并且可选地重复此过程。通过这种方式,您可以获得诸如Javascript 获得均匀采样的数学上完美的方法;连锁店;项目数量,javascript,recursion,random-sample,Javascript,Recursion,Random Sample,假设我想通过从0到9随机选取一个数字开始,然后(可选地)随机选取x+1和9之间的另一个数字来递归创建一个数字列表,其中x是最后选取的数字,并且可选地重复此过程。通过这种方式,您可以获得诸如1,3,6、3,4,8,9、2,7等列表。这是我真正想做的事情的简化 出于我的目的,我不想只是从列表中挑选一堆随机数,删除重复项,然后对它们进行排序。这需要递归地完成。问题是,以我描述的方式简单地做这件事并不会给所有数字一个平等的机会。它倾向于选择更大的数字,而不是更小的数字。我尝试了一些方法来抵消这一点,但它
1,3,6
、3,4,8,9
、2,7
等列表。这是我真正想做的事情的简化
出于我的目的,我不想只是从列表中挑选一堆随机数,删除重复项,然后对它们进行排序。这需要递归地完成。问题是,以我描述的方式简单地做这件事并不会给所有数字一个平等的机会。它倾向于选择更大的数字,而不是更小的数字。我尝试了一些方法来抵消这一点,但它太倾向于小数字了
这是使用Lo Dash中的随机整数函数的javascript:
function randomlist(index) {
if (index > 8) return;
var range = _.random(9 - index);
var randex = [_.random(index, index + range)];
if (_.random(10) < 6) randex = randex.concat(randomlist(randex[0] + 1));
return randex
}
tally = [0,0,0,0,0,0,0,0,0,0]
for (i=0;i<1000;i++) {
var list = randomlist(0);
list.forEach(function(x){tally[x]+=1});
}
函数随机列表(索引){
如果(指数>8)返回;
var范围=随机(9-指数);
var randex=[随机(指数,指数+范围)];
如果(随机(10)<6)randex=randex.concat(随机列表(randex[0]+1));
返回randex
}
tally=[0,0,0,0,0,0,0,0,0,0]
对于(i=0;i,根据您的描述,符合该描述的“列表”数量有限。因此,假设您创建一个包含所有列表的数组,然后简单地从数组中随机选择一些内容?此处:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>test-page</title>
<script type="text/javascript">
//<!--
var lists, und, tmp, dv, pkd, i, q,r,s,t,u,v,w,x,y,z;
function begin()
{ lists=[];
for(i=0,q=0; q<10; q++)
for(r=q+1;r<10;r++)
{ lists[i++]=[q,r];
for(s=r+1;s<10;s++)
{ lists[i++]=[q,r,s];
for(t=s+1;t<10;t++)
{ lists[i++]=[q,r,s,t];
for(u=t+1;u<10;u++)
{ lists[i++]=[q,r,s,t,u];
for(v=u+1;v<10;v++)
{ lists[i++]=[q,r,s,t,u,v];
for(w=v+1;w<10;w++)
{ lists[i++]=[q,r,s,t,u,v,w];
for(x=w+1;x<10;x++)
{ lists[i++]=[q,r,s,t,u,v,w,x];
for(y=x+1;y<10;y++)
{ lists[i++]=[q,r,s,t,u,v,w,x,y];
for(z=y+1;z<10;z++)
lists[i++]=[q,r,s,t,u,v,w,x,y,z];
} } } } } } } }
for(j=0; j<i; j++)
{ tmp=document.createElement("span");
tmp.innerHTML=lists[j]+"<br />";
document.body.appendChild(tmp);
}
tmp=document.createElement("span");
tmp.innerHTML="<br />Total: " + i + " lists. <br />"; //1013
document.body.appendChild(tmp);
pkd=[];
i=0;
dv=document.getElementById("pks");
return;
}
function Pick()
{ if(lists==und)
return;
q=Math.floor(Math.random()*1013);
for(r=0; r<i; r++)
if(pkd[r]==q) //check this array for previously-picked list
break;
if(r==i) //not previously picked?
{ pkd[i++]=q; //add to array
tmp=document.createElement("span");
tmp.innerHTML=lists[q]+"<br />";
dv.appendChild(tmp); //display this list
}
else
Pick(); //try again to pick an unpicked list
//DON'T click the button more than 1013 times!
return;
}
// -->
</script>
</head>
<body>
<input type="button" value="create lists" onclick="begin();" />
<input type="button" value="random pick" onclick="Pick();" /><br />
<br />
<div id="pks">
</div>
<br />
</body>
</html>
测试页
//
你是否忽略了一个事实,即大的数字比小的数字多,这就是为什么随机数函数更倾向于选择大的数字?也许你应该考虑所有的数字范围都有相同的位数——小的数字只是从0开始,比如053和008。为什么不选择它们之间的距离呢然后用扫描来计算数字?我的意思是[2,4,1,5,2]变成[2,6,7,12,14].你的概率分布是什么?你只需要前10个数字的一个均匀抽样的随机子集吗?然后在每个递归步骤中,要么选择特定的项,要么不选择。@Vernoner3 Voltazim,我认为你不理解我的问题,因为你的答案对我来说没有意义。\uuU9-索引)索引等于0的
有相同的机会选择1
或任何其他数字。但是总体上1
出现的机会较小,因为它只能出现在第一个单元格中。因此,您应该替换\uU9-索引)
该函数根据数组的最大大小为1
赋予更多权重。您可以通过询问来找到每个数字的确切权重。这很聪明,当然它会产生完全均匀的采样。唯一的问题是它往往会产生太多长的列表。在我的描述中,我提到了(可调)每一个新的数字在其递归时被添加到列表中的概率百分比。因此,如果概率为50%,那么你将得到1个数字的2个数字列表的一半和3个数字列表的四分之一,依此类推。但实际上我实现了一个与你提出的解决方案类似的解决方案。也就是说,我可以一开始就生成一个排序列表对递归过程进行一次初始化,然后在每次递归时从列表中弹出元素。因为我确实需要递归,但这些数字实际上不必在递归过程中生成。但当我问这个问题时,我没有意识到这一点。