ビジネスパーソン・ガジェット置場 empty lot for business

営業や仕事、それに伴う生活を便利に楽にするツール、ガジェットを作ります。既にあるツールも自分用にカスタマイズ。

Numbers3 予測アプリ【python + streamlit】

Numbers3を過去のデータを元にストレートの予測を行います。(予測のアルゴリズムはとても簡易なものなので、当たるも八卦当たらぬも八卦です)過去のデータはpaypay銀行からいただいております。過去のデータを見ると複数回同じ数字が出るということは少ないようです。

例えばこんな状況で

今回のガジェットはこういう声に対応
「ナンバーズ、過去のデータを調べてたらきっと当たるはず!過去のデータを調べてそこから当選番号を導き出すのだ!」(本当は毎回同じ確率であるはずですよね。ただ、可能性として抽選機の何らかの癖がその確率に影響していることもあるのかな)

このガジェットでできることはこちら

  • ナンバーズ3の過去の当選結果をまとめております。
  • 表示している項目はかこに複数回同じ数字がでた回数
  • それぞれのシングル数字の出現回数
  • 2020年3月〜のデータでまだ出現していない数字一覧
  • 今回の予測数字(複数)
  • 次回の予測
  • 今回の当選結果の入力とデータベースの更新

注意点はこちら

今回は自動でデータを取得させていません。またデータを複雑にしてしまったので、関数が若干入り組んでいます。

 

評価(自己)

役立ち度  ★★★(平均)
効率化   ★★(悪し)
ミス防止  ★★★(平均)
楽しさ   ★★★★(良し)
操作性   ★★(悪し)

当選番号を自動で取得していないため手動で入力する必要があり効率化はしておりません。また、1日のデータは1度だけしか更新できないようになっているため操作性もあまり良くありません。

実行環境

使用環境    streamlit 
使用言語    python
使用ライブラリ pandas、numpy、random、collections、datetime、jpholiday

 

コード

import pandas as pd
import numpy as np
import random
import collections
import datetime
import jpholiday
import streamlit as st

st.title('Numbers3 予測アプリ')

# データを読み込んで各数字の出現回数win_timesを返す
def num_appearance():
    win_nums = pd.read_csv('抽選数字.csv')
    
    # 各数字の出現回数
    win_times = win_nums.groupby('number').count()
    win_times = win_times.reset_index(drop=False)
    win_times.sort_values('date', ascending=False)
    return win_times

# 当選回数集計データフレーム(elected_df)を返す関数
def agg_result(win_times):
   # 最高出現回数
    max = win_times['date'].max()
    # 各出現回の数字の個数
    elected_num = {}
    while max >0:
        elected_num[f'{str(max)}回'] = len(win_times[win_times['date']==max])
        max -= 1
    elected_df = pd.DataFrame(elected_num, index=[0])
    # 平均出現回数
    elected_df['平均(回)'] = round(win_times['date'].mean(), 2)
    elected_df = elected_df.rename(index={0: '個数'})
    return elected_df

def single_num_appearance(win_times):
    # 各シングル数値の出現回数
    str_number = win_times['number'].values.astype(str)
    single_num = []
    for i in str_number:
        if len(i) == 1:
            single_num.append(0)
            single_num.append(0)
            single_num.append(int(i))
        elif len(i) == 2:
            single_num.append(0)
            single_num.append(int(i[0]))
            single_num.append(int(i[1]))
        else:
            single_num.append(int(i[0]))
            single_num.append(int(i[1]))
            single_num.append(int(i[2]))

    num_dict = {}
    for i in range(10):
        num_dict[f'{i}'] = single_num.count(i)
    single_num_df = pd.DataFrame(num_dict, index=[0])
    single_num_df = single_num_df.rename(index={0: '回数'})
    return single_num_df

# 未出現の数字をリスト化(3/20時点の600個以下と推定)
def get_unelected_num():
    unelected_num = [i for i in range(1000) if i not in win_times['number'].values]
    # 600個に満たない場合*を追加して個数を600個にする
    while len(unelected_num) < 600:
        unelected_num.append('*')
    return unelected_num

# 未出現の数字をマトリックス化(3/20時点の600個以下と推定)
def get_matrix(unelected_num):
    # numpyのarray型にしてデータフレーム化する
    _matrix = np.array(unelected_num).reshape(20, 30).T
    matrix = pd.DataFrame(_matrix)
    return matrix

def show_predict():
    show_df = pd.read_csv('予測.csv', index_col=[0])
    return show_df
    
    

# 翌抽選日を求める関数
def returnBizDay(DATE):
    Date = datetime.date(int(DATE[0:4]), int(DATE[5:7]), int(DATE[8:10]))
    Date = datetime.date(Date.year, Date.month, Date.day + 1)
    while Date.weekday() >= 5 or jpholiday.is_holiday(Date):
        Date = datetime.date(Date.year, Date.month, Date.day + 1)
    return Date.strftime("%Y/%m/%d")

def get_predict(date, unelected_num):
    # 100回抽選実施しリストに格納
    predict_list = []
    for i in range(100):
        predict = random.choice(unelected_num)
        if predict == '*':
            continue
        else:
            predict_list.append(predict)
    # 抽選結果を出現回数にまとめてデータフレームを作成
    c = collections.Counter(predict_list)
    predict_df = pd.DataFrame(c, index=[0]).T
    predict_df.columns = ['回数']
    predict_df = predict_df.sort_values('回数', ascending=False).reset_index(drop=False).rename(columns={'index': 'number'})
    predicted = predict_df[predict_df['回数']==predict_df['回数'].max()]
    predicted = predicted.drop('回数', axis=1).T.rename({'number': date})
    return predicted


# データフレームを更新する関数
def update_data(win_date, win_num):
    win_nums = pd.read_csv('抽選数字.csv')
    _win_nums = pd.DataFrame({'date': win_date, 'number': win_num}, index=[0])
    win_nums = pd.concat([win_nums, _win_nums], ignore_index=True)
    win_nums = win_nums.sort_values('date')
    win_nums.to_csv('抽選数字.csv', index=False)
    


win_times = num_appearance()
elected_df = agg_result(win_times)
single_num_df = single_num_appearance(win_times)
unelected_num = get_unelected_num()
matrix = get_matrix(unelected_num)
show_df = show_predict()
win_num = None

st.write('★当選回数内訳')
st.table(elected_df)

st.write('★各シングル数字の出現回数')
st.table(single_num_df)

st.write('★未出現の数字リスト')
st.dataframe(matrix)

st.write('★今回のナンバーズ予測')
st.dataframe(show_df)

win_date = st.sidebar.text_input('抽選日を入力してください', placeholder='YYYY/mm/dd')
win_num = st.sidebar.text_input('当選番号を入力してください', value='')


if win_num != '':
    if int(win_num) in show_df.values:
        # print(win_num)
        # print(show_df.values)
        st.write('### !!!!当選!!!!')
    else:
        st.write('### 。。。ハズレ。。。')

if st.button('次回予測'):
    DATE = win_date
    date = returnBizDay(DATE)
    predicted = get_predict(date, unelected_num)
    predicted.to_csv('予測.csv')
    st.write('★次回のナンバーズ予測')
    st.dataframe(predicted)

st.write('今回の当選結果データをバックデータに反映させますか?')
if st.button('YES'):
    update = update_data(win_date, win_num)