【Perl】再現性ありの配列シャッフル【ワンライナー】
2015-09-16-1
[Programming][Perl]
行をランダムに入れ替える(シャッフルする)には、コマンドライン(UNIX系)なら shuf コマンドを使います。
しかし再現性がありません。毎回異なる結果になります。実用的にはこれで良いのですが、ある種の状況では困ります。
例えば、機械学習でクロスバリデーションするときは、シャッフルしてからファイル分割するわけですが、結果が元のファイルの何行目かを知りたいときがあります(もちろん、行番号だけの行からなるファイルを作ってシャッフルして使うなど、工夫すれば元のファイルの行へのアクセスが可能ですが、ここではシンプルに済ませたい場合の話です)。
シャッフルを再現するにはランダムシードが指定できれば OK。
Perl モジュールの List::Util の shuffle 関数は実行前に srand でランダムシードが指定できるので、これで解決。
srand の引数(後ろの数字)を変更して使いましょう。
実行例です:
ref.
- Perl で配列をシャッフル[2006-11-28-2]
- 重複のない乱数リストをPerlワンライナーで生成する[2012-01-30-1]
% seq 10 | shuf 7 1 2 3 9 6 8 10 5 4
しかし再現性がありません。毎回異なる結果になります。実用的にはこれで良いのですが、ある種の状況では困ります。
例えば、機械学習でクロスバリデーションするときは、シャッフルしてからファイル分割するわけですが、結果が元のファイルの何行目かを知りたいときがあります(もちろん、行番号だけの行からなるファイルを作ってシャッフルして使うなど、工夫すれば元のファイルの行へのアクセスが可能ですが、ここではシンプルに済ませたい場合の話です)。
シャッフルを再現するにはランダムシードが指定できれば OK。
Perl モジュールの List::Util の shuffle 関数は実行前に srand でランダムシードが指定できるので、これで解決。
(追記150922: もっと短い書き方を教えていただきました(↓)。ありがとうございます。perl -M'List::Util shuffle' -ne ' BEGIN{srand 4649} END{print shuffle @a} push@a,$_'
)perl -MList::Util=shuffle -e 'BEGIN{srand 1};print shuffle(<>)'
srand の引数(後ろの数字)を変更して使いましょう。
実行例です:
% seq 10 | perl -M'List::Util shuffle' -ne 'BEGIN{srand 0}...' 8 5 10 3 6 4 9 1 7 2 % seq 10 | perl -M'List::Util shuffle' -ne 'BEGIN{srand 0}...' 8 5 10 3 6 4 9 1 7 2 % seq 10 | perl -M'List::Util shuffle' -ne 'BEGIN{srand 1}...' 6 2 8 9 10 4 3 7 5 1 % seq 10 | perl -M'List::Util shuffle' -ne 'BEGIN{srand 1}...' 6 2 8 9 10 4 3 7 5 1
ref.
- Perl で配列をシャッフル[2006-11-28-2]
- 重複のない乱数リストをPerlワンライナーで生成する[2012-01-30-1]
この記事に言及しているこのブログ内の記事