alias sample method——运行时间复杂度为O(1)的抽样算法
根据离散离散概率分布抽样是一个常见的问题。这篇文章将介绍运行时间复杂度为O(1)的 alias method 抽样算法思想。
下面举例说明:
比如 a,b,c,d 的概率分别为 0.1,0.2,0.3,0.4。如何编程实现按概率抽样呢?
最简单的方法是生成一个数组:1,2,2,3,3,3,4,4,4,4。然后随机生成一个不大于4的数。这种方法简单易实现,但当随机变量很多时,占用的空间就太大了。
再进一步,可以根据它们的概率密度分布(PDF)生成累积分布(CDF):0.1,0.3,0.6,1。然后生成不大于1的随机数,看它落在哪个区间。但这需要与临界点进行比较,
我们知道,插入有序数列最好的时间复杂度为O(logn)。
而alias method可以实现以运行复杂度为O(1)的方式抽样。当然它需要预处理,预处理的时间复杂度为O(n),但实际过程中,尤其是重复跑的时候,运行时间复杂度才是重要的。
alias method 怎么处理的呢?我们知道等概率分布抽样的时间复杂度为O(1),如果二项不等概率分布抽样的时间复杂度也为O(1)。如果a,b,c,d 概率分布均为0.25,那我们随机
生成1,2,3,4,抽中哪个就是哪个,复杂度自然为O(1)。如果只有两个变量,比如 a,b 概率分布为 0.2,0.8.那我们用CDF的方法,小于0.2就是a, 大于就是b,只需比较一次,
所以复杂度也是O(1)。alias method就是把这两种方法结合起来.
首先我们把原概率分布乘以N(为后面的拼接做准备),这里是N=4。得到:0.4,0.8,1.2,1.6。

然后我们把它拼成等概率分布和二项不等概率分布:

注意拼接的过程中,最多每一列最多有两种颜色。乘以N就保证了一定可以存在这样的拼法。具体证明见引用[1],图片出自引用[2]。
怎么抽样呢?
首先我们以等概率分布抽每一列。不失一般性,假设我们抽中了第三列。然后进行二项分布抽样,如果小于0.6,就是褐色,也就是c,反之,就是红色,也就是d.
这两个操作的复杂度均为O(1),故总时间复杂度也为O(1)。
怎么保证正确性呢?
以样本d,举例,原来抽中c的概率为0.4。运用alias method方法后,抽中c的概率为(0.25+ 0.25 * 0.2 + 0.25 * 0.4) = 0.4。事实上,等比例放大后再拆分,
其概率分布比例并没有变,结果当然也不会变。具体证明见引用[1].
引用:
1, http://www.keithschwarz.com/darts-dice-coins/
2, http://blog.csdn.net/sky_zhe/article/details/10051967
alias sample method——运行时间复杂度为O(1)的抽样算法的更多相关文章
- 时间复杂度为O(nlogn)的LIS算法
时间复杂度为 n*logn的LIS算法是用一个stack维护一个最长递增子序列 如果存在 x < y 且 a[x] > a[y],那么我们可以用a[y]去替换a[x] 因为a[y]比较小 ...
- 时间复杂度为O(nlogn)的排序算法
时间复杂度为O(nlogn)的排序算法(归并排序.快速排序),比时间复杂度O(n²)的排序算法更适合大规模数据排序. 归并排序 归并排序的核心思想 采用"分治思想",将要排序的数组 ...
- Alias sample(别名采样)
应用场景:加权采样,即按照随机事件出现的概率抽样 具体算法: 举例如上,随机事件出现的概率依次是1/2,1/3,1/12,1/12;记随机事件的个数为N,则所有事件概率乘以N后概率为2,4/3,1/3 ...
- 平均时间复杂度为O(nlogn)的排序算法
本文包括 1.快速排序 2.归并排序 3.堆排序 1.快速排序 快速排序的基本思想是:采取分而治之的思想,把大的拆分为小的,每一趟排序,把比选定值小的数字放在它的左边,比它大的值放在右边:重复以上步骤 ...
- Java虚拟机运行时数据区域及垃圾回收算法
程序计数器 记录正在执行的虚拟机字节码指令的地址(如果正在执行的是本地方法则为空). Java 虚拟机栈 每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表.操作数栈.动态链接.方法出口 ...
- (转)递归算法的时间复杂度终结篇与Master method
开篇前言:为什么写这篇文章?笔者目前在学习各种各样的算法,在这个过程中,频繁地碰到到递归思想和分治思想,惊讶于这两种的思想的伟大与奇妙的同时,经常要面对的一个问题就是,对于一个给定的递归算法或者用分治 ...
- python-Day5-深入正则表达式--冒泡排序-时间复杂度 --常用模块学习:自定义模块--random模块:随机验证码--time & datetime模块
正则表达式 语法: mport re #导入模块名 p = re.compile("^[0-9]") #生成要匹配的正则对象 , ^代表从开头匹配,[0 ...
- 关于乱序(shuffle)与随机采样(sample)的一点探究
最近一个月的时间,基本上都在加班加点的写业务,在写代码的时候,也遇到了一个有趣的问题,值得记录一下. 简单来说,需求是从一个字典(python dict)中随机选出K个满足条件的key.代码如下(py ...
- java.lang.reflect.Method.getAnnotation()方法示例【通过反射获取到方法对象再获取方法对象上的注解信息】
转: java.lang.reflect.Method.getAnnotation()方法示例 java.lang.reflect.Method.getAnnotation(Class <T&g ...
随机推荐
- Problem A 栈
Description You are given a string consisting of parentheses () and []. A string of this type is s ...
- linux命令每日一练习-pwd,cd
pwd显示当前路径. pwd -P没能明白什么意思, cd 进入目录 cd ..返回上级目录
- 【转】CentOS yum安装和卸载软件的使用方法
在CentOS yum安装和卸载软件的使用方法安装方法安装一个软件时. CentOS yum -y install httpd安装多个相类似的软件时 CentOS yum -y install ...
- Jquery实现的Tabs标签页
效果图: HTML: <div class="tabs"> <ul id="tabs"> <li class="tab- ...
- 分析一个嵌入payload的恶意.lnk文件
原文:https://isc.sans.edu/diary/Analyzis+of+a+Malicious+.lnk+File+with+an+Embedded+Payload/20763 We re ...
- static声明初始化块的一下注意事项
通过输出结果,我们可以看到,程序运行时静态初始化块最先被执行,然后执行普通初始化块,最后才执行构造方法.由于静态初始化块只在类加载时执行一次,所以当再次创建对象 hello2 时并未执行静态初始化块.
- LeetCode222 Count Complete Tree Nodes
对于一般的二叉树,统计节点数目遍历一遍就可以了,但是这样时间复杂度O(n),一下就被卡住了. 这题首先要明白的是,我们只需要知道叶子节点的数目就能统计出总节点树. 想法1: 既然是完全二叉树,我肯定是 ...
- struts2中form提交到action中的中文参数乱码问题解决办法(包括取中文路径)
我的前台页是这样的: <body> <form action="test.action" method="post"> ...
- VS调试Ajax
VS调试Ajax: 1.ashx在后台处理程序中设定断点 2.触发AJAX 3.F12打开浏览器调试,搜索找到ajax调用的JS,设置断点,在浏览器中单步调试,会自动进入后台处理程序,然后就可以调试后 ...
- Linux学习之CentOS--FTP服务原理及vsfptd的安装、配置
本篇随笔将讲解FTP服务的原理以及vsfptd这个最常用的FTP服务程序的安装与配置... 一.FTP服务原理 FTP(File Transfer Protocol)是一个非常古老并且应用十分广泛的文 ...