如何對任意分佈採樣?

給定任意分佈

import random

N = 30
samples = [i for i in range(N)]
weights = [random.random() for i in range(N)]

如有 30 個樣本和每個樣本對應的權重,可視化如下:

plt.figure(figsize=(20,10))
rects = plt.bar(x=samples, height=weights, width=0.4, alpha=0.8, color='red', label="權重")

# 在每個條上標註數量
for rect in rects:
    height = rect.get_height()
    plt.text(rect.get_x() + rect.get_width() / 2, height+0.01, str(int(height*100)/100), ha="center", va="bottom")

plt.ylim(0,1.1*max(weights))
plt.xticks(samples)
plt.xlabel('類別')
plt.ylabel('權重')
plt.legend()
plt.show()

在這裏插入圖片描述

plt.figure(figsize=(10,10))
plt.pie(weights,
        labels=range(N),
        autopct='',
        shadow=False,
        startangle=0)
plt.axis('equal')
plt.show()

在這裏插入圖片描述
注意到上面的分佈甚至沒有進行歸一化,即所有權值的和不等於1。

那麼有什麼辦法可以對上述分佈進行採樣呢?比如需要獲得 1000 個新樣本,樣本數量服從上面的任意分佈。

下面就來介紹採樣方法!

其實這個方法大家都見過,就是輪盤賭

任意離散分佈都可以畫在輪盤上,重採樣只需要隨機地旋轉輪盤即可!

def sample(weights, labels, N_new = None):
    if N_new is None:
        N_new = len(labels)
    
    N = len(labels)
    p = []
    index = int(random.random() * N)
    beta = 0.0  # 輪盤指針
    mw = max(weights)
    for _ in range(N_new):
        beta += random.random() * 2.0 * mw
        while beta > weights[index]:
            beta -= weights[index]
            index = (index + 1) % N
        p.append(labels[index])
    
    return p

下面用上面的函數進行1000輪重採樣:

samples = resample(weights, list(set(samples)),1000)
weights = [np.sum(np.array(samples)==i) for i in range(N)]

結果如下:
在這裏插入圖片描述
在這裏插入圖片描述
是不是和預期的分佈是一致的!

現在,你也學會採樣了吧!

上面的採樣函數也可以用如下方式實現,原理是一樣的!

def sample(weights, labels, N_new = None):
    assert(len(weights)==len(labels))
    
    if N_new is None:
        N_new = len(labels)
    
    N = len(labels)
    p = []
    cs = np.cumsum(weights)  # 累計求和函數
    
    for _ in range(N_new):
        angle = random.random() * cs[-1]  # 隨機轉動一個角度
        for i in range(len(labels)):
            if angle > cs[i]:  # 轉過第 i 項
                continue
            else:  # 恰好落在第 i 項
                p.append(labels[i])
                break
    assert(N_new == len(p))
    return p

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章