質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.48%

Python AI 宝くじ当選番号予測 ロト7

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 6,843

score 18

pythonで機械学習、深層学習によって宝くじ当選番号予測プログラム ロト7Versionを作っています。
参考資料はこちら
(実行時は時間短縮のためself.epochsを1にしています。)

整理整頓しました。

質問
個人的にパラメータの部分がよくわからないのですが、コメントのような理解でよろしいでしょうか?self.units = 6これについては何の意味があるのか 単位?単位が6?

ロト7のcsvはこちらからダウンロードしています。ボーナス数字以下については使わないため、削除しています。

#各インポート宣言
#numpy 数値計算を効率的に行うためのライブラリ
#pandas データ分析を効率的に行うためのライブラリ
#tflearn 深層学習ライブラリ
#time 時刻に関するさまざまな関数を提供
#itertools 効率的なループ実行のためのイテレータ生成関数
#sklearn 機械学習ライブラリ
#preprocessing 前処理用のライブラリ
import numpy as np
import pandas as pd
import tflearn
import time
import itertools
from sklearn import preprocessing

#予測LSTMクラス
class PredictionLSTM:
    def __init__(self):
        #LSTM訓練パラメータ
        #steps_of_history いくつ前のデータまでを学習に用いるか
        #steps_of_history いくつ先のデータを予測するか
        #units よくわからない
        #epochs 一つの訓練データを何回繰り返して学習させるか
        #batch_size バッチサイズ
        self.steps_of_history = 10
        self.steps_of_future = 1
        self.units = 6
        self.epochs = 1
        self.batch_size = 1

     #データセット作成
    def create_dataset(self,data):
        x,y = [],[]
        for i in range(0,len(data) - self.steps_of_history,self.steps_of_future):
            a = i + self.steps_of_history
            x.append(data[i:a])
            y.append(data[a])
        x = np.reshape(np.array(x),[-1,self.steps_of_history,1])
        y = np.reshape(np.array(y),[-1,1])
        return x,y

        #予測データ作成
    def create_predict_dataset(self,data):
        latest_x = np.array([data[-self.steps_of_history:]])
        latest_x = np.reshape(latest_x,(-1,self.steps_of_history,1))
        return latest_x

    #訓練評価データ分割
    def split_dataset(self,x,y,test_size=0.1):
        pos = round(len(x) * (1 - test_size))
        train_x,train_y = x[:pos],y[:pos]
        test_x,test_y = x[pos:],y[pos:]
        return train_x,train_y,test_x,test_y

    #モデル作成
    def _create_model_by_tflearn(self):
        net = tflearn.input_data(shape=[None,self.steps_of_history,1])

        #LSTM
        net = tflearn.lstm(net,n_units = self.units)

        net = tflearn.fully_connected(net,1,activation = "linear")
        net = tflearn.regression(net,optimizer = "adam",learning_rate = 0.001,loss = "mean_square")

        model = tflearn.DNN(net,tensorboard_verbose = 0)

        return model

    #訓練
    def train(self,train_x,train_y):
        model = self._create_model_by_tflearn()
        model.fit(train_x,train_y,validation_set = 0.1,batch_size = self.batch_size,n_epoch = self.epochs)

        return model

    #予測
    def predict(self,model,data):
        return model.predict(data)

    #評価誤差アルゴリズム
    def rmse(self,y_pred,y_true):
        return np.sqrt(((y_true - y_pred) ** 2).mean())

    def rmsle(self,y_pred,y_true):
        return np.sqrt(np.square(np.log(y_true + 1) - np.log(y_pred + 1)).mean())

    def mae(self,y_pred,y_true):
        return np.mean(np.abs((y_true - y_pred)))

    def mape(self,y_pred,y_true):
        return np.mean(np.abs((y_true - y_pred) / y_true)) * 100

#メイン処理
if __name__ == "__main__":

    #処理の速さを図る
    START_TIME = time.time()

    #1~37までの数字を用意
    a = {m for m in range(1,38)}
    d = {tuple(p): i for i, p in enumerate(itertools.combinations(a,7))}
    e = {v: k for k, v in d.items()}

    dataframe = pd.read_csv("./loto7.csv",encoding='cp932')
    dataframe = dataframe[["第1数字","第2数字","第3数字","第4数字","第5数字","第6数字","第7数字"]]
    data = dataframe.index.map(
        lambda _:d[ tuple(sorted(
            [(dataframe.第1数字[_]),
            (dataframe.第2数字[_]),
            (dataframe.第3数字[_]),
            (dataframe.第4数字[_]),
            (dataframe.第5数字[_]),
            (dataframe.第6数字[_]),
            (dataframe.第7数字[_])
            ]
            ))
            ]
        )
    data = data.values.reshape(data.shape[0], 1).astype(dtype=np.float32)

    #正規化
    #データが0~1に入るよう変換
    #fit_transform()について
    #fit()を実施した後に、同じデータに対してtransform()を実施する
    #fit()とは
    #渡されたデータの最大値、最小値、平均、標準偏差、傾き...などの統計を取得して、内部メモリに保存する
    #transform()とは
    #fit()で取得した統計情報を使って、渡されたデータを実際に書き換える
    scaler = preprocessing.MinMaxScaler()
    data = scaler.fit_transform(data)

    #LSTMインスタンス作成
    lstm = PredictionLSTM()

    #訓練,評価データ作成
    #create_datasetの処理を正規化したデータを用いてx,yに代入
    #split_datasetの処理をx,yを用いて訓練、評価データに代入
    x,y = lstm.create_dataset(data)
    train_x,train_y,test_x,test_y = lstm.split_dataset(x,y)

    #訓練
    #trainの処理を作成したtrain_x,train_yを使って行い、結果をmodelに代入
    model = lstm.train(train_x,train_y)

    #評価
    #訓練予測にpredictの処理を訓練したデータとtrain_xを用いて行う
    #評価予測にpredictの処理を訓練したデータとtest_xを用いて行う
    train_predict = lstm.predict(model,train_x)
    test_predict = lstm.predict(model,test_x)

    #RMSE(Root Mean Squared Error) この値が小さければ小さいほど、誤差の小さいモデルである
    #訓練誤差にrmseの処理をtrain_yと訓練予測データを用いて行う
    #評価誤差にrmseの処理をtest_yと評価予測データを用いて行う
    #Train ScoreとTest Scoreを出力
    train_score = lstm.rmse(train_y,train_predict)
    test_score = lstm.rmse(test_y,test_predict)
    print("Train Score: {0:.3f} RMSE".format(train_score))
    print("Test Score: {0:.3f} RMSE".format(test_score))

    #予測
    #latest_xにcreate_predict_datasetの処理を正規化したデータを用いて行う
    #次の予測に訓練データをlatest_xを用いて行う
    #予測に正規化のinverse_transformを”次の予測”を用いて行う
    latest_x = lstm.create_predict_dataset(data)
    next_prediction = model.predict(latest_x)
    next_prediction = scaler.inverse_transform(next_prediction)
    #予測結果を出力
    print("次の当選番号の予測は: {}".format(e[np.round(next_prediction[0][0])]))

    #測定時間を出力
    print("時間: {0:.1f}sec".format(time.time() - START_TIME))
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • toast-uz

    2020/09/24 21:10

    質問は1投稿で1つにして、質問に関係ある範囲に絞りかつ実行可能で問題を再現可能なコードを提示いだたくと、回答がつきやすいと思います。

    キャンセル

  • EDM

    2020/09/25 09:11

    意見ありがとうございます。見直してみます。

    キャンセル

回答 1

checkベストアンサー

+2

”csvを読み込んだ後に頭に一桁があれば0をつける”
こちらをプログラムで行うにはどのようにすればいいのでしょうか。

はい、こちらになります。

data = dataframe.index.map(lambda _:int(str(dataframe.第1数字[_]).zfill(2) + str(dataframe.第2数字[_]).zfill(2) + str(dataframe.第3数字[_]).zfill(2) + str(dataframe.第4数字[_]).zfill(2)) + str(dataframe.第5数字[_]).zfill(2) + str(dataframe.第6数字[_]).zfill(2) + str(dataframe.第7数字[_]).zfill(2)))

しかし、これを行なっても、正しいこたえは得られません。

コピペ元のプログラムをきちんと読みましょう。

元のプログラムは、どのようにしてこたえを導いていますか?

元のプログラムは、3つの数字データを元に予測するものですが、
日本で発売されている数字選択式全国自治宝くじのひとつである「NUMBERS3」が使う各数字が
0〜9で成り立っていることを奇貨として、
3つの数を10進法で最大3桁となる整数yに変換し、各時点xに対するyを線形にプロットしたグラフを分析・予測するものです。

イメージしやすい言い方をすれば、000から999の数字が書かれた「1000面体のサイコロ」を振って出た目の過去の記録を分析して、次に振って出る目を予測しているのです。(実際は実数で計算しているので語弊はありますが)

一方、LOTO7は1から37までの数字を7つ、重複なしに選択するものです。

したがって、仮に上記のように2桁で区切ってデータを与えても、
内部では、(データによるが)最大で37363534333231までの数が書かれたサイコロを仮定して出る目を予測することになってしまい、 実際に存在するパターン以外のパターンまで計算に使う可能性があるため、
正しそうな答えを導くことはできないのではないでしょうか。

そこで、ロト7の全パターンを、10進数に線形にあてはめた数字をデータとして投入する、というやり方になるかもしれませんね。

    import itertools
    a = [m for m in range(37)]
    #137の数字の組み合わせパターンを登録
    d = {tuple(p): i for i, p in enumerate(itertools.combinations(a, 7))}
    e = {v: k for k, v in d.items()}

    #パターンをキーとしてインデックスをマッピングする。
    data = dataframe.index.map(
        lambda _:d[ tuple(sorted(
           [(dataframe.第1数字[_])-1 , 
            (dataframe.第2数字[_])-1 , 
            (dataframe.第3数字[_])-1 , 
            (dataframe.第4数字[_])-1 , 
            (dataframe.第5数字[_])-1 , 
            (dataframe.第6数字[_])-1 , 
            (dataframe.第7数字[_])-1
           ]
           ))
        ]
    )
---------------------------------
Run id: ;;;;;;
Log directory: /tmp/tflearn_logs/
---------------------------------
Training samples: 304
Validation samples: 34
--
Training Step: 304  | total loss: 0.08920 | time: 2.274s
| Adam | epoch: 001 | loss: 0.08920 | val_loss: 0.04319 -- iter: 304/304
--
Train Score: 0.216 RMSE
Test Score: 0.187 RMSE
次の当選番号の予測は: 5597193.5
Time: 3.3sec 


で、あとは出てきたnext_prediction(上で言えば「5597193.5」)を、求めるべきこたえに戻せばよい。

戻し方を明かしちゃうと勉強にならないので、明日までに考えてみてください。

next_prediction[0][0]は予測されたインデックスを表しているのですから、
単純に次のようにすればよいと思います。

from decimal import Decimal, ROUND_HALF_UP
n0 = next_prediction[0][0]
n1 = Decimal(str(n0))
n2 = n1.quantize(Decimal('0'), rounding=ROUND_HALF_UP)
print("次の当選番号の予測は: {}".format(e[n2]))


※私は数学に詳しくないので、このアプローチが本当に正しい答えを導くかどうかについては保証しません。
あくまでコピペ元のプログラムのアプローチを生かす形での、正しそうな答えを導くためのショートカットを示しただけです。
(組み合わせをマッピングしたインデックスのトレンドが、組み合わせの予測に使えるかといわれれば、大いに疑問)
たぶん、各数字の出現頻度等を考慮した、もっとまっすぐなアプローチをご存知の方がいるはず。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/09/29 11:58 編集

    roundですが私のバージョンがpython3なので、五捨五入、銀行丸めになってしまうのでnp.roundにしました。

    マッピングするときの-1はどういう意図ですか?
    つけるとkeyerrorになってしまうため、つけていません。

    キャンセル

  • 2020/09/29 21:19 編集

    roundについて全く抜けていました。ありがとうございます。
    ただ np.roundも銀行家の丸めになってしまうとの記載が他サイトでありました。(https://www.sejuku.net/blog/70052)。 https://www.mathpython.com/ja/python-number-round/ を参考に直しました。

    マッピングで-1をする意味ですが、組み合わせテーブルを作るときに。range(37)としており、0〜36
    までの数で組み合わせを作成していることによります。

    テーブル上の0は、loto7の実際の数の1に対応、テーブル上の1はloto7の2に対応・・・となっています。
    したがって、−1することで、テーブルのインデックスと対応させている、ということになります。

    結局私が回答の中でやっていることと、EDMさんが編集した後のソースは、内容は全く同じことになります。
    私のコードは回りくどいため、直感的にわかりやすい(バグもうみにくい)という意味では、EDMさんの書き方の方が優れていると思います。

    キャンセル

  • 2020/09/30 11:05

    回答ありがとうございます。
    np.roundも銀行丸めになってしまうのですね。改善します。
    -1の説明についてもありがとうございます。そのような意図だったのですね。理解できました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る