随机抽样与概率(Alias抽样,蓄水池抽样,洗牌算法)
1、Alias采样
学习来源:
1、时间复杂度O(1)的离散采样算法——Alias method
程序实现
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import numpy as np def alias_setup(probs): K = len(probs) q = np.zeros(K) J = np.zeros(K, dtype=np.int) smaller = [] larger = [] for kk, prob in enumerate(probs): q[kk] = K * prob # 保存面积块 if q[kk] < 1.0: smaller.append(kk) # 面积小于1的元素下标 else: larger.append(kk) # 面积大于1的元素下标 while len(smaller) > 0 and len(larger) > 0: small = smaller.pop() large = larger.pop() # J 记录的是填充这一列的下标 J[small] = large # q 记录的是原来事件的占比 q[large] = q[large] - (1 - q[small]) if q[large] < 1.0: smaller.append(large) else: larger.append(large) return J, q def alias_draw(J, q): K = len(J) kk = int(np.floor(np.random.rand() * K)) # 随机选一列 if np.random.rand() < q[kk]: return kk else: return J[kk] if __name__ == "__main__": J, q = alias_setup([1/2, 1/3, 1/12, 1/12]) print(J, q) # [0 0 0 1] [1. 0.66666667 0.33333333 0.33333333] ret = alias_draw(J, q)
构造表的时间复杂度O(n),采样的时间复杂度O(1)
2、蓄水池抽样
问题描述:给定一个数据量很大的整数数组(不能一次全部读取到内存中)和一个目标数(保证出现在数组中),目标数在数组中可能出现多次,要求对与目标数相等的数的下标随机抽样,使得每个下标等概率出现。
方法:设定一个种子为0,假设有m个下标符合,每次遇到第i个,则从[0,i)中随机抽取一个数,如果这个数等于种子0,就记录当前的下标;
抽取的下标为第k个概率 = 1/k * (1 - 1/(k+1)) * ... *(1 - 1/m) = 1/m
3、洗牌算法
问题描述:随机打乱一个数组,使得每种排列都等概率的出现
方法:第i个数与[i, n-1]中的随机一个数进行交换