python 偏りのある乱数分布発生

とあるコーディングで必要になったので、ご説明もかねて本記事作成してみました。

Pythonのライブラリ「Numpy」でRandomによって乱数を発生させることができることは、広く知られています。ただ、正規分布で左右の分布を偏らせることは、機能には無いようでした。

雑な方法

案外この世の中、雑にふるまっても誰も気づかないものです。テキトーに済ませたい場合は下記のコードで実現できます。関数bias_randomによって生成していて、下記コードの例ではユーザー入力のところに適当な値を記載すると、データの個数もしっかり5000が出ます。

import numpy as np
import matplotlib.pyplot as plt

def bias_random(avg:float , std:float ,weight:float, count:int):
    """    偏った乱数のリストを発生させる
    <Parameters>----------
    avg : 平均, std : 左右の標準偏差、リストで与えること, 
    weight : 左右の重み、リストで与えること, count : 発生させたい乱数の数
    <Returns>-------------
    dat : float  偏った乱数のリスト
    """
    # 乱数の配列を発生させる
    np.random.seed(10000)
    dat_left = np.random.normal(avg,std[0],round(1.1*count*weight[0])) 
    dat_right = np.random.normal(avg,std[1],round(1.1*count*weight[1]))

    dat = [i for i in dat_left if i <= avg]
    dat_right = [i for i in dat_right if i > avg]
    dat.extend(dat_right)
    dat = np.random.choice(a=dat, 
                            size=count)

    return dat

if __name__ == '__main__':

    # ユーザー入力-+-+-+-+-+-+-+-+-+-
    data_avg = 50
    data_std = [5, 10] #left, right
    dat_count = 5000
    dat_weight = [0.2, 0.8] #left, right
    # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

    dat = bias_random(data_avg, data_std, dat_weight, dat_count)

    plt.rcParams['axes.axisbelow'] = True # gridを最背面にする記述
    plt.grid()

    plt.hist(dat, bins = 100)

    # 描画
    plt.title('data count:' + str(len(dat)))
    plt.xlabel('bin'); plt.ylabel('count')
    # bboxの作成
    boxdic = {
        "facecolor" : "white",
        "edgecolor" : "black",
        "boxstyle" : "Round",
        "linewidth" : 0.1
    }
    # Axesにテキストを追加
    plt.text(70, 80, # ← w=70, h=80なのでavgなどの値によって変更必要
            "data weight\nleft : " + str(dat_weight[0]) 
                    + "\nright : " + str(dat_weight[1])
    , size=10, bbox=boxdic)

    plt.savefig("./img.png") 

ただ、この方法だと強引に左右のデータを結合するので平均値の境目が急激に変化していしまうことがあります。(複数回実行するといい感じの分布も出力されます。その際にseed値を変更することはお忘れなきよう)

コメント

タイトルとURLをコピーしました