Alias sample(別名采樣)


應用場景:加權采樣,即按照隨機事件出現的概率抽樣

具體算法:

as

舉例如上,隨機事件出現的概率依次是1/2,1/3,1/12,1/12;記隨機事件的個數為N,則所有事件概率乘以N后概率為2,4/3,1/3,1/3;

記隊列small,large分別存放小於1和大於1的事件下標(例子中small=[0,1],large=[2,3]);

記accept存放第i列對應的事件i矩形的面積百分比;alias存放第i列不是事件i的另外一個事件的標號;

每次從small,large中各取一個,將大的補充到小的之中,小的出隊列,再看大的減去補給之后,如果大於1,繼續放入large中,如果等於1,則也出去,如果小於1則放入small中。

上例中accept=[2/3,1,1/3,1/3],alias=[1,0,1,1],這里alias[1]的0是默認值,也可默認置為-1避免和事件0沖突;以上部分在源碼create_alias_table函數中,時間復雜度是O(N);

隨機采樣1~N 之間的整數i,決定落在哪一列。隨機采樣0~1之間的一個概率值,如果小於accept[i],則采樣i,如果大於accept[i],則采樣alias[i];這一部分源碼在alias_sample;

下面附上具體的源碼:

import numpy as np
def create_alias_table(area_ratio):
    """
	area_ratio[i]代表事件i出現的概率
    :param area_ratio: sum(area_ratio)=1
    :return: accept,alias
    """
    N = len(area_ratio)
    accept, alias = [0] * N, [0] * N
    small, large = [], []
    area_ratio_ = np.array(area_ratio) * N
    for i, prob in enumerate(area_ratio_):
        if prob < 1.0:
            small.append(i)
        else:
            large.append(i)

    while small and large:
        small_idx, large_idx = small.pop(), large.pop()
        accept[small_idx] = area_ratio_[small_idx]
        alias[small_idx] = large_idx
        area_ratio_[large_idx] = area_ratio_[large_idx] - \
            (1 - area_ratio_[small_idx])
        if area_ratio_[large_idx] < 1.0:
            small.append(large_idx)
        else:
            large.append(large_idx)

    while large:
        large_idx = large.pop()
        accept[large_idx] = 1
    while small:
        small_idx = small.pop()
        accept[small_idx] = 1

    return accept, alias


def alias_sample(accept, alias):
    """
	
    :param accept:
    :param alias:
    :return: sample index
    """
    N = len(accept)
    i = int(np.random.random()*N)
    r = np.random.random()
    if r < accept[i]:
        return i
    else:
        return alias[i]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM