東風と半荘の基礎データ比較

2023/5/5

東風戦と半荘戦の副露率がどれくらい違うか知りたかったけどぱっと見データが見当たらなかったので自分で調べた。

サンプル:2019年の四鳳東喰赤と四鳳南喰赤の約2000ゲームをランダムサンプリング
 

東風半荘t検定(p値)
ゲーム数19771998
局数5.65110.655
和了率0.2170.2120.097
放銃率0.1290.1250.074
リーチ率0.1650.1770.000
副露率0.3770.3370.000
副露回数3.2025.336
副露回数/局数0.5700.499
流局率0.1400.1560.000

天鳳の公式のデータを見ていても小数点以下3桁目くらいはぶれてそう。
リーチ率、副露率、流局率は有意に違う。副露率が上がるとリーチ率は下がるし流局率も下がりそうだから納得か。まぁその理屈だと和了率も差があってよさそうだけど……。
結局副露率は4%くらい違った!自分の普段の副露率+4%くらいを目安にしてみるか……。
東風戦は半荘戦における平場の南1と言われることもあり、半荘でも東風でも、局が進むごとに大雑把には副露率が上がる傾向があるかもしれない。そのあたりも調べたいかも。

あとは平均打点とか和了巡目とかも変わりそう。

 
追記に特に意味もなくGoogle Colaboratoryで動くコードをおいておきます。なぜかrequestでmjlogの中身をとってこれなくてseleniumを使ったのが大変だった。

# module
 
!pip install tqdm
!pip install japanize-matplotlib
 
import os
import pickle
import random
import re
import time
 
import japanize_matplotlib
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from scipy import stats
import tarfile
from tqdm import tqdm
import xml.etree.ElementTree as ET
 
# selenium準備
 
%%shell
 
cat > /etc/apt/sources.list.d/debian.list  /etc/apt/preferences.d/chromium.pref 
    def calc_game_data(self, folder_path):
        for file in os.listdir(folder_path):
            # ゲーム開始
            xml_data = ET.parse(os.path.join(folder_path, file))
            root = xml_data.getroot()
            Data.set_game_data(self)
            Data.set_kyoku_data(self)
            for child in root:
                # 局開始
                if child.tag=="INIT":
                    self.kyoku_num += 1
                    Data.cumsum_kyoku_data(self)
                    Data.set_kyoku_data(self)
                elif child.tag=="N":
                    self.furo_boolen_kyoku_array[int(child.attrib["who"])] = 1
                    self.furo_num_kyoku_array[int(child.attrib["who"])] += 1
                elif child.tag=="REACH":
                    if child.attrib["step"]=="2":
                        self.reach_kyoku_array[int(child.attrib["who"])] = 1
                elif child.tag=="AGARI":
                    self.agari_kyoku_array[int(child.attrib["who"])] = 1
                    self.agari_point_kyoku_array[int(child.attrib["who"])] = int(child.attrib["ten"].split(",")[1])
                    if child.attrib["who"]==child.attrib["fromWho"]:
                        self.tsumo_kyoku_array[int(child.attrib["who"])] = 1
                    else:
                        self.hoju_kyoku_array[int(child.attrib["fromWho"])] = 1
                    if "owari" in child.attrib:
                       break
                elif child.tag=="RYUUKYOKU":
                    self.ryukyoku_num += 1
                    if "owari" in child.attrib:
                       break
            if self.kyoku_num!=0:
                Data.cumsum_kyoku_data(self)
                Data.aggregate_data(self)
 
tonpu_data = Data()
tonpu_data.calc_game_data(folder_path_tonpu)
hantyan_data = Data()
hantyan_data.calc_game_data(folder_path_hantyan)
 
pd.DataFrame(list(
    zip(
        [
            len(tonpu_data.kyoku_num_array),
            "{:.3f}".format(np.mean(tonpu_data.kyoku_num_array)),
            "{:.3f}".format(np.mean(tonpu_data.agari_rate_array)),
            "{:.3f}".format(np.mean(tonpu_data.hoju_rate_array)),
            "{:.3f}".format(np.mean(tonpu_data.reach_rate_array)),
            "{:.3f}".format(np.mean(tonpu_data.furo_rate_array)),
            "{:.3f}".format(np.mean(tonpu_data.furo_num_array)),
            "{:.3f}".format(np.mean(tonpu_data.furo_num_per_kyoku_array)),
            "{:.3f}".format(np.mean(tonpu_data.agari_point_array[tonpu_data.agari_point_array!=0])),
            "{:.3f}".format(np.mean(tonpu_data.ryukyoku_rate_array))
        ],
        [
            len(hantyan_data.kyoku_num_array),
            "{:.3f}".format(np.mean(hantyan_data.kyoku_num_array)),
            "{:.3f}".format(np.mean(hantyan_data.agari_rate_array)),
            "{:.3f}".format(np.mean(hantyan_data.hoju_rate_array)),
            "{:.3f}".format(np.mean(hantyan_data.reach_rate_array)),
            "{:.3f}".format(np.mean(hantyan_data.furo_rate_array)),
            "{:.3f}".format(np.mean(hantyan_data.furo_num_array)),
            "{:.3f}".format(np.mean(hantyan_data.furo_num_per_kyoku_array)),
            "{:.3f}".format(np.mean(hantyan_data.agari_point_array[hantyan_data.agari_point_array!=0])),
            "{:.3f}".format(np.mean(hantyan_data.ryukyoku_rate_array))
        ],
        [
            "",
            "",
            "{:.3f}".format(stats.ttest_ind(tonpu_data.agari_rate_array, hantyan_data.agari_rate_array)[1]),
            "{:.3f}".format(stats.ttest_ind(tonpu_data.hoju_rate_array, hantyan_data.hoju_rate_array)[1]),
            "{:.3f}".format(stats.ttest_ind(tonpu_data.reach_rate_array, hantyan_data.reach_rate_array)[1]),
            "{:.3f}".format(stats.ttest_ind(tonpu_data.furo_rate_array, hantyan_data.furo_rate_array)[1]),
            "",
            "",
            "",
            "{
:.3f}".format(stats.ttest_ind(tonpu_data.ryukyoku_rate_array, hantyan_data.ryukyoku_rate_array)[1])
        ]
    )), 
    index=["ゲーム数", "局数", "和了率", "放銃率", "リーチ率", "副露率", "副露回数", "副露回数/局数",
           "平均和了点数", "流局率"],
    columns=["東風", "半荘", "t検定"])
 
fig = plt.figure(figsize=(12,6))
plt.rcParams["font.size"] = 18
ax = plt.subplot(111)
# plt.ylim(0, 80)
ax.hist(tonpu_data.agari_rate_array,  bins=50, color="b", alpha = 0.5, label="東風")
ax.hist(hantyan_data.agari_rate_array, bins=50, color="g", alpha = 0.5, label="半荘")
#軸設定
ax.legend()