怎么写一个带概率的随机抽取模型?

2014-11-03 10:34:37 +08:00
 zhimingcc
对于[1,2,3,4,5,6,7]这个数组,如果随机抽取,肯定每个数的被抽取的概率都是1/7,
代码大概是 Random.nextInt(7)就搞定了

如果人为增加一个概率,比如1,2概率是0.25,3,4,5,6,7都是0.1的概率,
该怎么写这样一个带概率的抽取模型?
5305 次点击
所在节点    程序员
28 条回复
mengzhuo
2014-11-03 10:49:51 +08:00
https://www.v2ex.com/t/142820#reply11

搭车同求更快的算法
robbielj
2014-11-03 10:53:23 +08:00
最简单的说可以抽两次吧
先分成[1,2]和剩下的,
第一次random两个组,都是0.5
第二次在组内random
zhimingcc
2014-11-03 10:54:57 +08:00
@robbielj 不能这么写死啊,我只是举个例子。。。。比如用不同的概率分布模型
andyzhshg
2014-11-03 10:56:16 +08:00
构造一个数组,里边1,2各25个,3,4,5,6,7各10个(不一定必须是25,10,可取最小整数倍,比如5和2),然后就继续用你说的算法就行了...不过我这办法看起来很矬的样子...
CtrlSpace
2014-11-03 10:58:04 +08:00
一个笨方法。
弄一个长数组,按比例存放要抽取的数据,然后随机抽取数组下标。
staticor
2014-11-03 10:58:42 +08:00
加一个权重的字典
zhimingcc
2014-11-03 10:59:42 +08:00
@mengzhuo GitHub被墙了。。。。先跪求翻墙软件,shadowsocksX感觉有点慢!
guotie
2014-11-03 11:02:58 +08:00
4楼的方法是最快的。
lichao
2014-11-03 11:03:16 +08:00
思路:

i = nextInt(1..100)

case i
when 1..25 then 1
when 26..50 then 2
when 51..60 then 3
when 61..70 then 4
when 71..80 then 5
when 81..90 then 6
when 91..100 then 7
whywhy36
2014-11-03 11:05:08 +08:00
sorry, no Chinese Input Method :-(

1. init one mapping according to the probability
1-25 -> 0
26-50 -> 1
51-60 -> 2
...
2. Random.nextInt(100)
3. pick the index from the mapping
4. get the number ...
zhimingcc
2014-11-03 11:08:03 +08:00
@lichao 赞一个!!简单但容易实现!!
yxz00
2014-11-03 11:20:19 +08:00
如果精度要求不是很高,四楼的方法不错
khowarizmi
2014-11-03 11:50:53 +08:00
发现跟楼上的思路重复了,但还是写一下吧.(仅仅针对lz给的例子)

p = Math.random()
if 0 < p < 0.25
x = 1
if 0.25 < p < 0.5
x = 2
....
delphiqin
2014-11-03 12:30:51 +08:00
delphiqin
2014-11-03 12:33:08 +08:00
额,发代码失败,重来……
https://gist.github.com/DelphiQin/37379f79fa03c3ff84d5
hahastudio
2014-11-03 12:35:43 +08:00
xiaoxiaoming
2014-11-03 13:45:16 +08:00
可以用一个 类似 轮盘转法,命中率就是长度 或者是面积
jokester
2014-11-03 14:34:58 +08:00
Weighted random sampling with a reservoir 这篇论文给出了一个保证one-pass的算法
feiyuanqiu
2014-11-03 14:36:54 +08:00
php:

function rand_weight($numbers)
{
$total = 0;
$dist = array();
foreach ($numbers as $num => $weight) {
$total += $weight;
$dist[$num] = $total;
}
$rand = mt_rand(0, $total - 1);
foreach ($dist as $num => $weights) {
if ($rand < $weights) { return $num; }
}
}
feiyuanqiu
2014-11-03 14:44:50 +08:00
使用:
$a = array(
'this' => 10, // 50%
'is' => 2, // 10%
'a' => 5, // 25%
'test' => 3, // 15%
);
$result = array();
for ($i=0; $i < 100; $i++) {
$result[] = rand_weight($a);
}
print_r(array_count_values($result));exit;

// 结果: Array ( [a] => 24 [this] => 50 [is] => 8 [test] => 18 )

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/143548

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX