ランダム数字で抽選する — 重複なしの決め方と、公平だと言える手順

jakup 運営チーム

「ランダムな数字がほしい」と思う場面は、思っているより幅があります。忘年会の席順を決めたい。応募者の中から当選者を選びたい。テストに使うデータがほしい。調査のサンプルを無作為に抜き出したい。

どれも「数字をランダムに出す」という点では同じですが、必要な条件はまったく違います。 席順なら同じ番号が二度出てはいけません。サイコロの代わりなら、むしろ同じ目が続いても構わない。ここを取り違えたまま始めると、たいてい途中でやり直しになります。

このページでは、ランダム数字を実務で使うときに先に決めておくべきことと、あとから「公平でした」と説明できる手順の作り方を整理します。数字そのものを出す作業はツールに任せて、ここでは判断のほうを扱います。

まず決めるのは「重複なし」か「重複あり」か

最初の分岐であり、いちばん間違えやすいところです。

統計の言葉では、重複ありを復元抽出、重複なしを非復元抽出と呼びます。引いた番号を箱に戻すかどうか、という違いです。

同じ数字が出るか 向いている場面
重複あり 出る サイコロの代用・テストデータ・確率の試行
重複なし 出ない 席順・当選者選び・グループ分け・サンプリング

迷ったら 「同じ番号が二度出たら困るか」 と自分に聞いてください。困るなら重複なしです。

そしてもう一点。重複なしを選ぶときは、範囲の広さが個数以上でなければ成立しません。 1〜10 から 12 個を重複なしで引くことはできない、というのは言われれば当たり前ですが、応募者 80 人から当選者 100 名を選ぼうとして初めて気づく、というのは実際に起こります。

逆に言えば、決めることはこの二つだけです。同じ数字を許すかどうかと、範囲をどこからどこまでにするか。 それさえ決まっていれば、あとは出すだけなので、先に一度触って感覚をつかんでおくほうが早いかもしれません。

// すぐに計算する

乱数ジェネレーター

範囲・個数・重複の設定でランダムな数字を生成。抽選・宝くじ・サンプリングに。

乱数ジェネレーター を開く

公平だと説明できる抽選の手順

抽選そのものは一瞬で終わります。難しいのは、終わったあとに「この抽選は公平でした」と示せる状態にしておくことです。手順のほうが本体だと考えてください。

  1. 母集団に連番を振る。 応募者を受付順に 1 から並べます。名前ではなく番号で扱うことで、選ぶ側の主観が入る余地がなくなります。
  2. 当選者数と補欠数を先に決める。 「当選 10 名・補欠 3 名」まで決めてから引きます。引いたあとで補欠を足すと、その部分だけ後付けの設計になります。
  3. 範囲・個数・重複なしを設定して、一度だけ引く。
  4. 出た順のまま記録する。 画面を保存する、立会人を置く、日時を残す。順番そのものが当選順位や補欠順になります。
  5. 条件を事前に公開しておく。 募集要項に抽選方法と当選者数を書いておけば、結果への問い合わせにそのまま答えられます。

3 番の「一度だけ」が要です。気に入らないから引き直す、が一度でも入った時点で、それは抽選ではなく選抜になります。やり直す可能性があるなら、どういう場合にやり直すのかを引く前に決めて公開しておくしかありません。

景品や賞品を伴う抽選では、景品類の上限額などが景品表示法で定められています。実施前に消費者庁の案内で最新の条件をご確認ください。ここに書いたのは進め方の整理であり、法的な助言ではありません。

Excel で済ませられるか

Excel でも乱数は作れますが、抽選に使うには合わない点が二つあります。

RANDBETWEEN には重複を防ぐ機能がありません。 100 人から 10 人選ぼうとして 10 個並べると、同じ番号が入ります。そして RANDRANDBETWEEN揮発性関数で、シートを編集する・ファイルを開き直すだけで再計算されて値が変わります。抽選結果を保存したはずが翌日には別の数字になっていた、という事故はほぼこれが原因です。

重複なしを Excel で作る手順や、結果を値として固定する方法は Excelでランダムな数字を作る にまとめました。 一回きりの抽選なら、範囲と個数と重複なしを指定して引くほうが早く、壊れません。

疑似乱数と、暗号論的に安全な乱数

「それは本当にランダムなのか」という質問はよく出ます。

プログラムが作る乱数の多くは疑似乱数です。内部の状態から計算で次の値を作るので、原理としては決まった手順の産物です。統計的な偏りが出ないよう設計されていて、席替えやグループ分けの用途では実用上まったく問題ありません。

対して暗号論的に安全な乱数は、次の値を予測できないことまで保証します。ブラウザには crypto.getRandomValues() という標準機能があり、jakup の乱数ジェネレーターはこちらを使っています。結果を先読みされては困る抽選でも、そのまま使えるという意味です。

ただし引き換えがひとつあります。予測できないことと、同じ結果をもう一度出せることは両立しません。 再現が必要なら、乱数の側ではなく記録の側で担保してください。

よくある失敗と、その原因

四捨五入で範囲に丸める。 自分でプログラムを書く場合、Math.round() を使うと両端の数字だけ選ばれる確率が半分になります。 切り捨て(Math.floor())が正解です。範囲の端が妙に出にくいと感じたら、たいていこれです。

割り算の余りで範囲に落とす。 大きな乱数を % 100 のようにして 0〜99 に収めると、範囲の前半がわずかに出やすくなります(モジュロバイアス)。桁が大きければ影響は小さいものの、厳密さが要る場面では避ける書き方です。

人が数字を思いつく。 「適当に 1 から 10 で選んで」と言われたときの人の答えは偏りやすいことが知られています。端の数字は避けられ、真ん中あたりに集まる。ランダムさが要るなら、人の直感は使わないほうが確実です。

ばらけて見えないので引き直す。 これは失敗というより誤解です。次の項で扱います。

無作為であることと、公平であること

最後に、抽選を扱うときにいちばん効いてくる区別を置いておきます。

無作為であることと、公平であることは同じではありません。

チーム分けで「どの班も強さが均等になるように」したい場合、無作為では実現できません。無作為は偏りを意図的に作らないだけで、結果として強い人が一つの班に固まることは普通に起こります。均等にしたいなら、実力順に並べて上位と下位を交互に振り分けるような、無作為の反対側にある設計が要ります。

「誰も操作していない」と示したいなら無作為が最善。「結果のバランスを取りたい」なら無作為は道具として合っていません。 どちらをやりたいのかを先に決めてください。

席替えやグループ分けの具体的な手順は 席替え・グループ分けをランダムで決める にまとめています。

よくある質問

Q. 出た結果がばらけていないのですが、壊れていませんか。 いいえ。真に無作為なら、近い数字が続いたり、ある範囲に固まったりすることは普通に起こります。むしろ毎回きれいに散らばるほうが不自然です。「均等にばらけたもの」を無作為だと感じてしまうのは、人の側の錯覚としてよく知られています。

Q. 抽選をやり直してもいいですか。 引いたあとの気分でやり直すと、抽選としての意味がなくなります。やり直しの可能性があるなら、条件(当選者の資格不備が判明した場合など)を引く前に決めて公開しておいてください。

Q. 当選者が辞退したらどうしますか。 補欠を先に引いておくのがいちばん簡単です。当選 10 名なら、同じ抽選で 13 個引いて 11〜13 番目を補欠にしておく。辞退が出るたびに引き直すより、手順として説明しやすくなります。

Q. 「公平な抽選だった」と証明できますか。 数学的に証明することはできません。示せるのは手順の側です。条件を事前に公開し、一度だけ引き、結果をそのまま記録する。この三つが揃っていれば、問い合わせには十分答えられます。

Q. 応募者数より多い数を重複なしで引けますか。 引けません。重複なしは範囲の中の数字を使い切る方式なので、個数は範囲の広さを超えられません。当選者数が応募者数を上回るなら、そもそも抽選が不要な状況です。

Q. 当選確率を人によって変えたいのですが。 確率に応じて番号を複数割り当てるのが手軽です。当選しやすくしたい人に番号を 2 つ持たせれば、その人の確率は 2 倍になります。応募者名簿の側で調整する、と考えてください。

// すぐに計算する

乱数ジェネレーター

範囲・個数・重複の設定でランダムな数字を生成。抽選・宝くじ・サンプリングに。

乱数ジェネレーター を開く