'22/03/12更新:自然な分布になる雛形コードも追記しました。
本記事では、例えば複数のパラメータA, B, Cの3つがあって、それらの和が一定値Sの制約条件の元に、整数の乱数を作成する雛形コードを載せました。
下図は、S=150と指定して2000水準作成した例です。生成したデータはcsvファイルに出力する仕様です。

▼1. 各要素の生成する乱数の範囲を確率で決定する場合
下図のように、A, B, Cの分布はおよそ同じ分布で生成されます。和が一定の場合はこれが自然な分布と想像できます。

import numpy as np
import random
import math
import pandas as pd
parameter_name_list = ['A', 'B', 'C']
S = 150
N = 2000
data_list = []
i = 0
while i < N:
flag_A = np.random.choice(['low', 'center', 'high'], p=[1/3, 1/3, 1/3])
if flag_A == 'low':
A = np.random.randint(0, S / 3)
elif flag_A == 'center':
A = random.randint(S / 3, S / 3 * 2)
else:
A = random.randint(S / 3 * 2, S)
if S == A or A == 0:
continue
else:
flag_B = np.random.choice(['low', 'center', 'high'], p=[1/3, 1/3, 1/3])
if flag_B == 'low':
B = np.random.randint(0, math.ceil((S) / 3))
elif flag_B == 'center':
B = np.random.randint(math.ceil((S) / 3), math.ceil((S) / 3) * 2)
else:
B = random.randint(math.ceil((S) / 3) * 2, (S))
if A + B > S or B == 0:
continue
else:
C = S - (A + B)
i = i + 1
data_list.append([A, B, C])
df = pd.DataFrame(data_list, columns=parameter_name_list)
df['sum'] = df['A'] + df['B'] + df['C']
df.index = np.arange(1, len(df) + 1)
df.to_csv('data1.csv', index=True)
df
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(6,6))
ax = fig.gca()
df.hist(ax = ax)
plt.tight_layout()
▼2. 各要素の生成する乱数の範囲をある程度指定する場合
下図のように、Aは正規分布に近いといった分布を恣意的に作成できます。当然ですが、和が一定のためにBとCはそれにならった分布になります。
A
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
parameter_name_list = ['A', 'B', 'C']
S = 150
N = 2000
rng = np.random.default_rng(1)
rng
parameter_A = rng.integers(15, 85, size=N)
parameter_A
parameter_B = rng.integers(20, 55, size=N)
parameter_B
parameter_C = rng.integers(15, 35, size=N)
parameter_C
np_list = [parameter_A, parameter_B, parameter_C]
param_arr = np.vstack(np_list).T
param_arr
arr = param_arr * S / param_arr.sum(axis=1)[:, np.newaxis]
arr
arr.sum(axis=1)
arr2 = np.floor(arr)
arr2
df = pd.DataFrame(arr2, columns=parameter_name_list)
df
df['sum'] = df.sum(axis=1)
df
df2 = df.copy()
df2[parameter_name_list[-1]] = df[parameter_name_list[-1]] + (S - df['sum'])
df3 = df2.drop(['sum'], axis=1)
df3['sum'] = df3.sum(axis=1)
df3
df3.to_csv('data2.csv', index=False)
fig = plt.figure(figsize=(6,8))
ax = fig.gca()
df3.hist(ax = ax)
plt.tight_layout()
以上
<広告>
リンク