NumPyで陰二項分布乱数を生成:random_negative_binomial() 関数徹底解説


P(k) = (n + k - 1)! / (k! * (n - 1)!) * p^(k) * (1 - p)^(n - k)

ここで、

  • p は成功確率
  • n は試行回数
  • k は生成される非負の整数

この関数は、以下の引数を取ります。

  • size: 生成される乱数の数。size は None または 1 以上の実数である必要があります。
  • p: 成功確率。p は 0 と 1 の間の値である必要があります。
  • n: 試行回数。n は正の整数である必要があります。

この関数は、npy_int64 型の NumPy 配列を返します。配列の各要素は、陰二項分布からサンプリングされた非負の整数です。

import numpy as np

# 試行回数と成功確率を設定
n = 10
p = 0.2

# 陰二項分布から10個の乱数を生成
random_numbers = np.random.negative_binomial(n, p, size=10)

# 乱数を表示
print(random_numbers)

このコードは、10 回の試行で成功確率が 0.2 の陰二項分布から 10 個の乱数を生成し、それらをコンソールに表示します。

関数の動作

random_negative_binomial() 関数は、以下のアルゴリズムを使用して陰二項分布から乱数を生成します。

  1. まず、ポアソン分布から n 個の乱数を生成します。
  2. 次に、生成されたポアソン乱数の合計が n になるまで、ランダムに 1 つの乱数を選択します。
  3. 選択された乱数の数は、陰二項分布からの乱数となります。
  • size は None または 1 以上の実数である必要があります。
  • p は 0 と 1 の間の値である必要があります。
  • n は正の整数である必要があります。


特定の試行回数と成功確率でのサンプリング

import numpy as np

# 試行回数と成功確率を設定
n = 10
p = 0.2

# 陰二項分布から10個の乱数を生成
random_numbers = np.random.negative_binomial(n, p, size=10)

# 乱数を表示
print(random_numbers)

異なる試行回数と成功確率でのサンプリング

import numpy as np

# 試行回数と成功確率のリストを作成
n_list = [5, 15, 20]
p_list = [0.3, 0.1, 0.4]

# 各試行回数と成功確率に対して陰二項分布から乱数を生成
for n, p in zip(n_list, p_list):
  random_numbers = np.random.negative_binomial(n, p, size=10)
  print(f"n = {n}, p = {p}:")
  print(random_numbers)

このコードは、n_listp_list に設定された異なる試行回数と成功確率に対して、陰二項分布から乱数を生成します。各試行回数と成功確率ごとの乱数は、コンソールに表示されます。

特定のサイズの配列を生成

import numpy as np

# 試行回数と成功確率を設定
n = 15
p = 0.2

# サイズ100の陰二項分布乱数配列を生成
random_numbers = np.random.negative_binomial(n, p, size=100)

# 乱数の統計量を表示
print(random_numbers.mean())
print(random_numbers.var())

このコードは、15 回の試行で成功確率が 0.2 の陰二項分布からサイズ 100 の乱数配列を生成します。その後、この配列の平均値と分散を表示します。

import numpy as np

# 試行回数と成功確率を設定
n = 10
p = 0.2

# シード値を設定
np.random.seed(123)

# 陰二項分布から10個の乱数を生成
random_numbers = np.random.negative_binomial(n, p, size=10)

# 乱数を表示
print(random_numbers)

# シード値を同じにして再度生成
np.random.seed(123)
random_numbers2 = np.random.negative_binomial(n, p, size=10)

# 2回目の生成結果を表示
print(random_numbers2)

このコードは、np.random.seed() を使用してシード値を設定し、陰二項分布から乱数を生成します。同じシード値を使用すると、毎回同じ乱数が生成されることが確認できます。



ポアソン分布と二項分布の組み合わせ

陰二項分布は、ポアソン分布と二項分布を組み合わせることで生成することができます。この方法は、以下の手順で行います。

  1. ポアソン分布から n 個の乱数を生成します。
  2. 生成されたポアソン乱数の合計が n になるまで、ランダムに 1 つの乱数を選択します。
  3. 選択された乱数の数は、陰二項分布からの乱数となります。

この方法は、比較的単純で高速ですが、精度が低くなる場合があります。

import numpy as np

def negative_binomial_alt(n, p):
  """
  ポアソン分布と二項分布の組み合わせを使用して陰二項分布から乱数を生成します。

  Args:
    n: 試行回数
    p: 成功確率

  Returns:
    陰二項分布からの乱数
  """
  while True:
    # ポアソン分布からn個の乱数を生成
    poisson_numbers = np.random.poisson(n * p)

    # 生成されたポアソン乱数の合計がnになるまでループ
    if sum(poisson_numbers) == n:
      # 成功数をカウント
      success_count = 0
      for num in poisson_numbers:
        if num > 0:
          success_count += 1

      # 成功数を返す
      return success_count

# 試行回数と成功確率を設定
n = 10
p = 0.2

# 陰二項分布から10個の乱数を生成
random_numbers = [negative_binomial_alt(n, p) for _ in range(10)]

# 乱数を表示
print(random_numbers)

陰二項分布は、ガンマ分布とポアソン分布を組み合わせることで生成することもできます。この方法は、以下の手順で行います。

  1. ガンマ分布から r 個の乱数を生成します。
  2. ポアソン分布から n 個の乱数を生成します。
  3. 生成されたガンマ乱数の合計を r 倍します。
  4. 生成されたポアソン乱数の各要素を、3 で生成された値で割ります。
  5. 生成されたポアソン乱数の各要素を丸めます。
  6. 丸めた値の合計を k とします。
  7. k は、陰二項分布からの乱数となります。

この方法は、精度が高く、より複雑な陰二項分布のモデル化にも使用できますが、計算コストが高くなります。

import numpy as np

def negative_binomial_alt2(n, p):
  """
  ガンマ分布とポアソン分布の組み合わせを使用して陰二項分布から乱数を生成します。

  Args:
    n: 試行回数
    p: 成功確率

  Returns:
    陰二項分布からの乱数
  """
  while True:
    # ガンマ分布からr個の乱数を生成
    gamma_numbers = np.random.gamma(1 / p, n * p)

    # ポアソン分布からn個の乱数を生成
    poisson_numbers = np.random.poisson(n)

    # 生成されたガンマ乱数の合計をr倍する
    scaled_gamma_numbers = gamma_numbers * r

    # 生成されたポアソン乱数の各要素を3で割る
    scaled_poisson_numbers = poisson_numbers / scaled_gamma_numbers

    # 生成されたポアソン乱数の各要素を丸める
    rounded_numbers = np.round(scaled_poisson_numbers)

    # 丸めた値の合計をkとする
    k = int(sum(rounded_numbers))

    # kは、陰二項分布からの乱数となる
    return k

# 試行回数と成功確率を設定
n = 10
p = 0.2

# 陰二項分布から10個の乱数を生成
random_numbers = [negative_binomial_alt2(n, p) for _ in range(10)]

# 乱数を表示
print(random_