로또 커뮤니티에는 "핫 넘버", "콜드 넘버", "이번에 나올 차례"라는 말이 넘칩니다. 과거 당첨 번호의 통계를 내면 어떤 번호는 유난히 자주, 어떤 번호는 유난히 드물게 나온 것처럼 보이기 때문입니다. 그런데 그 "치우침"은 무작위 추첨이라면 당연히 생기는 모양입니다. 이 글은 그 이유를 세 단계로 설명하고, 실제로 컴퓨터로 추첨을 반복해 본 결과를 보여 줍니다.
로또 추첨은 매 회차 독립적인 무작위 시행입니다. 지난주에 어떤 번호가 나왔든 이번 주 추첨에는 아무 영향이 없습니다. 동전 던지기로 생각하면 쉽습니다. 앞면이 다섯 번 연속 나왔다고 해서 여섯 번째에 뒷면이 나올 확률이 50%보다 높아지지 않습니다. 동전은 앞선 결과를 기억하지 못하고, 로또 추첨기도 마찬가지입니다.
P(다음 회차에 7번이 나온다 | 지난 10회 동안 안 나왔다) = P(7번이 나온다)
= 6 / 45 ≈ 13.3% (보너스 제외)
"오래 안 나왔으니 이제 나올 때가 됐다"는 생각에는 이름이 있습니다. 도박사의 오류입니다. 이 착각이 흔한 이유는 두 가지입니다.
아래는 로또 6/45 추첨을 컴퓨터로 반복해 번호별로 몇 번 나왔는지 센 코드입니다. 난수 생성기의 시드를 고정(20260919)했기 때문에
누가 실행해도 같은 결과가 나옵니다.
function mulberry32(a) { // 시드 고정 난수 생성기
return function () {
a |= 0; a = a + 0x6D2B79F5 | 0;
let t = Math.imul(a ^ a >>> 15, 1 | a);
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
return ((t ^ t >>> 14) >>> 0) / 4294967296;
};
}
function simulate(draws, seed) {
const rnd = mulberry32(seed);
const count = new Array(46).fill(0);
for (let d = 0; d < draws; d++) {
const pool = Array.from({ length: 45 }, (_, i) => i + 1);
for (let k = 0; k < 6; k++) { // 중복 없이 6개 뽑기
const i = Math.floor(rnd() * pool.length);
count[pool.splice(i, 1)[0]]++;
}
}
return count.slice(1);
}
const c = simulate(1000, 20260919);
console.log(Math.min(...c), Math.max(...c));
결과는 다음과 같습니다. 모든 번호는 정확히 같은 확률로 뽑히도록 만든 추첨인데도, 횟수는 번호마다 다릅니다.
| 추첨 횟수 | 번호당 기댓값 | 가장 적게 나온 번호 | 가장 많이 나온 번호 |
|---|---|---|---|
| 100회 | 13.3회 | 5회 (33번, 기댓값보다 −62%) | 22회 (1번, +65%) |
| 1,000회 | 133.3회 | 111회 (7번, −17%) | 160회 (20번, +20%) |
| 100,000회 | 13,333.3회 | 13,044회 (17번, −2.2%) | 13,532회 (5번, +1.5%) |
여기서 읽어야 할 것은 세 가지입니다.
지난 기록에서 "많이 나온 번호"를 골라 사는 것은 "지난 동전 던지기에서 앞면이 많았으니 앞면에 거는" 것과 같습니다. 기록은 이미 지나간 무작위의 모양을 보여 줄 뿐, 다음 결과에 대한 정보를 갖고 있지 않습니다.
당첨 확률은 어떤 조합이든 같습니다. 다만 로또 1~3등 당첨금은 당첨자 수로 나누어 받는 구조이므로, 다른 사람도 많이 고르는 조합을 고르면 당첨됐을 때 나눠 받는 사람이 늘어날 수 있습니다.
이것은 당첨 확률을 높이는 방법이 아니라 당첨금이 나뉠 위험을 조금 줄일 수 있다는 정도의 이야기입니다. 실제로 사람들이 어떤 번호를 고르는지의 정확한 분포는 알 수 없고, 등수별 당첨금 규정은 회차마다 공식 자료를 확인해야 합니다.
등수별 확률 계산은 이전 글에서, 복권을 부담 없이 즐기는 기준은 다음 글에서 이어집니다.