PR

ロードマップ4: Djangoで作る競馬予想AIモデル分析ソフト part2

DevOps
この記事は約18分で読めます。
スポンサーリンク
スポンサーリンク

はじめに

私は競馬予想プログラムソフトの制作過程を動画で投稿している者です。

ここでは、モデル分析用のWEBアプリの開発手順を話していきます。

現在作成している競馬予想プログラムソフトの概要は以下を参照ください。

スポンサーリンク

本プログラムの前提

本プログラムでは以下の前提を置いています。

  • Windows 10
  • Python3.10.5
  • Django ver5.0.4
  • 競馬予想プログラムで作成したモデルを分析する目的で使います。
  • Bookersで公開中のモデル分析管理クラスと連携してモデル分析を行います。

とりわけ、最後の2つに関しては有料記事でソースを公開しているため、まったく同じ環境で競馬予想プログラムの作成とモデルの分析を行いたい場合は以下のBookers記事一覧から記事を購入ください。

また、競馬予想プログラムの制作過程については大まかな概要は以下の再生リストから参照ください。

詳細な解説は以下の記事一覧を参照ください。

競馬予想プログラム
「競馬予想プログラム」の記事一覧です。
スポンサーリンク

モデル管理画面:モデルインポート機能の追加

今回はモデルインポート機能を作っていきます。

機能詳細

モデル管理分析クラスを用いてエクスポートされたモデル情報ファイル(model_info.json)をインポートして、モデル情報をDBへ登録する機能。

モデル管理分析クラスのエクスポートメソッドを実行する前に、学習済モデルに対して以下のメソッドをすべて実行済であること

  • self.predict
  • self.set_bet_column
  • self.basic_analyze
  • self.generate_odds_graph
  • self.generate_profit_loss

モデル管理分析クラスについては、以下の記事を参照ください。

基本的には、上記記事にあるサンプルコード通りに実行して貰えれば、問題なくエクスポートできると思います。

完成イメージ

以下のような画像の状態になることを目指します。

スポンサーリンク

インポート画面の開発

以下より、実際にソースを見せながら作り方の手順を示していきます。

settings.pyの設定

現状まだ使いませんが、なぜかこのタイミングでアプリケーション追加していたので、以下のように追加しといてください。

# app_keiba/settings.pyの編集
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'model_analyzer',
    "markdownx",  # 追加
]

models.pyの編集

今回作るインポート機能は、フォームとも呼ばれており、要するにWEBページから情報を渡すための帳票だと思ってください。

今から作成するのは、Django側がフォームから受け取るデータの受け口になります。

この受け口はModelと呼ばれており、ここで定義した内容がDBのテーブル定義となります。

from django.db import models
############# ここから下を追加 ###############
from datetime import datetime

# Create your models here.


class ModelList(models.Model):
    model_id = models.CharField(
        verbose_name="モデルID", max_length=64)
    model_name = models.CharField(
        verbose_name="モデル名", max_length=64, null=False, blank=False, default="No model name")
    model_type = models.CharField(
        verbose_name="モデル種別", max_length=64, null=False, blank=False)
    model_dir = models.CharField(
        verbose_name="モデルパス", max_length=256, null=False, blank=False)
    model_analyze_dir = models.CharField(verbose_name="分析結果パス",
                                         max_length=256, null=False, blank=False)
    model_predict_dir = models.CharField(verbose_name="推論結果パス",
                                         max_length=256, null=False, blank=False)
    bet_columns_map = models.JSONField(
        verbose_name="馬券カラムマップ", null=False, blank=False)
    pl_column_map = models.JSONField(
        verbose_name="収支カラムマップ", null=False, blank=False)
    return_hit_rate_file = models.JSONField(
        verbose_name="馬券別回収率と的中率マップ", null=False, blank=False)
    fav_bet_num_dir = models.JSONField(
        verbose_name="馬券別人気ごとベット回数マップ", null=False, blank=False)
    profit_loss_dir = models.JSONField(
        verbose_name="馬券別収支データマップ", null=False, blank=False)
    odds_graph_file = models.JSONField(
        verbose_name="馬券別オッズグラフマップ", null=False, blank=False)
    confidence_column = models.CharField(verbose_name="確信度カラム",
                                         max_length=64, null=False, blank=False)
    confidence_rank_column = models.CharField(verbose_name="確信度ランクカラム",
                                              max_length=64, null=False, blank=False)
    motivate = models.TextField(
        verbose_name="モデル説明", max_length=1024, blank=False)
    memo = models.TextField(verbose_name="備考", max_length=1024, blank=True)
    regist_date = models.DateTimeField(
        verbose_name="登録日", default=datetime.now)

    @staticmethod
    def get_serializer_field_list(exclude=["regist_date"]):
        fields_meta = ModelList._meta.get_fields()

        serialize_field_list = []
        for i, meta_field in enumerate(fields_meta):
            if i > 0 and meta_field.name not in exclude:
                serialize_field_list.append(meta_field.name)
        return serialize_field_list

    @staticmethod
    def get_forms_field_list(include=["model_name", "motivate", "memo"]):
        fields_meta = ModelList._meta.get_fields()

        forms_field_list = []
        for i, meta_field in enumerate(fields_meta):
            if i > 0 and meta_field.name in include:
                forms_field_list.append(meta_field.name)
        return forms_field_list

modelsに対応したテーブルの作成

上記のModelを作成したら、manage.pyファイルがあるフォルダがカレントディレクトリになっていること確認して、コマンドプロンプトで以下のコマンドを実行してください。

python manage.py makemigrations
python manage.py migrate

色々ログが出ますが、おまじないだと思ってください。今後もmodels.pyファイルを編集したら、必ず上記の2コマンドを実行するようにしてください。

forms.pyの作成

それでは、フォームの受け口を作ってあげたので、実際にWEB上で表示するフォームの作成をしましょう。

app_keiba/model_analyser」配下に「forms.py」ファイルを作成して、以下のコードを記載してください。

# 新規作成
from django import forms
from django.core.validators import FileExtensionValidator
from .models import ModelList


class ModelImportForms(forms.Form):
    model_name = forms.CharField(
        label="モデル名",
        required=True
    )
    motivate = forms.CharField(
        widget=forms.Textarea,
        label="モデルの説明",
        required=True
    )
    memo = forms.CharField(widget=forms.Textarea, label="備考")
    model_info_json = forms.FileField(
        label="モデル情報ファイル",
        required=True,
        validators=[FileExtensionValidator(['json', ])]
    )


class ModelListForms(forms.ModelForm):
    class Meta:
        model = ModelList
        fields = ModelList.get_serializer_field_list()

view.pyの編集

フォームの作成とモデルの作成まで完了したので、実際にHTMLソース上にフォームを表示させるために、view.pyからformデータをHTMLへ渡すようにしましょう。

以下のように編集してください。

from django.shortcuts import render
from django.views import View
from django.views.generic import FormView # 追加
from .models import ModelList # 追加
from .forms import ModelImportForms, ModelListForms # 追加
import json # 追加

# Create your views here.
~~~省略~~~

class ModelManageView(View):
   # 追加
    nav_params = {
        "model_analyze": True,
        "model_manage": False
    }

    def get(self, request):
        # print(ModelList.get_serializer_field_list())
        form = ModelImportForms()  # 追加
        self.nav_params |= {"form": form}  # 追加
        return render(request, 'model_manage.html', self.nav_params)  # 追加

   # 以下を追加
    def post(self, request):
        form = ModelImportForms(request.POST, request.FILES)
        if form.is_valid():
            model_info = json.loads(
                form.cleaned_data.pop("model_info_json").read())
            form.cleaned_data |= model_info
            model_form = ModelListForms(form.cleaned_data)
            if model_form.is_valid():
                model_form.save()
            else:
                print(model_form.errors)
                self.nav_params |= {"model_form": model_form, "form": form}
        else:
            self.nav_params |= {"form": form}

        return render(request, 'model_manage.html', self.nav_params)

HTMLソースの修正

それでは、最後にviewsから受け取ったフォームをHTMLソース上に表示させましょう。

以下のHTMLファイルを丸っとコピペしてください。

{% extends "base_layout.html" %}
{% block content %}
<div class="list-item">
    <h3>モデルインポート</h3>
    {% if form.errors %}
    <ul>
        {% for error in form.errors %}
        <li>{{ error }}</li><!--form内にエラーがある際に表示させる-->
        {% endfor %}
    </ul>
    {% endif %}
    {% if model_form.errors %}
    <h4>Upload Json File Error!!</h4>
    {{ model_form.errors }}
    {% endif %}
    <form class="" action="" method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <table>{{ form.as_table }}</table>
        <button type="submit" class="btn btn-primary">送信</button>
    </form>
</div>
{% endblock %}
スポンサーリンク

サーバの起動と画面の確認

それでは、インポート機能の追加ができたので、サーバを起動しましょう。

manage.pyファイルがあるフォルダがカレントディレクトリになっていることを確認して、コマンドプロンプトで以下のコマンドを実行

python manage.py runserver

http://localhost:8000/model-manage へアクセスしましょう。

以下の画面が表示されればOKです!

以上で、インポート機能の作成が完了です。

スポンサーリンク

(おまけ)DBの中身確認

適当にモデルをインポート

以下のmodel_info.jsonのサンプルファイルを作成しておいてください。

{
  "model_id": "first_model",
  "model_type": "lightGBM",
  "model_dir": "E:\\keiba_dev\\keiba_ai\\models\\first_model",
  "model_analyze_dir": "E:\\keiba_dev\\keiba_ai\\models\\first_model\\analyze",
  "model_predict_dir": "E:\\keiba_dev\\keiba_ai\\models\\first_model\\analyze\\00_predict",
  "bet_columns_map": {
    "tan": "bet_tan"
  },
  "pl_column_map": {
    "tan": "pl_tan"
  },
  "return_hit_rate_file": {
    "tan": "E:\\keiba_dev\\keiba_ai\\models\\first_model\\analyze\\tan\\hit_and_return_rate.csv"
  },
  "fav_bet_num_dir": {
    "tan": "E:\\keiba_dev\\keiba_ai\\models\\first_model\\analyze\\tan\\fav_bet_num"
  },
  "profit_loss_dir": {
    "tan": "E:\\keiba_dev\\keiba_ai\\models\\first_model\\analyze\\tan\\profit_loss"
  },
  "odds_graph_file": {
    "tan": "E:\\keiba_dev\\keiba_ai\\models\\first_model\\analyze\\tan\\odds_graph"
  },
  "confidence_column": "pred_prob",
  "confidence_rank_column": "pred_rank"
}

http://localhost:8000/model-manage の画面上で、適当にフォームに値を入力して、ファイル選択では先ほど作成した「model_info.json」を選択してください。

画像イメージ

入力が完了したら「送信」を押してください。

再度以下のような空のフォーム画面が映っている画像になれば、インポート成功です。

DBの中身確認

以下のフリーソフトダウンロードして、インストールしてください。DBの中身を見るために使います。(Win/Mac対応)

Downloads - DB Browser for SQLite

インストールできたら、「app_keiba/db.sqlite3」ファイルがある(manage.pyがあるフォルダと同じ場所にある)と思うので、さっきインストールしたソフトの上部のツールタブから「データベースを開く」を選択して、db.sqlite3を選択してください。

以下の画像の状態になればOKです。

重要なのは赤線を引いている箇所、これがあれば大丈夫です。

次に「データ閲覧」のタブを選択して、下記画像のようにプルダウンから矢印で示した項目を選択しましょう。

するとテーブルのデータ一覧が参照できるようになっており、先ほどインポートしたモデルがDBに反映されていることが確認できると思います。

以上で、フォームの作成完了になります。お疲れ様でした。

スポンサーリンク

ソース公開しました!

Bookersでロードマップ4で解説したソースを公開しました!

以下のリンクへ飛んでいただき、BookersとYouTube連携して私のチャンネルを登録すると無料でWEBアプリのソースが手に入ります。

無料!競馬予想AIモデル分析基盤um-AI
競馬予想プログラムソフトの開発をしている者です。今回は第一弾から第三弾記事を使って作った競馬予想モデルを分析できるWEBアプリを公開します…

良ければ、実際に触って遊んでみてください!

スポンサーリンク

前回記事

メインページの作成

スポンサーリンク

次回記事

フォームのモーダル化とレスポンス表示

コメント

タイトルとURLをコピーしました