random_stateを固定しても再現しない?行順・データ版・実行環境を分けて確認する
random_stateは、scikit-learnなどの処理で乱数を制御するための引数です。同じ整数を指定して実験を再確認しやすくできますが、データの内容や並びまで固定する引数ではありません。「同じseedなのに違う」を調べるときは、乱数・入力・環境の3つを分けます。
整数と乱数生成器の共有は同じ扱いではない
scikit-learnでは、整数を指定する場合と、RandomStateのインスタンスやNoneを使う場合で、繰り返し呼び出した際の状態の扱いが異なります。使う推定器や分割器の公式引数説明を確認してください。[出典1] ここでは、学習結果を1回再現する教材として、分割器に整数を渡します。
from sklearn.model_selection import train_test_split
row_ids = ["doc-a", "doc-b", "doc-c", "doc-d", "doc-e", "doc-f"]
train_ids, test_ids = train_test_split(
row_ids, test_size=2, random_state=17
)
print(train_ids, test_ids)
出力された行IDを保存してください。乱数の整数だけを記録するより、どの行を評価したかを直接確認できます。値17は教材の識別用で、性能がよくなる数字という意味はありません。
同じ行番号でも、行順が変われば別の文書になる
教材の元の並びがA、B、C、D、E、Fで、評価用の行番号が1、4だったとします。対象はB、Eです。並びをF、E、D、C、B、Aへ反転すると、同じ番号1、4の対象はE、Bになります。この例では集合はたまたま同じですが、順番は変わります。番号0、2ならA、CがF、Dになり、対象自体も変わります。
そのため、行番号だけを保存して別の並びへ適用しないでください。安定した行ID、入力の内容、並べ方をセットで記録します。取得順が不定のファイル一覧やデータベースの返却順にも注意が必要です。
再現用の記録を4つに分ける
| 記録 | 例 | 分かること |
|---|---|---|
| 入力 | データファイルのハッシュ、行ID、列順、抽出条件 | 同じデータを参照したか |
| 分割 | 学習・評価の行ID、random_state、分割条件 | 同じ対象で比較したか |
| 処理 | コード版、前処理、モデルの引数 | 同じ計算を指定したか |
| 環境 | Python・ライブラリ版、実行機器、並列設定 | 実行条件の違いがないか |
seedを変える実験と、seedを固定する検証を分ける
1回の結果を再現する目的なら、条件を固定します。乱数による変動を調べたいなら、複数のseedで試す設計を先に決めます。この2つを混ぜて、よい数値が出たseedだけを採用すると、実験の意味が変わります。
教材の比較表には、各seedの評価行IDと指標を残す欄を用意します。数値は実行後に埋め、平均だけでなく変動も確認します。最終評価用データを見ながらseedを選び直すことは避けてください。
再現できないときの点検順
- 評価した行IDが一致しているか。
- データのハッシュと前処理の版が一致しているか。
- 乱数を使う箇所すべての引数を確認したか。
- 乱数生成器を共有し、別の処理が状態を進めていないか。
- ライブラリ版、並列化、機器などが変わっていないか。
random_stateが固定されていることは、実験の記録の一部分です。再現性を示すレポートでは、seedだけでなく入力と分割のIDを示すと、違いの発生箇所を追いやすくなります。本記事は再現性の教材であり、掲載コードによる実モデルの性能測定結果は提示していません。