libs.commands.ranking.ranking
libs/commands/results/ranking.py
1""" 2libs/commands/results/ranking.py 3""" 4 5import re 6 7import pandas as pd 8from tabulate import tabulate 9 10import libs.global_value as g 11from cls.types import GameInfoDict 12from libs.data import aggregate, loader 13from libs.functions import message 14from libs.utils import formatter 15 16 17def aggregation() -> tuple[str, dict]: 18 """ランキングデータを生成 19 20 Returns: 21 tuple[str, dict]: 集計結果 22 - str: ランキングの集計情報 23 - dict: 各ランキングの情報 24 """ 25 26 # 情報ヘッダ 27 if g.params.get("individual"): # 個人集計 28 msg = "\n*【ランキング】*\n" 29 else: # チーム集計 30 msg = "\n*【チームランキング】*\n" 31 32 # データ取得 33 game_info: GameInfoDict = aggregate.game_info() 34 if not game_info["game_count"]: # 検索結果が0件のとき 35 msg += "\t" + message.reply(message="no_hits") 36 return (msg, {}) 37 38 result_df = loader.read_data("ranking/aggregate.sql") 39 if result_df.empty: 40 msg += "\t" + message.reply(message="no_target") 41 return (msg, {}) 42 43 df = pd.merge( 44 result_df, aggregate.ranking_record(), 45 on=["name", "name"], 46 suffixes=["", "_x"] 47 ) 48 49 if g.params.get("anonymous"): 50 mapping_dict = formatter.anonymous_mapping(df["name"].unique().tolist()) 51 df["name"] = df["name"].replace(mapping_dict) 52 53 # 集計 54 data: dict = {} 55 56 # ゲーム参加率 57 df["participation_rate"] = df["game_count"] / game_info["game_count"] 58 df["rank"] = df["participation_rate"].rank(ascending=False, method="dense").astype("int") 59 df["disp"] = df.apply(lambda row: f"<>{row["participation_rate"]:>7.2%} ({row["game_count"]:3d}G / {game_info["game_count"]:4d}G)", axis=1) 60 data["ゲーム参加率"] = table_conversion(df) 61 62 # 通算ポイント 63 df["rank"] = df["point_sum"].rank(ascending=False, method="dense").astype("int") 64 df["disp"] = df.apply(lambda row: f"<>{row["point_sum"]:>+7.1f}pt ({row["game_count"]:3d}G)", axis=1) 65 data["通算ポイント"] = table_conversion(df) 66 67 # 平均ポイント 68 df["rank"] = df["point_avg"].rank(ascending=False, method="dense").astype("int") 69 df["disp"] = df.apply(lambda row: f"<>{row["point_avg"]:>+7.1f}pt ({row["point_sum"]:>+7.1f}pt / {row["game_count"]:3d}G)", axis=1) 70 data["平均ポイント"] = table_conversion(df) 71 72 # 平均収支 73 df["rank"] = df["rpoint_avg"].rank(ascending=False, method="dense").astype("int") 74 df["disp"] = df.apply(lambda row: f"<>{row["rpoint_avg"] - 25000:>6.0f}点 ({row["rpoint_avg"]:>6.0f}点 / {row["game_count"]:3d}G)", axis=1) 75 data["平均収支"] = table_conversion(df) 76 77 # トップ率 78 df["rank"] = df["rank1_rate"].rank(ascending=False, method="dense").astype("int") 79 df["disp"] = df.apply(lambda row: f"<>{row["rank1_rate"]:>7.2%} ({row["rank1"]:3d} / {row["game_count"]:3d}G)", axis=1) 80 data["トップ率"] = table_conversion(df) 81 82 # 連対率 83 df["rank"] = df["top2_rate"].rank(ascending=False, method="dense").astype("int") 84 df["disp"] = df.apply(lambda row: f"<>{row["top2_rate"]:>7.2%} ({row["top2"]:3d} / {row["game_count"]:3d}G)", axis=1) 85 data["連対率"] = table_conversion(df) 86 87 # ラス回避率 88 df["rank"] = df["top3_rate"].rank(ascending=False, method="dense").astype("int") 89 df["disp"] = df.apply(lambda row: f"<>{row["top3_rate"]:>7.2%} ({row["top3"]:3d} / {row["game_count"]:3d}G)", axis=1) 90 data["ラス回避率"] = table_conversion(df) 91 92 # トビ率 93 df["rank"] = df["flying_rate"].rank(ascending=True, method="dense").astype("int") 94 df["disp"] = df.apply(lambda row: f"<>{row["flying_rate"]:>7.2%} ({row["flying"]:3d} / {row["game_count"]:3d}G)", axis=1) 95 data["トビ率"] = table_conversion(df) 96 97 # 平均順位 98 df["rank"] = df["rank_avg"].rank(ascending=True, method="dense").astype("int") 99 df["disp"] = df.apply(lambda row: f"<>{row["rank_avg"]:>4.2f} ({row["rank_dist"]})", axis=1) 100 data["平均順位"] = table_conversion(df) 101 102 # 役満和了率 103 df["rank"] = df["gs_rate"].rank(ascending=False, method="dense").astype("int") 104 df["disp"] = df.apply(lambda row: f"<>{row["gs_rate"]:>7.2%} ({row["gs_count"]:3d} / {row["game_count"]:3d}G)", axis=1) 105 data["役満和了率"] = table_conversion(df, ["gs_count", 1]) 106 107 # 最大素点 108 df["rank"] = df["rpoint_max"].rank(ascending=False, method="dense").astype("int") 109 df["disp"] = df.apply(lambda row: f"<>{row["rpoint_max"]:>6.0f}点 ({row["point_max"]:>+7.1f}pt)", axis=1) 110 data["最大素点"] = table_conversion(df) 111 112 # 連続トップ 113 df["rank"] = df["c_top"].rank(ascending=False, method="dense").astype("int") 114 df["disp"] = df.apply(lambda row: f"<>{row["c_top"]:>2d}連続 ({row["game_count"]:3d}G)", axis=1) 115 data["連続トップ"] = table_conversion(df, ["c_top", 2]) 116 117 # 連続連対 118 df["rank"] = df["c_top2"].rank(ascending=False, method="dense").astype("int") 119 df["disp"] = df.apply(lambda row: f"<>{row["c_top2"]:>2d}連続 ({row["game_count"]:3d}G)", axis=1) 120 data["連続連対"] = table_conversion(df, ["c_top2", 2]) 121 122 # 連続ラス回避 123 df["rank"] = df["c_top3"].rank(ascending=False, method="dense").astype("int") 124 df["disp"] = df.apply(lambda row: f"<>{row["c_top3"]:>2d}連続 ({row["game_count"]:3d}G)", axis=1) 125 data["連続ラス回避"] = table_conversion(df, ["c_top3", 2]) 126 127 # 表示 128 msg += message.header(game_info, "", 1) 129 130 for key in list(data.keys()): 131 if key in g.cfg.dropitems.ranking: # 非表示項目 132 data.pop(key) 133 continue 134 135 if key in data: # 対象者がいなければ項目を削除 136 if not data[key]: 137 data.pop(key) 138 continue 139 140 data[key] = f"*{key}*\n" + data[key] 141 142 return (msg, data) 143 144 145def table_conversion(df: pd.DataFrame, threshold: list | None = None) -> str: 146 """テーブル変換 147 148 Args: 149 df (pd.DataFrame): 変換対象データ 150 threshold (list | None, optional): 非表示にする閾値. Defaults to None. 151 152 Returns: 153 str: 作成したテーブル 154 """ 155 156 if isinstance(threshold, list): 157 df = df.query(f"{threshold[0]} >= @threshold[1]").copy() 158 159 if df.empty: 160 return "" 161 162 df.sort_values(by=["rank", "game_count"], ascending=[True, False], inplace=True) 163 df = df.query("rank <= @g.cfg.ranking.ranked") 164 tbl = tabulate(df.filter(items=["rank", "name", "disp"]).values) 165 tbl = re.sub(r"( *[0-9]+)\s(.*)<>(.*)", r"\1:\2\3", tbl) 166 tbl = "\n".join(tbl.splitlines()[1:-1]).replace(" -", "▲") 167 tbl = f"\n```\n{tbl}\n```\n" 168 169 return tbl
def
aggregation() -> tuple[str, dict]:
18def aggregation() -> tuple[str, dict]: 19 """ランキングデータを生成 20 21 Returns: 22 tuple[str, dict]: 集計結果 23 - str: ランキングの集計情報 24 - dict: 各ランキングの情報 25 """ 26 27 # 情報ヘッダ 28 if g.params.get("individual"): # 個人集計 29 msg = "\n*【ランキング】*\n" 30 else: # チーム集計 31 msg = "\n*【チームランキング】*\n" 32 33 # データ取得 34 game_info: GameInfoDict = aggregate.game_info() 35 if not game_info["game_count"]: # 検索結果が0件のとき 36 msg += "\t" + message.reply(message="no_hits") 37 return (msg, {}) 38 39 result_df = loader.read_data("ranking/aggregate.sql") 40 if result_df.empty: 41 msg += "\t" + message.reply(message="no_target") 42 return (msg, {}) 43 44 df = pd.merge( 45 result_df, aggregate.ranking_record(), 46 on=["name", "name"], 47 suffixes=["", "_x"] 48 ) 49 50 if g.params.get("anonymous"): 51 mapping_dict = formatter.anonymous_mapping(df["name"].unique().tolist()) 52 df["name"] = df["name"].replace(mapping_dict) 53 54 # 集計 55 data: dict = {} 56 57 # ゲーム参加率 58 df["participation_rate"] = df["game_count"] / game_info["game_count"] 59 df["rank"] = df["participation_rate"].rank(ascending=False, method="dense").astype("int") 60 df["disp"] = df.apply(lambda row: f"<>{row["participation_rate"]:>7.2%} ({row["game_count"]:3d}G / {game_info["game_count"]:4d}G)", axis=1) 61 data["ゲーム参加率"] = table_conversion(df) 62 63 # 通算ポイント 64 df["rank"] = df["point_sum"].rank(ascending=False, method="dense").astype("int") 65 df["disp"] = df.apply(lambda row: f"<>{row["point_sum"]:>+7.1f}pt ({row["game_count"]:3d}G)", axis=1) 66 data["通算ポイント"] = table_conversion(df) 67 68 # 平均ポイント 69 df["rank"] = df["point_avg"].rank(ascending=False, method="dense").astype("int") 70 df["disp"] = df.apply(lambda row: f"<>{row["point_avg"]:>+7.1f}pt ({row["point_sum"]:>+7.1f}pt / {row["game_count"]:3d}G)", axis=1) 71 data["平均ポイント"] = table_conversion(df) 72 73 # 平均収支 74 df["rank"] = df["rpoint_avg"].rank(ascending=False, method="dense").astype("int") 75 df["disp"] = df.apply(lambda row: f"<>{row["rpoint_avg"] - 25000:>6.0f}点 ({row["rpoint_avg"]:>6.0f}点 / {row["game_count"]:3d}G)", axis=1) 76 data["平均収支"] = table_conversion(df) 77 78 # トップ率 79 df["rank"] = df["rank1_rate"].rank(ascending=False, method="dense").astype("int") 80 df["disp"] = df.apply(lambda row: f"<>{row["rank1_rate"]:>7.2%} ({row["rank1"]:3d} / {row["game_count"]:3d}G)", axis=1) 81 data["トップ率"] = table_conversion(df) 82 83 # 連対率 84 df["rank"] = df["top2_rate"].rank(ascending=False, method="dense").astype("int") 85 df["disp"] = df.apply(lambda row: f"<>{row["top2_rate"]:>7.2%} ({row["top2"]:3d} / {row["game_count"]:3d}G)", axis=1) 86 data["連対率"] = table_conversion(df) 87 88 # ラス回避率 89 df["rank"] = df["top3_rate"].rank(ascending=False, method="dense").astype("int") 90 df["disp"] = df.apply(lambda row: f"<>{row["top3_rate"]:>7.2%} ({row["top3"]:3d} / {row["game_count"]:3d}G)", axis=1) 91 data["ラス回避率"] = table_conversion(df) 92 93 # トビ率 94 df["rank"] = df["flying_rate"].rank(ascending=True, method="dense").astype("int") 95 df["disp"] = df.apply(lambda row: f"<>{row["flying_rate"]:>7.2%} ({row["flying"]:3d} / {row["game_count"]:3d}G)", axis=1) 96 data["トビ率"] = table_conversion(df) 97 98 # 平均順位 99 df["rank"] = df["rank_avg"].rank(ascending=True, method="dense").astype("int") 100 df["disp"] = df.apply(lambda row: f"<>{row["rank_avg"]:>4.2f} ({row["rank_dist"]})", axis=1) 101 data["平均順位"] = table_conversion(df) 102 103 # 役満和了率 104 df["rank"] = df["gs_rate"].rank(ascending=False, method="dense").astype("int") 105 df["disp"] = df.apply(lambda row: f"<>{row["gs_rate"]:>7.2%} ({row["gs_count"]:3d} / {row["game_count"]:3d}G)", axis=1) 106 data["役満和了率"] = table_conversion(df, ["gs_count", 1]) 107 108 # 最大素点 109 df["rank"] = df["rpoint_max"].rank(ascending=False, method="dense").astype("int") 110 df["disp"] = df.apply(lambda row: f"<>{row["rpoint_max"]:>6.0f}点 ({row["point_max"]:>+7.1f}pt)", axis=1) 111 data["最大素点"] = table_conversion(df) 112 113 # 連続トップ 114 df["rank"] = df["c_top"].rank(ascending=False, method="dense").astype("int") 115 df["disp"] = df.apply(lambda row: f"<>{row["c_top"]:>2d}連続 ({row["game_count"]:3d}G)", axis=1) 116 data["連続トップ"] = table_conversion(df, ["c_top", 2]) 117 118 # 連続連対 119 df["rank"] = df["c_top2"].rank(ascending=False, method="dense").astype("int") 120 df["disp"] = df.apply(lambda row: f"<>{row["c_top2"]:>2d}連続 ({row["game_count"]:3d}G)", axis=1) 121 data["連続連対"] = table_conversion(df, ["c_top2", 2]) 122 123 # 連続ラス回避 124 df["rank"] = df["c_top3"].rank(ascending=False, method="dense").astype("int") 125 df["disp"] = df.apply(lambda row: f"<>{row["c_top3"]:>2d}連続 ({row["game_count"]:3d}G)", axis=1) 126 data["連続ラス回避"] = table_conversion(df, ["c_top3", 2]) 127 128 # 表示 129 msg += message.header(game_info, "", 1) 130 131 for key in list(data.keys()): 132 if key in g.cfg.dropitems.ranking: # 非表示項目 133 data.pop(key) 134 continue 135 136 if key in data: # 対象者がいなければ項目を削除 137 if not data[key]: 138 data.pop(key) 139 continue 140 141 data[key] = f"*{key}*\n" + data[key] 142 143 return (msg, data)
ランキングデータを生成
Returns:
tuple[str, dict]: 集計結果
- str: ランキングの集計情報
- dict: 各ランキングの情報
def
table_conversion(df: pandas.core.frame.DataFrame, threshold: list | None = None) -> str:
146def table_conversion(df: pd.DataFrame, threshold: list | None = None) -> str: 147 """テーブル変換 148 149 Args: 150 df (pd.DataFrame): 変換対象データ 151 threshold (list | None, optional): 非表示にする閾値. Defaults to None. 152 153 Returns: 154 str: 作成したテーブル 155 """ 156 157 if isinstance(threshold, list): 158 df = df.query(f"{threshold[0]} >= @threshold[1]").copy() 159 160 if df.empty: 161 return "" 162 163 df.sort_values(by=["rank", "game_count"], ascending=[True, False], inplace=True) 164 df = df.query("rank <= @g.cfg.ranking.ranked") 165 tbl = tabulate(df.filter(items=["rank", "name", "disp"]).values) 166 tbl = re.sub(r"( *[0-9]+)\s(.*)<>(.*)", r"\1:\2\3", tbl) 167 tbl = "\n".join(tbl.splitlines()[1:-1]).replace(" -", "▲") 168 tbl = f"\n```\n{tbl}\n```\n" 169 170 return tbl
テーブル変換
Arguments:
- df (pd.DataFrame): 変換対象データ
- threshold (list | None, optional): 非表示にする閾値. Defaults to None.
Returns:
str: 作成したテーブル