2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🎯Numbers3&4の当選番号を予測する『MAGI』システムを作る - モデル構築編(MELCHIOR)

Posted at

1. はじめに

どうも、趣味でデータ分析している猫背なエンジニアです。

え~宝くじで一攫千金したくないですか?
宝くじの当選番号を予測するシステムを長年愛してやまない『新世紀エヴァンゲリオン』に登場するMAGIシステムをコンセプトに、つくりたい!そうしたい!と思って開発記録を書いていきます。この記事ではモデル構築編の第一弾と題し『MELCHIOR』を紹介します。

2. これまでの「🎯Numbers3&4の当選番号を予測する『MAGI』システムを作る」

これまでのエヴァンゲリオン.png

西暦2025年。
あるエンジニアは、繰り返される敗北の記録——「宝くじの外れ券」の山に終止符を打つべく、ひとつの意思決定機構を構築する決意を固めた。
その名は―― N-MAGIシステム。
モデル名はMELCHIOR、BALTHASAR、CASPER。
それぞれが異なる思考ロジックを持ち、合議によって“もっともらしい当選数字”を導き出す。
ベースとなったのは、かつて存在した神話と、そして…アニメ『新世紀エヴァンゲリオン』の意志決定AI。
過去のデータ、時系列学習、出現頻度、逆張りアルゴリズム。それらを融合させ、抽選数字の予測という“人類補完計画”にも似た夢を追い求める開発者の姿があった。

すべては「当てたい」という欲望と、「遊びたい」という本能のままに。

っていう茶番はおいといて...本編に入ります👍

3. MELCHIORのモデル選定(復習)

概要編の4.MAGIを構成する3つの『脳』の選定でモデルの説明をしました。振り返りですが、MELCHIORの人格は科学者とされ、独自解釈ではAI予測型(時系列学習モデル)としていました。今回の実装では、時系列学習モデルとしてLSTM(Long Short-Term Memory)を選定しました。実は前から気になっていたモデルでした。

< 選定モデル LSTM とは?>

LSTMはRNNの一種で、時系列データを扱うのが得意なニューラルネットワーク(NN)です。
LSTMは、これまでのデータの流れを記憶しながら処理できる仕組みを持っています。

モデルイメージング メモ
人間の脳も過去の出来事をある程度覚えていて、それをもとに次の行動を決めたりする。
音楽を聴いているときに次にどんなメロディが来るか予想できるときがあるのは「これまで聞いた流れを覚えている」からであり、この部分が似ている。

普通のネットワークは、データを1回きりでしか扱えませんが、本モデルは「前の情報を保持しながら、次のデータを処理」できます。例えば、株価の推移をみて、明日の値動きだったりね。

この「過去から未来を読む」タスクに向いているのがLSTM最大の特徴。

< LSTMの仕組み >

NNと書いているように人間のニューロンに似ていることは間違いなく、同じように「覚える・忘れる・出力する」の仕組みを使って、情報の出入りをコントロールしている。ということはわかった。

※まだまだ勉強中であるためリンクから詳しい情報を受け取ってほしい。

4. いざ開発:MELCHIORによるNumbers4時系列予測モデルの構築

本節では、Numbers4の過去当選データをもとに、LSTMを用いた予測モデル “MELCHIOR” の設計および実装プロセスについて詳細に述べる。

4.1 データ前処理

本モデル(MELCHIOR)では、Numbers4の各当選番号(4桁)を単なる整数値としてではなく、「千の位」「百の位」「十の位」「一の位」 という4つの桁情報に分解して処理を行う。この処理により、各桁ごとの数字の出現傾向や周期性を個別に学習可能な系列データとして扱うことができるようになる。

✂️ なぜ桁分解するのか?

Numbers4は「0000」〜「9999」までの10,000通りから抽選されるが、4桁すべての数字が等しくランダムに振る舞っているとは限らない。実際の出現履歴を観察すると、桁によって偏りや傾向が見られる場合がある。
そこで、1つの4桁の番号を1つの時系列として扱うのではなく、各桁(千・百・十・一)をそれぞれ独立した時系列データとして分割することで、それぞれの桁が持つ規則性を、より細かく学習させる。
こうした 「桁別の性格」 を LSTM に学習させることにより、全体として1つの4桁の番号を予測する際に、より精度の高い・理由のある予測を生成できる構造になっている。

digits = pd.DataFrame({
    "thousands": df["number4"].str[0].astype(int),
    "hundreds":  df["number4"].str[1].astype(int),
    "tens":      df["number4"].str[2].astype(int),
    "units":     df["number4"].str[3].astype(int),
})

4.2 正規化処理

LSTMなどのRNN系モデルは、入力データのスケール(値の大きさ)に非常に敏感であり、値の範囲が異なると勾配消失や学習の不安定性を引き起こす可能性があります。そのため、本モデルでは、各桁(千・百・十・一)に分解された時系列データを、それぞれ独立に前処理としてスケーリング(正規化)しています。

スケーリング手法:MinMaxScaler

各桁の数字(0〜9)は本質的には同じスケールを持っていますが、出現分布や偏りが異なる可能性があるため、桁ごとに別々のスケーリングを実施します。ここでは sklearn.preprocessing.MinMaxScaler を使用して、各桁の値を[0, 1]の範囲に線形変換しています。

scalers = {col: MinMaxScaler() for col in digits.columns}
scaled_digits = pd.DataFrame({
    col: scalers[col].fit_transform(digits[[col]]).flatten()
    for col in digits.columns
})

スケーリングの逆変換(予測後の処理)

予測結果は [0, 1] のスケール上で出力されるため、そのままでは実際の数字として解釈できません。そこで、学習前に記録した MinMaxScaler の情報をもとに、各桁の予測値を元のスケール(0〜9)に戻す逆変換を行います。この処理によって、モデルの出力は実際の桁データ(0〜9)の範囲に正確に復元され、最終的な4桁の予測番号として統合可能になります。

pred = scalers[digit].inverse_transform(pred_scaled.reshape(-1, 1))

このようにスケーリングと逆スケーリングを組み合わせることで、学習時の安定性と、予測後の可読性の両立を実現しています。LSTMを用いた時系列予測では、こうした前処理が極めて重要な役割を果たします。


4.3 時系列データ構築

時系列モデルでは、「未来の値」を予測するために、「過去の一定期間のデータ(履歴)」をモデルに入力する必要があります。この一定期間の履歴を「時系列ウィンドウ(sequence window)」と呼び、以下のような構造になります。
また、この手法はスライディングウィンドウ法と呼ばれ、1つの時系列から多数の「(履歴, 予測値)」のペアを作り出すことができます。

  • data: 1次元の時系列データ(例:0.0〜1.0に正規化された1桁の数字列)
  • seq_length: 何ステップ前までを使うか(例:300)
def create_sequences(data, seq_length):
    X, y = [], []
    for i in range(len(data) - seq_length):
        X.append(data[i:i+seq_length])      # 過去 seq_length 個の系列を特徴量として抽出
        y.append(data[i+seq_length])        # その直後の値を教師データとする
    return np.array(X), np.array(y)

処理の流れ

  1. data[i:i+seq_length]:インデックスiからi+seq_length-1までのデータを1つの「ウィンドウ」としてXに格納
  2. data[i+seq_length]:その直後の値を正解ラベル y に追加
  3. これを i = 0 から len(data) - seq_length - 1 まで繰り返す

例:seq_length=5 の場合のスライディング動作

i 入力(X) 予測対象(y)
0 [x₀, x₁, x₂, x₃, x₄] x₅
1 [x₁, x₂, x₃, x₄, x₅] x₆
2 [x₂, x₃, x₄, x₅, x₆] x₇

なぜ 300 にしているのか?

この設定により、直近300回分の当選結果(ある桁の値)をもとに、次の回の同じ桁の値を予測します。宝くじのようにランダム性が強いとされるデータであっても、出現傾向や周期性などが潜在的にある場合、LSTMがそのパターンを学習する可能性があるという仮説に基づいています。LSTMは記憶力が高いため、長めの履歴を与えることでその力を最大限に活かす構成となっています。

seq_length = 300

出力

この関数は、モデルに渡すための訓練データ X(shape: [サンプル数, 300]) とラベル y(shape: [サンプル数])をNumPy配列で返します。

return np.array(X), np.array(y)

以下に、あなたの提示された LSTM モデル構造 4.4 LSTMモデル設計 を、研究・技術記事風に詳しく説明します:


4.4 LSTMモデル設計(詳細解説)

本モデルでは、桁ごとの時系列データから次の数字(0〜9)を予測するために、多層LSTMアーキテクチャを採用している。構成は以下のとおり。

モデル全体構成
model = Sequential([
    Input(shape=(seq_length, 1)),
    LSTM(64, return_sequences=True),
    Dropout(0.2),
    LSTM(32),
    Dropout(0.2),
    Dense(1)
])
model.compile(optimizer='adam', loss='mse')

各層の設計意図

層種別 設定内容 説明
Input層 shape=(300, 1) 1次元の時系列データ(300ステップ)を入力とする。
LSTM層① LSTM(64, return_sequences=True) 64個の記憶セル。
次層LSTMへ系列出力するため return_sequences=True
Dropout① Dropout(0.2) 過学習防止のため20%のユニットをランダム無効化。
LSTM層② LSTM(32) 出力側の圧縮層。32ユニットで時系列の要約を抽出。
Dropout② Dropout(0.2) 同様に過学習対策。
出力層 Dense(1) 次に出現する1桁の数字(連続値)を出力。

損失関数と最適化

  • optimizer: Adam

    • 学習率調整と収束の早さに優れた最適化手法。
  • loss: mean_squared_error(MSE)

    • 回帰問題で最も一般的に使用される損失関数。
    • 数値予測(0〜9)で誤差の二乗を最小化する。
model.compile(optimizer='adam', loss='mse')

モデル出力について

出力はスカラー(連続値)であり、0.0〜9.0 の範囲を取り得る。予測値は np.round() で四捨五入し、int() に変換。さらに min/max 処理で 0〜9 にクランプし、実際の1桁数字として解釈している。

pred_digit = int(np.round(pred[0][0]))
pred_digit = max(0, min(9, pred_digit))

4.5 学習と予測

  • 各桁(千・百・十・一)ごとに独立してモデル学習を行う。
  • 予測は scaled_digits[digit].values[-seq_length:] を入力として実行。
  • 出力結果は inverse_transform() によって復元後、四捨五入し 0〜9 の整数値に丸める。
  • 最終的に4桁を結合して1つの予測番号とする。
pred_digit = int(np.round(pred[0][0]))
pred_digit = max(0, min(9, pred_digit))  # 範囲制限

4.6 出力形式と実行回数

本モデルでは、1回の関数実行に対して2件の4桁予測番号を生成する設計となっている。これは、宝くじのように完全な未来予測が困難であり、「多様な候補を提示する」ことを重視しているためである。
このループでは、1ループ=1つの4桁予測番号の生成を意味する。ループは固定で2回回すように設計しており、結果として ['0839', '2174'] のような2つの予測値リストが出力され、X上では上位1つを表示している。

for _ in range(2):  # 2つの予測番号を生成
    ...
    predictions.append(predicted_number)

5. 予測結果と考察 ~MAGIは何を見る?~

ここまでで、MELCHIORモデルの構築・設計思想・データ処理・学習構造について詳細に見てきました。では、実際に本モデルが出力する「未来の4桁予測番号」とは、どのようなものなのでしょうか?
以下に直近のものを提示します。(7/16に予測した次回(7/17)の当選番号)

NUMBERS4
image.png
NUMBERS3
image.png

MELCHIORの出力をどう扱うか

「絶対的な正解」ではなく、あくまで候補提示型AIとして捉えると、本モデルの意図が明確になります。

今後の改善・拡張の方向性

本実装はシンプルなLSTM構成を採用していますが、さらなる精度向上や面白さを追求します。

  • 複数桁を同時にマルチタスク学習させる構成
  • 外部情報(曜日・月・過去ヒット傾向など)を特徴量として追加
  • 出力に確率・スコアを付与して信頼度順でランキング表示
  • そもそもモデルを変えてみる....遺伝的アルゴリズムとか(笑)

6. 次回予告

次回予告_BALTHASAR.png

哲学はきっと数字で表現できるはず。

10. 今後の記事予定(MAGI伝記)

1. 【作戦概要】:全体構想と設計方針
  - 全体構想と設計方針
2. 【データ収集編】:過去の当選番号の収集
  - 過去の当選番号をどう集める?
3. 【モデル構築編】:3種のモデル(CASPER / BALTHASAR / MELCHIOR)実装と精度比較
  - CASPER / BALTHASAR / MELCHIORの実装と精度比較
4. 【投稿編】:X APIを用いた投稿
  - X APIを用いて予測を自動投稿
5. 【UI&演出編】:MAGI風UIをTkinterで再現して、予測を視覚化!
  - TkinterでMAGI風UIを構築

謝辞

今年の10月に30周年を記念すること、誠におめでたく思っております。前回の「庵野秀明展」に引き続き「30周年記念展ALL OF EVANGELION」にもぜひ行きたいと思っております。引き続き応援しています!

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?