randi関数徹底解説:Matlabで思い通りの乱数を生成する方法


rand関数徹底解説:MATLABで思い通りの乱数を生成する方法

はじめに

数値シミュレーション、統計モデリング、機械学習、ゲーム開発など、様々な分野で乱数は不可欠な要素です。実験の再現性を確保するため、あるいは逆に多様なシナリオを探求するために、特定の特性を持つ乱数を正確に生成する能力は、MATLABユーザーにとって非常に重要になります。

MATLABには、乱数を生成するための強力で多様なツールが用意されています。最も基本的な関数はrandですが、これだけでは不十分な場合がほとんどです。正規分布に従う乱数、指定した範囲の整数、特定の統計分布に従う乱数、あるいは既存のデータセットからの無作為抽出など、必要とされる「乱数」の性質は多岐にわたります。さらに、生成される乱数の列を制御し、実験の再現性を確保することも、しばしば求められる要件です。

この記事では、MATLABで乱数を生成するための主要な関数群を徹底的に解説します。単に乱数を生成するだけでなく、どのようにすれば「思い通りの」、つまり特定の性質を持つ乱数を生成できるのか、そのための方法論とテクニックを、豊富なコード例を交えながら詳細に説明します。

この記事を読むことで、以下のことができるようになります。

  • MATLABの基本的な乱数関数(rand, randn, randi)を使いこなす。
  • 指定した範囲、平均、分散など、特定のパラメータを持つ乱数を生成する。
  • 様々な統計分布(指数分布、ポアソン分布、ベータ分布など)に従う乱数を生成する。
  • 乱数生成のシードを制御し、結果の再現性を確保する。
  • 既存のデータから無作為にサンプルを抽出する。
  • 乱数生成に関するベストプラクティスと注意点を理解する。

それでは、MATLABの乱数生成の世界へ深く踏み込んでいきましょう。

1. 最も基本となる関数:rand (一様分布)

rand関数は、MATLABで最も基本的な乱数生成関数です。デフォルトでは、0から1の間の連続一様分布に従う乱数を生成します。これは、区間 [0, 1) 内のどの値も等しい確率で出現するという意味です。

rand関数は、引数の指定によって、様々なサイズの乱数配列を生成できます。

  • rand(): 1×1のスカラー乱数(1個の乱数)を生成します。
    matlab
    r = rand();
    disp(r); % 0から1の間の単一の乱数が表示されます
  • rand(n): nxnの正方行列を生成します。
    matlab
    R_square = rand(3); % 3x3の行列
    disp(R_square);
  • rand(m, n): mxnの行列を生成します。
    matlab
    R_rect = rand(2, 4); % 2x4の行列
    disp(R_rect);
  • rand([m n]): mxnの行列を生成します。rand(m, n)と同じですが、次元をベクトルで指定します。これは次元数が変数になっている場合に便利です。
    matlab
    dims = [5, 2];
    R_dims = rand(dims); % 5x2の行列
    disp(R_dims);
  • rand(d1, d2, d3, ...): d1 x d2 x d3 x … の多次元配列を生成します。
    matlab
    R_3d = rand(2, 3, 4); % 2x3x4の3次元配列
    disp(R_3d);
  • rand(size(A)): 既存の配列Aと同じサイズの乱数配列を生成します。
    matlab
    A = magic(3);
    R_same_size = rand(size(A)); % 3x3の行列
    disp(R_same_size);

データ型:

デフォルトでは、randdouble型の乱数を生成します。single型の乱数を生成したい場合は、型を引数で指定します。

matlab
R_single = rand(3, 3, 'single'); % single型の3x3行列
disp(class(R_single)); % 'single'と表示されるはずです

1.1 randを使って指定した範囲の一様乱数を生成する

randは [0, 1) の一様乱数を生成しますが、多くの場合は [a, b) や [a, b] のように、他の範囲の一様乱数が必要になります。これは簡単な線形変換で実現できます。

区間 [a, b) の一様乱数 R_ab は、[0, 1) の一様乱数 R_01 を使って次のように計算できます。

R_ab = a + (b - a) * R_01

ここで、aは区間の下限、bは区間の上限です。b - a は区間の幅です。randが生成する乱数に幅をかけてスケーリングし、aを足してシフトしていると考えることができます。

例:区間 [10, 20) の一様乱数を 5×5 行列で生成する。

matlab
a = 10;
b = 20;
R_10_20 = a + (b - a) * rand(5, 5);
disp(R_10_20); % 各要素が10以上20未満の乱数になります

注意点: randが生成するのは [0, 1) の乱数です。数学的には上限bは含まれません。実際には浮動小数点数の精度のため、bに非常に近い値が出現する可能性はありますが、厳密にbと等しくなることは通常ありません。もし [a, b] のように上限を含む範囲が必要な場合は、特別な処理が必要になることがありますが、一般的なシミュレーションでは [a, b) で十分な場合が多いです。

2. 正規分布に従う乱数:randn

randが一様分布なのに対し、randn標準正規分布(平均 $\mu=0$、標準偏差 $\sigma=1$、または分散 $\sigma^2=1$ の正規分布)に従う乱数を生成します。正規分布は、自然界や社会現象で頻繁に現れる非常に重要な確率分布です。

randn関数の使い方はrandと非常によく似ています。引数の指定方法はrandとほぼ同じです。

  • randn(): 1×1のスカラー乱数(標準正規分布)
  • randn(n): nxn行列(標準正規分布)
  • randn(m, n): mxn行列(標準正規分布)
  • randn([m n]): mxn行列(標準正規分布)
  • randn(d1, d2, ...): 多次元配列(標準正規分布)
  • randn(size(A)): Aと同じサイズ(標準正規分布)

例:標準正規分布に従う乱数を 2×3 行列で生成する。

matlab
R_normal_std = randn(2, 3);
disp(R_normal_std); % 平均0、標準偏差1の正規分布に従う乱数

2.1 randnを使って指定した平均と分散を持つ正規乱数を生成する

標準正規分布(平均0、標準偏差1)の乱数 R_std_normal を使って、任意の平均 $\mu$ と標準偏差 $\sigma$ を持つ正規分布の乱数 R_mu_sigma を生成するには、以下の線形変換を行います。

R_mu_sigma = mu + sigma * R_std_normal

例:平均10、標準偏差2を持つ正規分布に従う乱数を 4×4 行列で生成する。

matlab
mu = 10; % 平均
sigma = 2; % 標準偏差 (分散は sigma^2 = 4)
R_custom_normal = mu + sigma * randn(4, 4);
disp(R_custom_normal); % 各要素が平均10、標準偏差2の正規分布に従う乱数になります

重要な注意点: 正規分布を指定する際、平均と「分散」または「標準偏差」のどちらを使うか混乱することがあります。randnからの変換では標準偏差sigmaを使います。もし分散varianceが分かっている場合は、sigma = sqrt(variance)として標準偏差を求めてから変換してください。mu + variance * randn(...)としてしまうと、標準偏差が分散になってしまう誤りとなるので注意が必要です。

3. 整数乱数を生成する:randi

randrandnが連続値の乱数を生成するのに対し、randi整数の乱数を生成します。これは、サイコロの目やカードの選択、離散的なイベントのシミュレーションなどで非常に役立ちます。

randi関数は、生成したい整数の範囲を指定します。範囲は閉区間 [imin, imax] で指定され、下限iminと上限imaxの両方を含む可能性があります。

randi関数の主な使い方:

  • randi(imax): 1からimaxまでの整数の乱数(閉区間 [1, imax])を1個生成します。
    matlab
    die_roll = randi(6); % 1から6までの整数の乱数
    disp(die_roll);
  • randi(imax, n): 1からimaxまでの整数の乱数を含む nxn の正方行列を生成します。
    matlab
    R_int_square = randi(10, 3); % 1から10までの整数を含む3x3行列
    disp(R_int_square);
  • randi(imax, m, n): 1からimaxまでの整数の乱数を含む mxn の行列を生成します。
    matlab
    R_int_rect = randi(100, 2, 5); % 1から100までの整数を含む2x5行列
    disp(R_int_rect);
  • randi([imin, imax]): iminからimaxまでの整数の乱数(閉区間 [imin, imax])を1個生成します。
    matlab
    card_value = randi([1, 13]); % 1から13までの整数の乱数
    disp(card_value);
  • randi([imin, imax], dimensions): iminからimaxまでの整数の乱数を含む、指定した次元dimensionsの配列を生成します。dimensionsはスカラー(正方)またはベクトルで指定できます。
    matlab
    R_int_range_matrix = randi([-5, 5], 4, 4); % -5から5までの整数を含む4x4行列
    disp(R_int_range_matrix);

注意点: 整数乱数が必要な場合に、floor(imin + (imax - imin + 1) * rand())のような方法を使うことも原理的には可能ですが、randi関数を使用する方が意図が明確で、浮動小数点数の精度問題や端数処理によるバイアスを避けられるため推奨されます。特に [imin, imax] のように両端を含む範囲が必要な場合、手計算では + 1 の扱いでミスしやすいため、randi([imin, imax], ...) を使うのが最も安全です。

4. 乱数生成の再現性と制御:rng

シミュレーションや統計分析を行う上で、全く同じ乱数の列を再度生成したい場合があります。これは、アルゴリズムのデバッグ、異なる手法の比較、あるいは結果の検証に不可欠です。MATLABの乱数関数(rand, randn, randiなど)は、実際には真の乱数ではなく、「擬似乱数」を生成しています。擬似乱数は、初期状態(シードと呼ばれる)に基づいて決定論的なアルゴリズムによって生成される、統計的には乱数のように見える数列です。

この擬似乱数生成器の状態を制御するのがrng関数です。rngを使うことで、乱数生成の出発点(シード)を指定したり、乱数生成器の種類を変更したり、現在の状態を保存・復元したりすることができます。

rng関数の主な使い方:

  • rng(seed): 指定した非負の整数seedを使って、乱数生成器の状態を初期化します。同じseedを使えば、常に同じ乱数列が得られます。
    “`matlab
    rng(123); % シードを123に設定
    r1 = rand(1, 5);
    disp(r1);

    rng(123); % 再度シードを123に設定
    r2 = rand(1, 5);
    disp(r2); % r1とr2は全く同じ乱数の列になります

    rng(456); % 異なるシードを設定
    r3 = rand(1, 5);
    disp(r3); % r3はr1/r2とは異なる乱数の列になります
    * `rng('shuffle')`: 現在の時刻に基づいて乱数生成器の状態を初期化します。これにより、実行するたびに異なる乱数列が得られます。実験ごとに異なるランダムな結果を得たい場合に便利です。matlab
    rng(‘shuffle’); % 現在時刻でシードを設定
    r_shuffled1 = rand(1, 5);
    disp(r_shuffled1);

    % 少し待って再度実行するか、別のMATLABセッションで実行すると、
    % r_shuffled2はr_shuffled1とは異なる乱数列になります
    rng(‘shuffle’);
    r_shuffled2 = rand(1, 5);
    disp(r_shuffled2);
    * `rng('default')`: MATLABの起動時に設定されるデフォルトの状態に乱数生成器をリセットします。これは`rng(0, 'twister')`と等価です。matlab
    rng(‘default’); % デフォルト状態に戻す
    r_default = rand(1, 5);
    disp(r_default); % MATLABを起動して最初のrand()を実行したときと同じ乱数列になります
    * `s = rng`: 現在の乱数生成器の状態を取得し、構造体`s`に保存します。
    * `rng(s)`: previously saved state`s`を使って乱数生成器の状態を復元します。これは、特定の時点からの乱数列を正確に再現したい場合に非常に便利です。
    matlab
    rng(‘shuffle’); % 時刻で初期化
    state1 = rng; % 現在の状態を保存
    r_part1 = rand(1, 5);
    disp(r_part1);

    % ここで別の乱数生成を行うなど、状態が変化する処理を挟む
    rand(1, 2);

    rng(state1); % state1の状態に復元
    r_part2 = rand(1, 5);
    disp(r_part2); % state1保存時点から生成される乱数列が再開されるため、r_part2はr_part1と全く同じ乱数列になります
    * `rng(seed, generator)`: 指定したシードと、指定した種類の乱数生成アルゴリズム(ジェネレータ)を使って状態を初期化します。ジェネレータの種類には、`'twister'` (Mersenne Twister, デフォルト)、`'combRecursive'`、`'multFibonacci'`、`'philox'`、`'threefry'` などがあります。通常はデフォルトの`'twister'`で問題ありませんが、特定の要件(例:並列計算での独立したストリーム)に応じて変更することがあります。matlab
    rng(1, ‘combRecursive’); % シード1とcombRecursiveジェネレータを使用
    r_gen = rand(1, 5);
    disp(r_gen);
    “`

ベストプラクティス:

  • 再現性が必要な場合: スクリプトや関数の冒頭でrng(seed)を使ってシードを明示的に設定してください。これにより、何度実行しても同じ結果が得られます。デバッグや論文発表などで結果を固定したい場合に必須です。
  • 毎回異なる結果が必要な場合: シミュレーションのバリエーションを増やしたい場合などは、rng('shuffle')を使用します。ただし、'shuffle'は実行環境の時刻に依存するため、厳密な再現性は保証されません(同じマシンでミリ秒単位まで同じ時刻に実行すれば同じになる可能性はありますが、現実的ではありません)。
  • 状態の保存と復元: 長いシミュレーションの中で特定のチェックポイントから乱数列を再開したい場合は、s = rng; で状態を保存し、必要に応じて rng(s); で復元します。

非推奨の古い構文: rand('seed', seed_value) または rand('state', state_value) は古いMATLABバージョンで使用されていましたが、rng関数に置き換えられました。これらの古い構文は推奨されず、将来的に削除される可能性があるため、新しいコードではrngを使用してください。

5. 特定の確率分布に従う乱数を生成する:random

randが一様分布、randnが正規分布、randiが指定範囲の整数乱数と、基本的な分布に対応する関数はありますが、世の中にはこれら以外の様々な確率分布が存在します(指数分布、ポアソン分布、ベータ分布、ガンマ分布、ワイブル分布など)。統計モデリングや特定の確率現象のシミュレーションでは、これらの分布に従う乱数が必要になります。

MATLABのStatistics and Machine Learning Toolbox(もしインストールされていれば)には、randomという非常に汎用的な関数があります。この関数は、様々な統計分布から乱数を生成することができます。

random関数の一般的な構文は以下の通りです。

R = random(distname, param1, param2, ..., paramN, dimensions)

  • distname: 生成したい確率分布の名前を指定する文字列(例: 'Exponential', 'Poisson', 'Normal', 'Beta', 'Gamma', 'Weibull', 'Binomial', 'Uniform', 'Discrete Uniform' など)。
  • param1, param2, ..., paramN: 選択した分布のパラメータを指定します。必要なパラメータの数は分布によって異なります。例えば、指数分布はrateパラメータ、正規分布は平均と標準偏差、ベータ分布はアルファとベータパラメータが必要です。これらのパラメータはスカラーまたは配列で指定できます。
  • dimensions: 生成したい乱数配列のサイズを指定します。m, [m, n], [d1, d2, ...] など、randrandnと同じ形式で指定できます。パラメータが配列の場合、dimensionsを省略すると、パラメータ配列と同じサイズの乱数配列が生成されます。

5.1 random関数の具体的な使用例

いくつかの一般的な分布の例を見てみましょう。

例1:指数分布 (Exponential Distribution)

指数分布は、ポアソン過程におけるイベント間の待ち時間などをモデル化するのに使われます。パラメータはrate ($\lambda$) または mean ($1/\lambda$) で指定されます。randomでは通常 mean (または parameter mu) で指定します。

“`matlab
% 平均 mu=3 の指数分布に従う乱数を 10個生成
mu = 3;
R_exp = random(‘Exponential’, mu, 1, 10); % 1×10ベクトル
disp(R_exp);

% 平均 mu=10 の指数分布に従う乱数を 3×3 行列で生成
mu_matrix = 10 * ones(3, 3); % パラメータを配列で指定
R_exp_matrix = random(‘Exponential’, mu_matrix); % 次元指定を省略するとパラメータ配列と同じサイズ
disp(R_exp_matrix);

% あるいは次元を明示的に指定
R_exp_matrix_dims = random(‘Exponential’, 10, 3, 3);
disp(R_exp_matrix_dims);
“`

例2:ポアソン分布 (Poisson Distribution)

ポアソン分布は、一定期間内に発生する稀なイベントの数などをモデル化するのに使われます。パラメータは平均 ($\lambda$) で指定されます。生成される乱数は非負の整数になります。

“`matlab
% 平均 lambda=2 のポアソン分布に従う乱数を 15個生成
lambda = 2;
R_poisson = random(‘Poisson’, lambda, 1, 15); % 1×15ベクトル (非負整数)
disp(R_poisson);

% 平均 lambda=5 のポアソン分布に従う乱数を 2×4 行列で生成
R_poisson_matrix = random(‘Poisson’, 5, 2, 4); % 2×4行列 (非負整数)
disp(R_poisson_matrix);
“`

例3:ベータ分布 (Beta Distribution)

ベータ分布は、[0, 1] の区間内の連続値をモデル化するのに使われます。確率や割合などを表現するのに適しており、統計的推論(特にベイズ統計)でよく使用されます。パラメータは $\alpha$ と $\beta$ です。

“`matlab
% パラメータ alpha=0.5, beta=0.5 のベータ分布に従う乱数を 1×8個生成
alpha = 0.5;
beta = 0.5;
R_beta = random(‘Beta’, alpha, beta, 1, 8); % 1×8ベクトル (0から1の値)
disp(R_beta);

% パラメータ alpha=5, beta=1 のベータ分布に従う乱数を 3×2 行列で生成 (モードが1に近い分布)
R_beta_matrix = random(‘Beta’, 5, 1, 3, 2);
disp(R_beta_matrix);
“`

例4:離散一様分布 (Discrete Uniform Distribution)

これはrandi([imin, imax], ...)と同じ機能をrandomで実現する方法です。randiの方が直接的で推奨されますが、randomの枠組みで統一したい場合に使うこともできます。

“`matlab
% 1から6までの離散一様分布に従う乱数を 1×5個生成
imin = 1;
imax = 6;
R_discrete_uniform = random(‘Discrete Uniform’, imin, imax, 1, 5); % 1から6までの整数
disp(R_discrete_uniform);

% これは randi([1, 6], 1, 5) と同じです。
“`

5.2 サポートされている主な分布

random関数でサポートされている主な分布(distname文字列)の一部を以下に挙げます。

  • 連続分布:

    • 'Normal' (正規分布) – パラメータ: mean, standard deviation
    • 'Uniform' (連続一様分布 [a, b]) – パラメータ: a, b (rand相当の [0, 1) は a=0, b=1)
    • 'Exponential' (指数分布) – パラメータ: mean
    • 'Gamma' (ガンマ分布) – パラメータ: shape (A), scale (B)
    • 'Beta' (ベータ分布) – パラメータ: alpha (A), beta (B)
    • 'Lognormal' (対数正規分布) – パラメータ: mu (log mean), sigma (log std dev)
    • 'Weibull' (ワイブル分布) – パラメータ: scale (A), shape (B)
    • 'Rayleigh' (レイリー分布) – パラメータ: scale (B)
    • 't' (スチューデントのt分布) – パラメータ: degrees of freedom (NU)
    • 'F' (F分布) – パラメータ: numerator df (NU1), denominator df (NU2)
    • 'Chisquare' (カイ二乗分布) – パラメータ: degrees of freedom (NU)
    • 'BirnbaumSaunders' (バーンバウム・サンダース分布) – パラメータ: shape (BETA), scale (DELTA)
    • 'Extreme Value' (極値分布) – パラメータ: location (MU), scale (SIGMA)
    • 'Logistic' (ロジスティック分布) – パラメータ: location (MU), scale (SIGMA)
    • 'Pareto' (パレート分布) – パラメータ: shape (B), scale (A)
  • 離散分布:

    • 'Poisson' (ポアソン分布) – パラメータ: lambda (mean)
    • 'Binomial' (二項分布) – パラメータ: number of trials (N), probability of success (P)
    • 'Geometric' (幾何分布) – パラメータ: probability of success (P)
    • 'Hypergeometric' (超幾何分布) – パラメータ: population size (M), number of successes in population (K), sample size (N)
    • 'Negative Binomial' (負の二項分布) – パラメータ: number of successes (R), probability of success (P)
    • 'Discrete Uniform' (離散一様分布) – パラメータ: imin, imax (randi相当)
    • 'Multinomial' (多項分布) – パラメータ: number of trials (N), probabilities of each outcome (P)
    • 'Multivariate Normal' (多変量正規分布) – パラメータ: mean vector (MU), covariance matrix (SIGMA) – これは少し特殊で、他の分布とはパラメータの渡し方が異なります。mvnrnd関数を使用するのが一般的です。

これらの分布のパラメータの定義や意味については、MATLABのドキュメンテーション(doc randomや各分布名のドキュメンテーション、例: doc Exponential Distribution)を参照してください。

random関数は、これらの多様な分布から直接乱数を生成できるため、「思い通りの乱数」を生成するための非常に強力なツールとなります。

6. 既存のデータからの無作為抽出:randsample

シミュレーションや統計分析では、単に確率分布から乱数を生成するだけでなく、既存の有限のデータセットや母集団から、無作為に要素を選択(サンプリング)したい場合があります。このような用途にはrandsample関数が適しています。

randsample関数は、指定した母集団から、指定した個数のサンプルを、重複を許すか許さないかを指定して抽出できます。さらに、各要素が抽出される確率に重みを付けることも可能です。

randsample関数の主な構文:

  • y = randsample(population, k): 母集団populationから、重複を許さずに(非復元抽出)、k個のサンプルを無作為に抽出します。populationは要素のリスト(数値ベクトル、文字列配列、セル配列など)または正の整数nを指定できます。nを指定した場合、母集団は1:nとして扱われます。
    “`matlab
    % 1から10までの整数から重複なしで5個抽出
    samples1 = randsample(10, 5);
    disp(samples1); % 例: 8 2 9 1 6 (毎回異なります)

    % 文字のリストから重複なしで3個抽出
    letters = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’];
    sample_letters = randsample(letters, 3);
    disp(sample_letters); % 例: d a c
    * `y = randsample(population, k, replacement)`: `replacement`引数で重複を許すかどうか(復元抽出か非復元抽出か)を指定します。`replacement`は論理値 (`true`または`false`) です。`true`なら復元抽出、`false`なら非復元抽出です(デフォルトは`false`)。matlab
    % 1から10までの整数から重複を許して5個抽出
    samples_with_rep = randsample(10, 5, true);
    disp(samples_with_rep); % 例: 7 3 7 10 3 (重複が出現する可能性がある)

    % 非復元抽出 (上記と同じ)
    samples_without_rep = randsample(10, 5, false);
    disp(samples_without_rep); % 重複は出現しません
    * `y = randsample(population, k, replacement, weights)`: 各要素が抽出される確率に**重み**を付けます。`weights`は`population`と同じ長さのベクトルで、対応する要素の相対的な抽出確率を指定します。重みの合計は1である必要はありません。`weights`に負の値やNaNを含めることはできません。matlab
    % 1から6までの整数(サイコロの目)から1個抽出、特定の目(例: 6)が出やすいように重みを付ける
    outcomes = 1:6;
    weights = [1 1 1 1 1 5]; % 6が出る確率を他の目の5倍にする (重みの合計は10)
    weighted_roll = randsample(outcomes, 1, true, weights); % 復元抽出で1個
    disp(weighted_roll); % 6が出やすい
    ``
    重み付きサンプリングは通常、復元抽出 (
    replacement = true`) で行われます。非復元抽出で重みを使用する場合、抽出されるたびに母集団と重みが変化するため、最初の選択にのみ指定された重みが厳密に適用され、以降の選択は残りの要素と重みに基づいて行われます。

注意点: randsample(n, k)(母集団が 1:nの場合)で非復元抽出を行う場合、knを超えることはできません。k=nの場合は、1:nのランダムな順列(パーミュテーション)が生成されます。これはrandperm(n)関数と同じ機能です。

“`matlab
% 1から5までのランダムな順列を生成
permutation1 = randsample(5, 5, false);
disp(permutation1); % 例: 3 1 5 2 4

% これは randperm(5) と同じです。
permutation2 = randperm(5);
disp(permutation2);
“`

randsampleは、データセットからのブートストラップサンプリング、クロスバリデーションのためのデータ分割、あるいは特定の条件を満たすサンプルを生成する(重み付けを使うなど)場合に非常に便利な関数です。

7. 乱数生成の高度な側面:ジェネレータの種類とRandStream

前述のrng(seed, generator)構文で触れたように、MATLABは複数の乱数生成アルゴリズム(ジェネレータ)をサポートしています。デフォルトはMersenne Twister ('twister') です。

主なジェネレータの種類とその特徴:

  • 'twister' (Mersenne Twister): デフォルトのジェネレータ。非常に長い周期を持ち、多くの統計的検定に合格する高品質な乱数を生成します。多くの用途で推奨されます。
  • 'combRecursive' (Combined Multiple Recursive): 独立した並列ストリームを生成するのに適しています。Parallel Computing Toolboxなどで並列計算を行う際に、各ワーカーに独立した乱数列を割り当てたい場合などに使用されます。
  • 'multFibonacci' (Multiplicative Lagged Fibonacci): 古いジェネレータの一つ。’twister’ほど高品質ではありませんが、特定のレガシーコードで使用されている場合があります。
  • 'philox' / 'threefry' (Counter-based generators): よりモダンで、並列計算やGPU計算に適した特性を持つジェネレータです。

通常はデフォルトの'twister'で問題ありませんが、特定の並列計算環境や、乱数生成の性能や独立性に厳しい要件がある場合に、他のジェネレータを選択することがあります。

7.1 RandStreamオブジェクト

rng関数は、グローバルな乱数生成器の状態を制御します。MATLABは通常、このグローバルな状態を使って乱数を生成します。しかし、複数の独立した乱数列を同時に管理したい場合や、より細かく乱数生成を制御したい場合には、RandStreamオブジェクトを使用することができます。

RandStreamオブジェクトは、それぞれが独立した状態を持つ乱数生成器のインスタンスです。これにより、例えばシミュレーションの一部で特定の乱数列を使い、別の部分で全く独立した乱数列を使うといったことが容易になります。

“`matlab
% デフォルトのグローバルストリームで乱数生成
rng(0); % グローバルストリームのシードを0に設定
r_global1 = rand(1, 3);
disp([‘Global stream part 1: ‘, num2str(r_global1)]);

% 新しい独立したストリームを作成し、それを使って乱数生成
s1 = RandStream(‘twister’, ‘Seed’, 1); % シード1のMersenne Twisterストリーム
r_stream1 = rand(s1, 1, 3); % s1ストリームを使って乱数生成
disp([‘Stream 1: ‘, num2str(r_stream1)]);

% 別の新しい独立したストリームを作成し、それを使って乱数生成
s2 = RandStream(‘combRecursive’, ‘Seed’, 2); % シード2のcombRecursiveストリーム
r_stream2 = rand(s2, 1, 3); % s2ストリームを使って乱数生成
disp([‘Stream 2: ‘, num2str(r_stream2)]);

% グローバルストリームに戻って乱数生成 (s1, s2の生成によってグローバルストリームの状態は変化していない)
r_global2 = rand(1, 3);
disp([‘Global stream part 2: ‘, num2str(r_global2)]); % r_global1に続く乱数

% グローバルストリームの状態をリセット
rng(0);
r_global_reset = rand(1, 3);
disp([‘Global stream reset: ‘, num2str(r_global_reset)]); % r_global1と同じ乱数
“`

RandStreamオブジェクトを使うことで、並列計算での乱数列の管理や、複雑なシミュレーションで乱数の出所を明確にしたい場合に、コードの構造をきれいに保つことができます。しかし、多くの一般的な用途ではrng関数によるグローバルストリームの制御で十分です。

8. その他関連関数

MATLABには、乱数生成に関連するその他の便利な関数がいくつかあります。

  • randperm(n): 1からnまでの整数のランダムな順列(パーミュテーション)を生成します。これはrandsample(n, n, false)と同じですが、より直接的です。
    matlab
    p = randperm(7); % 1から7までのランダムな順列
    disp(p); % 例: 5 2 7 1 4 3 6
  • mvnrnd(MU, SIGMA, n): 多変量正規分布から乱数を生成します。平均ベクトルMUと共分散行列SIGMAを指定します。nは生成する乱数ベクトルの個数です。Statistics and Machine Learning Toolboxが必要です。
    matlab
    mu = [1, 2]; % 2次元の平均ベクトル
    Sigma = [1, 0.5; 0.5, 2]; % 2x2の共分散行列
    R_multinormal = mvnrnd(mu, Sigma, 10); % 10個の2次元ベクトルを生成
    disp(R_multinormal); % 10x2の行列になります
  • sprand(m, n, density): mxnの疎行列(ほとんどの要素が0の行列)を生成し、非ゼロ要素を [0, 1) の連続一様分布から取ります。densityは非ゼロ要素の割合(0から1)。
  • sprandn(m, n, density): mxnの疎行列を生成し、非ゼロ要素を標準正規分布から取ります。
  • sprandi(m, n, density, imax): mxnの疎行列を生成し、非ゼロ要素を [1, imax] の離散一様分布から取ります。または sprandi(m, n, density, [imin, imax])

これらの関数は、特定の構造を持つランダムなデータを生成する際に便利です。

9. よくある落とし穴とベストプラクティス

乱数生成を使う上で避けるべき落とし穴と、推奨される実践方法をまとめます。

  • 古い構文 rand('seed', ...) の使用: これは非推奨です。必ずrng関数を使用してください。
  • シード制御を怠る: 再現性が必要な実験やデバッグでは、必ずrng(seed)を使ってシードを明示的に設定してください。設定しないと、MATLABの起動時状態からの乱数列になり、セッションを跨いでの再現性が難しくなります。
  • randiが必要なのに floor(imin + (imax - imin + 1) * rand()) を使う: 整数乱数が必要な場合は、常にrandi([imin, imax], ...)を使用してください。変換による微細なバイアスや実装ミスを防げます。
  • 正規乱数のスケーリングミス: 平均 $\mu$ と分散 $v = \sigma^2$ が与えられた場合に、mu + v * randn(...)としてしまう誤りが多いです。正しくは標準偏差 $\sigma = \sqrt{v}$ を使ってmu + sqrt(v) * randn(...)またはmu + sigma * randn(...)とします。
  • ループ内での乱数生成 (非効率): 大量の乱数が必要な場合、ループを使って一つずつまたは小さな塊で生成するのは非効率です。MATLABは行列演算が得意なので、必要なサイズの乱数配列を一括で生成してください(例: rand(m, n))。
    “`matlab
    % 非推奨 (遅い)
    R = zeros(1000, 1000);
    for i = 1:1000
    for j = 1:1000
    R(i, j) = rand();
    end
    end

    % 推奨 (速い)
    R = rand(1000, 1000);
    ``
    * **複数の独立した乱数列を不用意に使う:** 意図せずにグローバルな乱数生成器の状態が他の関数呼び出しによって変更され、再現性が損なわれることがあります。複数の独立した乱数列を厳密に管理したい場合は、
    RandStream`オブジェクトの使用を検討してください。
    * 乱数の「質」を過信しない: 擬似乱数はあくまで「統計的に乱数のように見える」数列です。暗号学的な用途など、非常に高いレベルの予測不可能性が必要な場合には、MATLABの標準的な乱数生成器では不十分な場合があります。

10. まとめ

この記事では、MATLABで乱数を生成するための主要な関数とテクニックを詳細に解説しました。

  • 最も基本的な [0, 1) の連続一様乱数にはrandを使用し、簡単な変換で任意の範囲の一様乱数を生成できることを学びました。
  • 標準正規分布に従う乱数にはrandnを使用し、平均と標準偏差を指定して任意の正規分布に従う乱数を生成できることを学びました。
  • 指定した範囲の整数乱数にはrandiを使用するのが最も安全で推奨される方法であることを学びました。
  • シミュレーションの再現性を確保したり、実行ごとに異なる結果を得たりするために、rng関数を使って乱数生成器のシードと状態を制御する方法を学びました。
  • 指数分布、ポアソン分布、ベータ分布など、様々な統計分布に従う乱数を生成するには、Statistics and Machine Learning Toolboxのrandom関数が非常に強力なツールであることを学びました。
  • 既存の母集団から無作為にサンプルを抽出するには、重複の許否や重み付けも可能なrandsample関数を使用することを学びました。
  • さらに、randpermや疎行列のための関数、多変量正規分布のためのmvnrndといった関連関数や、ジェネレータの種類、RandStreamオブジェクトといった高度な概念についても触れました。
  • 最後に、乱数生成におけるよくある落とし穴と、効率的かつ信頼性の高い乱数生成のためのベストプラクティスを確認しました。

MATLABの乱数生成機能は非常に豊富で柔軟です。この記事で解説した関数とテクニックを習得することで、あなたは様々なシミュレーション、モデリング、分析タスクにおいて、「思い通りの乱数」を自在に生成し、より信頼性が高く、再現可能な結果を得ることができるようになるでしょう。

乱数生成は実践を通じて理解が深まります。ぜひ、この記事で紹介したコード例を実際にMATLABで実行し、パラメータを変えたり、異なる分布を試したりして、その振る舞いを観察してみてください。

これで、MATLABでの乱数生成に関する徹底解説は終わりです。あなたのMATLABによるデータ分析やシミュレーションが、より一層豊かで正確なものになることを願っています。


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール