PythonでLOTO6のデータ分析をしてみた ~その3~

はじめに

その3では、「loto6で期待値の高い数値の選び方はあるのか?」について以下の手順で分析・解析していきます。

  1. 期待値の定義と算出
  2. 期待値を最大化する数字の選び方

なお、本記事ではその2の内容を踏まえて、「loto6で特別に出やすい数字はない(出目は完全にランダム)」という前提で進めていきます。

PythonでLOTO6のデータ分析をしてみた ~その2~


出目がランダムじゃ期待値を上げることなんて出来ないのではないか?と思うかもしれませんが、loto6は4等賞以上の当たりでは当選者で賞金を分配するシステムになっているため、人が選びにくい数字を選ぶことで期待値を上げられる可能性があります。仮説としては、例えば数字を誕生日等から選ぶ人が多ければ、月である1〜12、日である1〜31に選択される数字が集中するため、この範囲を選ばなければ当選が他人と被りにくく、期待値を上げられるというようなことがありえるのでは、と考えました。

期待値の定義と算出

期待値の定義

loto6は1口200円で購入することが出来るので、期待値とは「当選確率を考慮した当選金額が1口当たり何円か」であると言えます。また、この期待値が高くなるような数字の選び方を見つけ出すことが本記事の目的になります。
上記より、1口の期待値(E(1口))は以下の式で表すことが出来ます。

\begin{equation*}
E(1口) = \Sigma_{k=1}^{5}{(k等賞の当選確率×k等賞の当選金額)}
\end{equation*}

期待値の算出

上記に示したとおり、期待値を算出するためには1〜5の各等賞の当選確率と当選金額を求める必要がありますので、以下順をおって算出していきます。

当選確率の理論値

loto6は1〜43の数字の中から6つの数字を選び、全て的中していれば1等賞、5つ的中していて残りの1つがボーナス数字と一致していれば2等賞、5つ的中していれば3等賞、4つ的中していれば4等賞、3つ的中していれば5等賞というように決まっていますのでそれぞれ以下のような式で理論値を求めることが出来ます。

\begin{equation*}
p(1等賞) = \frac{{}_{6} C _6}{ {}_{43} C _6}
\end{equation*}
\begin{equation*}
p(2等賞) = \frac{{}_{1} C _1 \cdot {}_{6} C _5 }{ {}_{43} C _6}
\end{equation*}
\begin{equation*}
p(3等賞) = \frac{{}_{36} C _1 \cdot {}_{6} C _5 }{ {}_{43} C _6}
\end{equation*}
\begin{equation*}
p(4等賞) = \frac{{}_{37} C _2 \cdot {}_{6} C _4 }{ {}_{43} C _6}
\end{equation*}
\begin{equation*}
p(5等賞) = \frac{{}_{37} C _3 \cdot {}_{6} C _3 }{ {}_{43} C _6}
\end{equation*}
\begin{equation*}
p(ハズレ|2個的中) = \frac{{}_{37} C _4 \cdot {}_{6} C _2 }{ {}_{43} C _6}
\end{equation*}
\begin{equation*}
p(ハズレ|1個的中) = \frac{{}_{37} C _5 \cdot {}_{6} C _1 }{ {}_{43} C _6}
\end{equation*}
\begin{equation*}
p(ハズレ|0個的中) = \frac{{}_{37} C _6 \cdot {}_{6} C _0 }{ {}_{43} C _6}
\end{equation*}

pythonのscipyを使って計算してみます。

In [1]:
import scipy.misc
import scipy as sp
#1等賞が当たる確率
sp.misc.comb(6, 6) / sp.misc.comb(43, 6)
Out[1]:
1.6402977862213017e-07
In [2]:
#2等賞が当たる確率
sp.misc.comb(1, 1) * sp.misc.comb(6, 5) / sp.misc.comb(43, 6)
Out[2]:
9.84178671732781e-07
In [3]:
#3等賞が当たる確率
sp.misc.comb(36, 1) * sp.misc.comb(6, 5) / sp.misc.comb(43, 6)
Out[3]:
3.543043218238012e-05
In [4]:
#4等賞が当たる確率
sp.misc.comb(37, 2) * sp.misc.comb(6, 4) / sp.misc.comb(43, 6)
Out[4]:
0.0016386574884350805
In [5]:
#5等賞が当たる確率
sp.misc.comb(37, 3) * sp.misc.comb(6, 3) / sp.misc.comb(43, 6)
Out[5]:
0.025490227597879028
In [6]:
#ハズレの確率
(sp.misc.comb(37, 4) * sp.misc.comb(6, 2) + sp.misc.comb(37, 5) * sp.misc.comb(6, 1) + sp.misc.comb(37, 6) * sp.misc.comb(6, 0)) / sp.misc.comb(43, 6)
Out[6]:
0.9728345362730532

整理すると下記のような感じです。5等すら2.5%程度しかなく、ほぼほぼ外れるギャンブルであることが分かります。
1等賞:およそ600万分の1
2等賞:およそ100万分の1
3等賞:およそ3万分の1
4等賞:およそ600分の1
5等賞:およそ40分の1
ハズレ:およそ40分の39

(参考)当選確率の実績値との比較

念の為、実データを使った当選確率の算出も実施してみます。データは以下で作ったものを使います。

Pandasを使ってloto6のデータを整形・加工する


In [7]:
import pandas as pd
#データ読み込み
df = pd.read_csv("loto6_allData.csv", index_col=1, parse_dates=True)
In [8]:
#データの上位5行を確認
df.head()
Out[8]:
抽せん回 曜日 本数字1 本数字2 本数字3 本数字4 本数字5 本数字6 ボーナス数字 1等口数 34 35 36 37 38 39 40 41 42 43
抽せん日
2000-10-05 1 2 8 10 13 27 30 39 2 0 0 0 0 0 7 0 0 0 0
2000-10-12 2 1 9 16 20 21 43 5 0 0 0 0 0 0 0 0 0 0 6
2000-10-19 3 1 5 15 31 36 38 13 2 0 0 5 0 6 0 0 0 0 0
2000-10-26 4 16 18 26 27 34 40 13 0 5 0 0 0 0 0 6 0 0 0
2000-11-02 5 9 15 21 23 27 28 43 0 0 0 0 0 0 0 0 0 0 7

5 rows × 65 columns

データには1等口数等の当選数があり、販売実績額を200(円/口)で割れば総口数が求まることから、これらを使って当選確率の実績値を求めることが可能です。

In [9]:
#総口数を計算
df['総口数'] = df['販売実績額'] / 200
#各等賞の割合を計算
for i in range(1, 6):
    df[str(i)+'等割合'] = df[str(i)+'等口数'] / df['総口数']
#データ確認
df.iloc[:, -5:].head()
Out[9]:
1等割合 2等割合 3等割合 4等割合 5等割合
抽せん日
2000-10-05 3.380711e-07 3.380711e-07 0.000044 0.002098 0.029489
2000-10-12 0.000000e+00 1.149056e-06 0.000032 0.001383 0.023779
2000-10-19 2.457452e-07 9.829807e-07 0.000020 0.001161 0.022294
2000-10-26 0.000000e+00 4.044960e-07 0.000018 0.001170 0.021693
2000-11-02 0.000000e+00 1.049850e-06 0.000030 0.001922 0.027994

通算の平均値を計算してみます。

In [10]:
df[[str(i)+'等割合' for i in range(1, 6)]].mean()
Out[10]:
1等割合    1.700584e-07
2等割合    1.161114e-06
3等割合    3.513919e-05
4等割合    1.637770e-03
5等割合    2.538049e-02
dtype: float64

先ほどの結果と比較してみましょう。

In [11]:
#理論値
percentList = [
    sp.misc.comb(6, 6) / sp.misc.comb(43, 6),
    sp.misc.comb(1, 1) * sp.misc.comb(6, 5) / sp.misc.comb(43, 6),
    sp.misc.comb(36, 1) * sp.misc.comb(6, 5) / sp.misc.comb(43, 6),
    sp.misc.comb(37, 2) * sp.misc.comb(6, 4) / sp.misc.comb(43, 6),
    sp.misc.comb(37, 3) * sp.misc.comb(6, 3) / sp.misc.comb(43, 6),
]
#実績値
tdf = df[[str(i)+'等割合' for i in range(1, 6)]].mean()
#結合
tdf = pd.concat([tdf, pd.DataFrame(index=tdf.index, data=percentList)], axis=1)
tdf.columns = ['実績値', '理論値']
tdf['誤差率%'] = 100 * (tdf['実績値'] - tdf['理論値']).abs() / tdf['実績値']
#表示
tdf
Out[11]:
実績値 理論値 誤差率%
1等割合 1.700584e-07 1.640298e-07 3.545037
2等割合 1.161114e-06 9.841787e-07 15.238411
3等割合 3.513919e-05 3.543043e-05 0.828823
4等割合 1.637770e-03 1.638657e-03 0.054174
5等割合 2.538049e-02 2.549023e-02 0.432357

ほぼ実績値と理論値が一致していますが、2等だけ15%程度違いがありますね。調べてみると、過去にドラマの数字と同じのを選ぶと2等が当選する!?というとんでもない事象があったようで、3等よりも多い3000口以上が当たったそうです。これは外れ値と考えられますので除外してもう一度見てみます。
https://www.news-postseven.com/archives/20120913_143230.html

In [12]:
#極端なケースを除外する
df = df[df['2等口数'] < 3000]
In [13]:
#実績値
tdf = df[[str(i)+'等割合' for i in range(1, 6)]].mean()
#結合
tdf = pd.concat([tdf, pd.DataFrame(index=tdf.index, data=percentList)], axis=1)
tdf.columns = ['実績値', '理論値']
tdf['誤差率%'] = 100 * (tdf['実績値'] - tdf['理論値']).abs() / tdf['実績値']
#表示
tdf
Out[13]:
実績値 理論値 誤差率%
1等割合 1.700234e-07 1.640298e-07 3.525169
2等割合 9.571105e-07 9.841787e-07 2.828116
3等割合 3.512710e-05 3.543043e-05 0.863517
4等割合 1.637609e-03 1.638657e-03 0.064031
5等割合 2.537762e-02 2.549023e-02 0.443740

概ね一致してきましたね。loto6はほぼ理論通りの確率で当選者を出していると言えそうです。

各回での1口当たりの実績的な期待値の算出

理論通りの確率で当選するとして、当選確率は理論値を、当選金額は実績値を使うと、1回1回のloto6での期待値は以下のように計算できます。

\begin{equation*}
E(1口) = \Sigma_{k=1}^{5}{(k等賞の当選確率×k等賞の当選金額)}
\end{equation*}
In [14]:
#数式に基づいて計算
df['1口の賞金期待値'] = 0
for i in range(1, 6):
    df['1口の賞金期待値_' + str(i) + '等'] = df[str(i)+'等賞金'] * percentList[i-1]
    df['1口の賞金期待値'] += df['1口の賞金期待値_' + str(i) + '等']
#表示
df['1口の賞金期待値'].head()
Out[14]:
抽せん日
2000-10-05     97.869876
2000-10-12     77.442953
2000-10-19    116.705072
2000-10-26    123.413250
2000-11-02     71.617009
Name: 1口の賞金期待値, dtype: float64
In [15]:
#統計量を確認
df['1口の賞金期待値'].describe()
Out[15]:
count    1196.000000
mean      102.316818
std        30.363657
min        39.939939
25%        79.551666
50%        97.834840
75%       119.104450
max       230.387829
Name: 1口の賞金期待値, dtype: float64

平均的な期待値は102円で、200円に対してほぼ半減することが分かります。一方で、最大は230円と、期待値が1口の価格を上回ることもある、という結果です。高い期待値を狙う数字の選び方はあるのでしょうか。

期待値を最大化する数字の選び方

おおまかな傾向の確認

まず時系列的な変化を確認してみます。

In [16]:
%matplotlib inline
#単純に期待値をプロット
df['1口の賞金期待値'].plot()
#100点の移動平均をプロット
df['1口の賞金期待値'].rolling(100, center=True).mean().plot()
Out[16]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f4c5e61a668>

ばらつきは大きいですが、移動平均を取るとあまり全体としての傾向には差がないことが分かります。そのため、時期的に傾向が変わっているということはなさそうです。次にヒストグラムでばらつきの形状を見てみましょう。

In [17]:
df['1口の賞金期待値'].plot.hist()
Out[17]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f4c5e516160>

単峰性ですが歪んだ形状をしていることが分かります。特に、期待値が高くなる側にロングテールな傾向があります。期待値が高い5ケースと低い5ケースについて、データを確認してみましょう。

In [18]:
#期待値の上位5件
df.sort_values('1口の賞金期待値', ascending=False).iloc[:5].T
Out[18]:
抽せん日 2015-05-11 00:00:00 2013-11-29 00:00:00 2004-06-03 00:00:00 2015-11-02 00:00:00 2005-02-17 00:00:00
抽せん回 966 817 189 1016 226
曜日
本数字1 10 16 3 1 8
本数字2 22 21 32 14 26
本数字3 31 27 35 31 36
本数字4 34 32 36 32 40
本数字5 36 34 39 39 42
本数字6 43 43 40 42 43
ボーナス数字 30 42 5 34 21
1等口数 1 1 1 0 1
1等賞金 133072000 145727200 200000000 0 200000000
2等口数 1 1 3 1 4
2等賞金 119763800 131153300 97388900 127248600 80699600
3等口数 134 273 357 134 274
3等賞金 1072500 576400 982000 1139500 1413700
4等口数 7613 10628 16537 7989 18629
4等賞金 16600 13000 18700 16800 18300
5等口数 140833 169749 327872 147595 352899
5等賞金 1000 1000 1000 1000 1000
キャリーオーバー 0 0 124632575 160113420 158668297
キャリーオーバー_今回 0 0 0 18724752 0
販売実績額 1475915400 1650770200 3565657000 1563623000 3918720000
1 0 0 0 1 0
2 0 0 0 0 0
3 0 0 1 0 0
4 0 0 0 0 0
5 0 0 7 0 0
6 0 0 0 0 0
7 0 0 0 0 0
8 0 0 0 0 1
26 0 0 0 0 2
27 0 3 0 0 0
28 0 0 0 0 0
29 0 0 0 0 0
30 7 0 0 0 0
31 3 0 0 3 0
32 0 4 2 4 0
33 0 0 0 0 0
34 4 5 0 7 0
35 0 0 3 0 0
36 5 0 4 0 3
37 0 0 0 0 0
38 0 0 0 0 0
39 0 0 5 5 0
40 0 0 6 0 4
41 0 0 0 0 0
42 0 7 0 6 5
43 6 6 0 0 6
総口数 7.37958e+06 8.25385e+06 1.78283e+07 7.81812e+06 1.95936e+07
1等割合 1.35509e-07 1.21156e-07 5.60906e-08 0 5.10371e-08
2等割合 1.35509e-07 1.21156e-07 1.68272e-07 1.27908e-07 2.04148e-07
3等割合 1.81582e-05 3.30755e-05 2.00244e-05 1.71397e-05 1.39842e-05
4等割合 0.00103163 0.00128764 0.000927571 0.00102186 0.00095077
5等割合 0.0190842 0.020566 0.0183906 0.0188786 0.0180109
1口の賞金期待値 230.388 220.197 219.58 218.628 217.794
1口の賞金期待値_1等 21.8278 23.9036 32.806 0 32.806
1口の賞金期待値_2等 117.869 129.078 95.8481 125.235 79.4228
1口の賞金期待値_3等 37.9991 20.4221 34.7927 40.373 50.088
1口の賞金期待値_4等 27.2017 21.3025 30.6429 27.5294 29.9874
1口の賞金期待値_5等 25.4902 25.4902 25.4902 25.4902 25.4902

77 rows × 5 columns

上位5件を見ると、2等の当選口数が少なく、2等の期待値が80円〜120円と非常に高いことが分かります。通常は中央値が100円程度ですので、この2等の期待値が全体の期待値を引っ張っているということのようです。また、当選数字を見ると、ボーナス数字を含めた当選数字に30とか40とかの大きい値が多いことが分かります。

In [19]:
#期待値の下位5件
df.sort_values('1口の賞金期待値').iloc[:5].T
Out[19]:
抽せん日 2017-04-03 00:00:00 2016-02-04 00:00:00 2014-05-19 00:00:00 2012-08-30 00:00:00 2003-07-31 00:00:00
抽せん回 1162 1042 865 689 146
曜日
本数字1 3 4 5 6 7
本数字2 4 10 7 8 17
本数字3 8 11 8 12 27
本数字4 12 12 12 17 36
本数字5 24 18 23 24 37
本数字6 37 25 25 31 39
ボーナス数字 10 36 26 38 4
1等口数 0 12 6 8 21
1等賞金 0 8291100 16727400 20094300 13944100
2等口数 15 17 18 34 31
2等賞金 4228500 5267200 5018200 4255200 8501300
3等口数 533 663 683 753 2362
3等賞金 128500 162000 158700 230500 133800
4等口数 20365 22031 24693 28797 46090
4等賞金 3500 4300 3800 5300 6000
5等口数 265661 257868 302771 381008 495006
5等賞金 1000 1000 1000 1000 1000
キャリーオーバー 247187990 0 0 0 0
キャリーオーバー_今回 35766902 0 0 0 0
販売実績額 1514209200 1442538800 1549941000 2251563600 3659103200
1 0 0 0 0 0
2 0 0 0 0 0
3 1 0 0 0 0
4 2 1 0 0 7
5 0 0 1 0 0
6 0 0 0 1 0
7 0 0 2 0 1
8 3 0 3 2 0
26 0 0 7 0 0
27 0 0 0 0 3
28 0 0 0 0 0
29 0 0 0 0 0
30 0 0 0 0 0
31 0 0 0 6 0
32 0 0 0 0 0
33 0 0 0 0 0
34 0 0 0 0 0
35 0 0 0 0 0
36 0 7 0 0 4
37 6 0 0 0 5
38 0 0 0 7 0
39 0 0 0 0 6
40 0 0 0 0 0
41 0 0 0 0 0
42 0 0 0 0 0
43 0 0 0 0 0
総口数 7.57105e+06 7.21269e+06 7.74970e+06 1.12578e+07 1.82955e+07
1等割合 0 1.66373e-06 7.74223e-07 7.10617e-07 1.14782e-06
2等割合 1.98123e-06 2.35696e-06 2.32267e-06 3.02012e-06 1.6944e-06
3等割合 7.03998e-05 9.19213e-05 8.81324e-05 6.68869e-05 0.000129103
4等割合 0.00268985 0.00305448 0.00318631 0.00255796 0.0025192
5等割合 0.0350891 0.035752 0.0390687 0.0338439 0.0270561
1口の賞金期待値 39.9399 44.82 45.0225 49.8258 50.7168
1口の賞金期待値_1等 0 1.35999 2.74379 3.29606 2.28725
1口の賞金期待値_2等 4.1616 5.18387 4.93881 4.18788 8.3668
1口の賞金期待値_3等 4.55281 5.73973 5.62281 8.16671 4.74059
1口の賞金期待値_4等 5.7353 7.04623 6.2269 8.68488 9.83194
1口の賞金期待値_5等 25.4902 25.4902 25.4902 25.4902 25.4902

77 rows × 5 columns

下位5件を見ると、1等から4等までの期待値が非常に低いことが分かります。また、当選数字を見ると、5位を除き、当選数字に30未満の小さい数字が多いことが分かります。本当にカレンダーから数字を選ぶ人が多く期待値が上がりにくいのかもしれません。

次に特定の数字が出た時の期待値を計算してみましょう。具体的には1が出た時の期待値、2が出た時の期待値、という具合です。

In [20]:
tmp = []

#特定の数値が出た場合の期待値を計算する
for i in range(1, 44):
    tmp.append(df[df[str(i)] >= 1][['1口の賞金期待値_' + str(i) + '等' for i in range(1, 6)] + ['1口の賞金期待値']].mean())
    
df_a = pd.concat(tmp, axis=1).T
df_a.index += 1
df_a.head()
Out[20]:
1口の賞金期待値_1等 1口の賞金期待値_2等 1口の賞金期待値_3等 1口の賞金期待値_4等 1口の賞金期待値_5等 1口の賞金期待値
1 19.412406 21.266797 21.232142 17.265832 25.490228 104.667405
2 17.803421 20.000892 19.249818 15.902699 25.490228 98.447058
3 17.215290 19.828452 17.388877 14.743536 25.490228 94.666383
4 21.461441 17.943574 18.544797 15.406742 25.490228 98.846781
5 20.290387 18.074772 17.792064 15.094927 25.490228 96.742378

1口の賞金期待値について棒グラフで確認してみましょう。

In [21]:
df_a['1口の賞金期待値'].plot.bar(figsize=(9, 6), ylim=(90, 120))
Out[21]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f4c5ac6fcf8>

上位から43、32、42、34、31と大きい数字が並んでいることが分かります。逆に3や8はとても小さい傾向が読み取れます。これらは上の結果を裏付けるものであると言えます。一方で、20や21、16、1などの数字も高めの傾向があるようです。その2で見たように、1は最も出ていない、や、21は多め、等の傾向があるので、これらを元に戦略を練っている人の影響が出ているのかもしれません。

また、上記のグラフを等賞ごとの期待値の積み上げ棒グラフで描いた結果がこちら。

In [22]:
df_a[['1口の賞金期待値_' + str(i) + '等' for i in range(5, 0, -1)]].plot.bar(figsize=(9, 6), stacked=True)
Out[22]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f4c5ab42ef0>

ぱっと見ですが、2等のばらつきが大きそうです。それぞれの標準偏差をプロットしてみましょう。

In [23]:
df_a[['1口の賞金期待値_' + str(i) + '等' for i in range(5, 0, -1)]].std().plot.bar(figsize=(9, 6), stacked=True)
Out[23]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f4c5a908208>

ばらつきは、2等、3等、1等、4等の順番のようです。これも上記の結果(上位5件は2等の期待値の影響が大きかった)を裏付けるものであると言えますね。

次にキャリーオーバーの額との関係を見てみましょう。

In [24]:
df.plot.scatter(x='キャリーオーバー_今回', y='1口の賞金期待値')
Out[24]:
<matplotlib.axes._subplots.AxesSubplot at 0x7f4c5a89c5f8>

散布図では良くわからないですね。カテゴライズして集計してみましょう。

In [25]:
df['キャリーオーバー_今回_category'] = pd.cut(df['キャリーオーバー_今回'], 10)
df.pivot_table(index='キャリーオーバー_今回_category', values='1口の賞金期待値', aggfunc='median').plot.bar()
del df['キャリーオーバー_今回_category']

平均的には、キャリーオーバーが高いほど期待値も高くなる傾向が見て取れます。以上より、データの可視化により以下の傾向が見て取れました。

・ 期待値は時系列的にはほとんど変化していない
・ 期待値のばらつきは単峰性だが歪があり、高い側がなだらかな傾向がある
・ 期待値のばらつきの要因は特に2等賞の期待値が影響している
・ 当選番号に30以上の数字が多い場合は期待値が高く、それ以下の数字が多い場合には期待値が低い傾向がある
・ キャリーオーバーが高いほど期待値が高くなる傾向がある

決定木分析を用いた期待値の分析

さあ、とうとう本題に近づいてきました。決定木分析を使って期待値を分析してみます。

In [26]:
#必要なモジュールのインポート
from sklearn import tree
from sklearn.externals.six import StringIO
import pydotplus
from IPython.display import display, Image

説明変数として、本数字の値とボーナス数字、キャリーオーバーの金額、加えてそれぞれの数字が出たかどうかを与えます。

In [27]:
Exvar = df.columns[2:9].tolist() + df.columns[20:21].tolist() + df.columns[22:-12].tolist()
display(Exvar)
['本数字1',
 '本数字2',
 '本数字3',
 '本数字4',
 '本数字5',
 '本数字6',
 'ボーナス数字',
 'キャリーオーバー_今回',
 '1',
 '2',
 '3',
 '4',
 '5',
 '6',
 '7',
 '8',
 '9',
 '10',
 '11',
 '12',
 '13',
 '14',
 '15',
 '16',
 '17',
 '18',
 '19',
 '20',
 '21',
 '22',
 '23',
 '24',
 '25',
 '26',
 '27',
 '28',
 '29',
 '30',
 '31',
 '32',
 '33',
 '34',
 '35',
 '36',
 '37',
 '38',
 '39',
 '40',
 '41',
 '42',
 '43']

目的変数には1口の賞金金額の期待値を与えます。

In [28]:
#決定木で期待値を分析
clf = tree.DecisionTreeRegressor(max_depth=5)
clf.fit(df[Exvar], df[['1口の賞金期待値']])
Out[28]:
DecisionTreeRegressor(criterion='mse', max_depth=5, max_features=None,
           max_leaf_nodes=None, min_impurity_split=1e-07,
           min_samples_leaf=1, min_samples_split=2,
           min_weight_fraction_leaf=0.0, presort=False, random_state=None,
           splitter='best')

学習結果の確認のため、feature_importanceを確認してみます。

In [29]:
pd.DataFrame(index=df[Exvar].columns, data=clf.feature_importances_).sort_values(0, ascending=False).head(10)
Out[29]:
0
本数字4 0.276258
キャリーオーバー_今回 0.174660
本数字2 0.137266
本数字6 0.089945
本数字3 0.085130
本数字1 0.070498
36 0.040758
30 0.032942
ボーナス数字 0.025772
40 0.016534

本数字4が最も影響し、次にキャリーオーバーが来ることが分かります。本数字4が来るということは、少なくとも値の大きい上位3つの数字の選び方が重要ということになります。(本数字5や6は必ず本数字4よりも大きい値になるため)

決定木を表示してみます。見やすさの都合で以下では深さ3までを表示しています。

In [30]:
# 決定木の描画
dot_data = StringIO() #dotファイル情報の格納先
tree.export_graphviz(clf, out_file=dot_data,  
                     feature_names=df[Exvar].columns,   
                     filled=True, rounded=True,  
                     special_characters=True, max_depth=3) 
graph = pydotplus.graph_from_dot_data(dot_data.getvalue()) 
Image(graph.create_png())
Out[30]:

色が濃いほど期待値が高いことを示しています。これによると最も期待値が高いノード(右端)にたどり着くためには、

  1. 本数字4を31.5以上にする。(つまり、32以上から3つの数字を選ぶ)
  2. 本数字3を30.5以上にする。(つまり、31以上から4つの数字を選ぶ)
  3. 30が本数字の2番目以上の数字になっている。(つまり、30を含めて30以上から4つ又は5つの数字を選ぶ)

を満たすことが必要で、そのときはなんと期待値が180円!!まで上がることが分かります。通常の期待値は102円ですから、約倍まで上昇しています。またこの経路にはキャリーオーバーは関係ないというのもポイント(常にこの買い方をして良い)です。

また、その2つ隣にも期待値150円というルートがありますので見てみます。これにたどり着くためには、

  1. 本数字4を31.5以上にする。(つまり、32以上から3つの数字を選ぶ)
  2. 本数字3を30.5以下にする。(つまり、30以下から3つの数字を選ぶ)
  3. キャリーオーバーが約3億7千万円以上。

を満たすことが必要で、そのときは期待値が150円!まで上がることが分かります。通常の期待値は102円ですから、これも約1.5倍まで上昇しています。ただし、こちらはキャリーオーバが絡むので、いつもできる戦略ではないです。

上記の例では、30という特定の数字の有無が出てきて少し過学習の気配があるので、特定の数字は説明変数から除いたケースでも検討してみます。

In [31]:
Exvar = df.columns[2:9].tolist() + df.columns[20:21].tolist()
display(Exvar)
['本数字1', '本数字2', '本数字3', '本数字4', '本数字5', '本数字6', 'ボーナス数字', 'キャリーオーバー_今回']
In [32]:
#決定木で期待値を分析
clf = tree.DecisionTreeRegressor(max_depth=5)
clf.fit(df[Exvar], df[['1口の賞金期待値']])
Out[32]:
DecisionTreeRegressor(criterion='mse', max_depth=5, max_features=None,
           max_leaf_nodes=None, min_impurity_split=1e-07,
           min_samples_leaf=1, min_samples_split=2,
           min_weight_fraction_leaf=0.0, presort=False, random_state=None,
           splitter='best')
In [33]:
pd.DataFrame(index=df[Exvar].columns, data=clf.feature_importances_).sort_values(0, ascending=False).head(10)
Out[33]:
0
本数字4 0.277535
キャリーオーバー_今回 0.194414
本数字2 0.161778
本数字6 0.113494
本数字3 0.093391
本数字1 0.081763
ボーナス数字 0.050853
本数字5 0.026772

特定の数字を除いたことにより、feature_importanceの傾向も少し変わっています。決定木も見ていきます。

In [34]:
# 決定木の描画
dot_data = StringIO() #dotファイル情報の格納先
tree.export_graphviz(clf, out_file=dot_data,  
                     feature_names=df[Exvar].columns,   
                     filled=True, rounded=True,  
                     special_characters=True, max_depth=3) 
graph = pydotplus.graph_from_dot_data(dot_data.getvalue()) 
Image(graph.create_png())
Out[34]:

これによると最も期待値が高いノード(右端)にたどり着くためには、

  1. 本数字4を31.5以上にする。(つまり、32以上から3つの数字を選ぶ)
  2. 本数字3を30.5以上にする。(つまり、31以上から4つの数字を選ぶ)
  3. キャリーオーバーが約1億7千万円以上。

を満たすことが必要で、そのときは期待値が160円程度まで上がることが分かります。通常の期待値は102円ですから、これも約1.5倍まで上昇しています。これもキャリオーバーが絡む買い方ですね。それ以外に関しては、あまり形状に変化がなさそうです。

上記をまとめると、1口当たりの期待値を上げるための数字の選び方として、以下のことが言えそうです。
・ なるべく大きい数字から選ぶ。具体的には、①32以上から3つ以上、又は②31以上から4つ以上の数字を選ぶ。
・ キャリーオーバの額が多い時を狙う。①の時は約4億円、②の時は約2億円以上あれば期待値は約1.5倍(1口当たり150円程度)まで上がる。
・ 過学習気味だが、②の時にさらに30を選んでいると期待値が180円!まで跳ね上がる可能性もある。

まとめ

本記事では、「loto6で期待値の高い数値の選び方はあるのか?」について分析を実施しました。当初の予想が当たっていたのか、決定木分析等で得られたルールを見ると、予想以上に(1〜31)から数字を選ばないほうがいいという結果になっており、裏を返せばカレンダ情報等から数字を選ぶ方が多い傾向が見て取れました。loto6は当選者数が少ないほど賞金が増えるシステムのですので、loto6で損をしにくくするためには、カレンダ情報から数字を選ぶときは多くとも3個まで、という考えが必要そうです。

とはいえ、期待値が上がると言っても1口の費用(200円)を超えるわけではありませんので、買えば買うほど損をしてしまうことは変わりませんので、ギャンブルはほどほどに、楽しんで遊べるといいですね!

コメントを残す

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

CAPTCHA