Bリーグのスタッツを使ってレーティングを計算する / ORtgとDRtg
前回はBリーグのホームページから選手スタッツからデータベースを作成するところまで紹介しました。今回はこのデータを以下のリンクにある計算式でアドバンスド・スタッツを求めたいと思います。
[11/18更新]
ORtgとDRtgを算出する記事を3回に分けて書いていましたが、こちらの記事にまとめました。
項目が非常に多いので内容が長くなります。
1.ORtgの算出
ここでは選手のオフェンシブレーティングを計算していきます。これにより100回の攻撃機会あたりの得点生産能力を評価し、オフェンス効率を数値化します。計算には大きく9項目の算出が必要となりますので順番に紹介します。
1-1.OR_Part
対象選手が取得したオフェンシブリバウンドがどれだけの得点の機会を生み出したかを示す指標です。プレイヤーがオフェンシブリバウンドを取ると、プレイで得点する確率が上がって得点に対する貢献となります。計算は前提となる4項目が必要ですので順番に紹介します。
1-1-1. Team_Scoring_Poss
チームのスコアリングポゼッション(得点の機会)の数を推定する指標です。
値が高い場合:チームが多くの得点機会を作り出していることを示します。これは効率的なオフェンス、高いシューティング効率、または両方を意味します。
値が低い場合:チームが得点機会をあまり作り出していない、またはシュート効率が低いことを示します。これは攻撃面での改善が必要であることを示唆しています。
Team_FGM (Team Field Goals Made): チームが成功させたフィールドゴールの数。
Team_FTM / Team_FTA (Free Throw Percentage): フリースローの成功率。
(1 - (1 - (Team_FTM / Team_FTA))^2) * Team_FTA * 0.4: フリースローによるスコアリングの期待値。
def calculate_team_scoring_poss(team_fgm, team_ftm, team_fta):
ft_success_rate = team_ftm / team_fta
ft_possessions = (1 - (1 - ft_success_rate) ** 2) * team_fta * 0.4
return team_fgm + ft_possessions
1-1-2. Team_Play%
チームが得点を獲得するためにどれだけ効率的にプレイしているかを示す指標です。
値が高い場合:チームがポゼッションを効率的に利用して得点に結びつけていることを意味します。つまり攻撃が効率的であり、少ないチャンスで多くの得点を獲得していることを示しています。
値が低い場合:チームがポゼッションを無駄にしているか、あるいは得点機会を十分に活かせていないことを意味します。つまり多くの試みにもかかわらず得点が少ない、または攻撃の効率が悪いことを示しています。
Team_Scoring_Poss: チームが得点を獲得する機会(スコアリングポゼッション)の数。
Team_FGA + Team_FTA * 0.4 + Team_TOV: チームの総ポゼッション数。フィールドゴール試投数(FGA)、フリースロー試投数(FTA)、ターンオーバー数(TOV)を合計したもの。
def calculate_team_play_percentage(team_scoring_poss, team_fga, team_fta, team_tov):
return team_scoring_poss / (team_fga + team_fta * 0.4 + team_tov)
1-1-3. Team_OR%
オフェンシブ・リバウンド率のチーム指標を示しています。チームがシュートを外したときに、オフェンシブ・リバウンドをどれだけ取れたかを示しています。
値が高い場合:チームが攻撃側でのリバウンドを多く獲得していることを意味し、攻撃のチャンスを増やしていることを示します。これは攻撃のセカンドチャンスを得る能力が高いことを示しています。
値が低い場合:チームが攻撃側でのリバウンドをあまり獲得できていないことを意味し、セカンドチャンスの機会が限られていることを示します。これは攻撃の効率に改善が必要であることを示唆しています。
Team_ORB: チームのオフェンシブ・リバウンドの数。
Opponent_DRB: 対戦相手チームのディフェンシブ・リバウンドの数。
def calculate_team_or_percentage(team_or, opponent_dr):
return team_or / (team_or + opponent_dr)
1-1-4. Team_OR_Weight
オフェンシブ・リバウンドへの重みを示す指標です。チームがオフェンシブ・リバウンドをどの程度重要視し、それが得点にどれだけ貢献するかを評価します。
値が高い場合:チームのオフェンスにおいてオフェンシブリバウンドが重要な役割を果たしていることを意味します。つまり、チームはオフェンシブリバウンドを獲得することで得点の多くの機会を作り出していると言えます。
値が低い場合:オフェンシブリバウンドがチームの得点にそれほど貢献していないことを意味します。チームはオフェンシブリバウンドよりも他の要素(例えば、フィールドゴールのシューティング効率など)で得点を獲得している可能性があります。
Team_OR% (オフェンシブリバウンド率): チームが攻撃側でどれだけのリバウンドを獲得しているかの割合。
Team_Play% (プレイ効率): チームがポゼッションをどれだけ効率的に得点に変換しているかの割合。
def calculate_team_or_weight(team_or_percentage, team_play_percentage):
numerator = (1 - team_or_percentage) * team_play_percentage
denominator = (1 - team_or_percentage) * team_play_percentage + team_or_percentage * (1 - team_play_percentage)
return numerator / denominator
1-1-5. OR_Part
プレイヤーがオフェンシブ・リバウンドを取得したときにその選手によって生み出される得点の機会を示す個人指標です。
値が高い場合:オフェンシブリバウンドがチームの得点に大きく貢献していることを意味します。つまり、チームはオフェンシブリバウンドから多くの得点機会を生み出しており、これがオフェンスの重要な部分を占めていると言えます。
値が低い場合:オフェンシブリバウンドがチームの得点にあまり貢献していないことを意味します。つまり、チームはオフェンシブリバウンドによる得点よりも他の方法で得点を獲得している可能性があります。
ORB (オフェンシブリバウンド): チームが獲得した攻撃側リバウンドの数。
Team_OR_Weight: オフェンシブリバウンドがチームのオフェンスにおいてどれだけ重要かを示す重み。
Team_Play%: チームのプレイ効率、つまりポゼッションをどれだけ効率的に得点に変換しているかの割合。
def calculate_OR_Part(ORB, Team_OR_Weight, Team_Play_Percentage):
return ORB * Team_OR_Weight * Team_Play_Percentage
1-2.FT_Part
プレイヤーの得点のうち、フリースローがチームの得点にどれだけ貢献しているかを測定するための指標です。
値が高い場合:フリースローがチームの得点に大きく貢献していることを意味します。フリースローの成功率が高く、また多くのフリースローの機会がある場合にこの値は高くなります。
値が低い場合:フリースローがチームの得点にそれほど貢献していないことを意味します。フリースローの成功率が低いか、またはフリースローの試投機会が少ない場合にこの値は低くなります。
FTM/FTA: フリースローの成功率。FTMはフリースロー成功数、FTAはフリースロー試投数です。
(1-(1-(FTM/FTA))^2): フリースローが1ポゼッションにどれだけの価値があるかを示します。フリースローが得点に変わる確率を考慮した係数です。
0.4: この係数は、フリースローが一般的に1ポゼッションを完全に終了させないという事実を反映しています。一部のフリースローはリバウンドの機会を残します。
def calculate_FT_Part(FTM, FTA):
if FTA == 0:
return 0
return 0.4 * FTA * (1 - (1 - FTM/FTA)**2)
1-3.AST_Part
アシスト(AST)がチームの得点にどれだけ貢献しているかを測定するための指標です。
値が高い場合:プレーヤーのアシストがチームの得点に大きく貢献していることを意味します。つまり、そのプレーヤーのパスが効果的であり、チームメイトの得点機会を増やしていることを示しています。
値が低い場合:プレーヤーのアシストがチームの得点にそれほど貢献していないことを意味します。プレーヤーのパスが得点に直接つながっていないか、または他のプレーヤーがより自己完結型で得点していることを示している可能性があります。
Team_PTS - Team_FTM: チームの総得点からフリースローによる得点を除いた値。
PTS - FTM: 個々のプレーヤーがフリースロー以外で獲得した得点。
Team_FGA - FGA: チーム全体のフィールドゴール試投数から個々のプレーヤーの試投数を除いた値。
AST: プレーヤーのアシスト数。
def calculate_AST_Part(PTS, FTM, FGA, Team_PTS, Team_FTM, Team_FGA, AST):
if (Team_FGA - FGA) == 0:
return 0
non_FT_PTS = Team_PTS - Team_FTM
player_non_FT_PTS = PTS - FTM
AST_Part = 0.5 * ((non_FT_PTS - player_non_FT_PTS) / (2 * (Team_FGA - FGA))) * AST
return AST_Part
1-4.FG_Part
プレーヤーのフィールドゴールがチームの得点にどれだけ貢献しているかを示す指標です。計算には事前にqASTを算出する必要があります。
1-4-1.qAST
プレイヤーのアシストの質を示す指標です。プレーヤーがコート上にいる時のチームのアシスト率から、そのプレーヤー自身のアシスト数を差し引いて算出します。
値が高い場合: プレーヤーがコート上にいる時にチームのアシスト率が高いことを意味し、プレーヤーがチームのオフェンスに大きく貢献していることを示します。つまり、このプレーヤーはチームメイトの得点機会を創出するのに効果的です。
値が低い場合: プレーヤーがコート上にいる時のチームのアシスト率が低いことを意味し、プレーヤーのアシストがチームの得点にそれほど貢献していないことを示します。プレーヤーは自身で得点を獲得することに重点を置いているか、またはアシストの機会が少ないかもしれません。
MIN / (Team_MIN / 5): プレーヤーがコート上にいる割合。
Team_AS: チーム全体のアシスト数。
AS: プレーヤーのアシスト数。
Team_FGM: チーム全体のフィールドゴール成功数。
FGM: プレーヤーのフィールドゴール成功数。
def calculate_qAST(MIN, Team_MIN, AS, Team_FGM, FGM, Team_AS):
if Team_MIN == 0 or Team_FGM == 0:
return 0
proportion_of_time_played = MIN / (Team_MIN / 5)
if ((Team_FGM / Team_MIN) * MIN * 5 - FGM) == 0:
second_part = 0
else:
second_part = (((Team_AS / Team_MIN) * MIN * 5 - AS) / ((Team_FGM / Team_MIN) * MIN * 5 - FGM)) * (1 - proportion_of_time_played)
qAST = (proportion_of_time_played * (1.14 * ((Team_AS - AS) / Team_FGM))) + second_part
return qAST
1-4-2.FG_Part
qASTを算出できましたら、この指標を求めることができます。
値が高い場合: プレーヤーのフィールドゴールがチームの得点に大きく貢献していることを意味します。プレーヤーは効率的に得点を獲得しており、特にアシストに頼らずに自ら得点を獲得している可能性が高いです。
値が低い場合: プレーヤーのフィールドゴールがチームの得点にそれほど貢献していないことを意味します。プレーヤーがシューティングの効率が低いか、アシストに大きく依存して得点を獲得していることを示唆している可能性があります。
FGM: プレーヤーによるフィールドゴール成功数。
PTS - FTM: プレーヤーによるフリースロー以外での得点。
FGA: プレーヤーによるフィールドゴール試投数。
qAST: プレーヤーがコート上にいるときのチームのアシスト率。
def calculate_FG_Part(FGM, PTS, FTM, FGA, qAST):
if FGA == 0:
return 0
FG_Part = FGM * (1 - 0.5 * ((PTS - FTM) / (2 * FGA)) * qAST)
return FG_Part
1-5.ScPoss
"Scoring Possessions" の略で、どれだけ得点のチャンスを生み出しているかを示す指標です。攻撃においてどれだけ影響を与えているかを測ります。
値が高い場合:プレーヤーやチームが多くの得点機会を生み出していることを意味し、効率的なオフェンスを運営していることを示します。シューティング、アシスト、フリースロー、オフェンシブリバウンドのいずれかまたは全てがうまく機能していることを意味します。
値が低い場合:プレーヤーやチームが得点機会をあまり生み出していないことを意味し、オフェンスの効率が低い可能性があります。フィールドゴールのシューティング、アシスト、フリースローの成功率、またはオフェンシブリバウンドの活用に問題があるかもしれません。
FG_Part: フィールドゴールによる得点機会。
AS_Part: アシストによる得点機会。
FT_Part: フリースローによる得点機会。
Team_OR / Team_Scoring_Poss: チームのオフェンシブリバウンド率。
Team_OR_Weight: オフェンシブリバウンドの重要性。
Team_Play%: チームのプレイ効率。
OR_Part: オフェンシブリバウンドによる得点機会。
def calculate_ScPoss(FG_Part, AST_Part, FT_Part, OR_Part, Team_OR, Team_Scoring_Poss, Team_OR_Weight, Team_Play):
if Team_Scoring_Poss == 0:
return 0
ScPoss = (FG_Part + AST_Part + FT_Part) * (1 - (Team_OR / Team_Scoring_Poss) * Team_OR_Weight * Team_Play) + OR_Part
return ScPoss
1-6.FGxPoss
フィールドゴールのミスショットがチームのポゼッションにどのように影響しているかを測定するための指標です。
値が高い場合: ミスショットによるポゼッションの損失が多いことを意味します。シューティングの効率が低いか、オフェンシブリバウンドを取る能力が低いことを示している可能性があります。
値が低い場合: ミスショットによるポゼッションの損失が少ないことを意味します。シューティングの効率が良いか、ミスショット後にオフェンシブリバウンドを取る能力が高いことを示しています。
FGA - FGM: プレーヤーまたはチームによるフィールドゴールの非成功試投数(ミスショット)。
Team_OR%: チームのオフェンシブリバウンド率。
1 - 1.07 * Team_OR%: ミスしたショットのうち、チームがリバウンドを取れなかった割合を推定する係数。
def calculate_FGxPoss(FGA, FGM, Team_OR_percent):
FGxPoss = (FGA - FGM) * (1 - 1.07 * Team_OR_percent)
return FGxPoss
1-7.FTxPoss
ミスしたフリースローがチームのポゼッションにどのように影響しているかを測定するための指標です。
値が高い場合: フリースローのミスによるポゼッションの損失が多いことを意味します。フリースローの成功率が低いことを示しており、フリースローの効率が悪いことを示唆しています。
値が低い場合: フリースローのミスによるポゼッションの損失が少ないことを意味します。フリースローの成功率が高いことを示しており、効率的なフリースローを示唆しています。
(1 - (FTM / FTA))^2: フリースローを連続してミスする確率。FTMはフリースロー成功数、FTAはフリースロー試投数です。
0.4 * FTA: フリースロー試投に対するポゼッションの影響を推定する係数。一般的に、フリースローはポゼッションを完全に終了させるわけではないため、この係数が使われます。
def calculate_FTxPoss(FTM, FTA):
if FTA == 0:
return 0
FTxPoss = ((1 - (FTM / FTA))**2) * 0.4 * FTA
return FTxPoss
1-8.TotPoss
プレーヤーがゲーム中に持つ総ポゼッション数を推定する指標です。
値が高い場合:プレーヤーやチームがゲーム中に多くのポゼッションを持っていることを意味します。チームがアクティブに攻撃を仕掛けているか、または多くのシューティングチャンスを得ていることを示している可能性があります。しかし、高いターンオーバー数やミスショットも多いポゼッション数を増やす要因となることがあります。
値が低い場合:プレーヤーやチームがゲーム中に比較的少ないポゼッションを持っていることを意味します。チームのプレースタイルが遅いか、オフェンスの機会が少ないことを示している可能性があります。
ScPoss: 得点機会。
FGxPoss: フィールドゴールのミスによるポゼッションの損失。
FTxPoss: フリースローのミスによるポゼッションの損失。
TOV: ターンオーバーによるポゼッションの損失。
def calculate_TotPoss(ScPoss, FGxPoss, FTxPoss, TOV):
TotPoss = ScPoss + FGxPoss + FTxPoss + TOV
return TotPoss
1-9.PProd
プレーヤーの総得点生産を測定するための指標です。フィールドゴール、アシスト、フリースロー、およびオフェンシブリバウンドを通じて、どれだけの得点に貢献しているかを評価します。計算は前提となる3項目が必要ですので順番に紹介します。
値が高い場合:プレーヤーやチームが多くの得点を生み出していることを意味します。特にシューティング、アシスト、フリースロー、オフェンシブリバウンドの全てがうまく機能しており、高いオフェンス効率を示している可能性があります。
値が低い場合: プレーヤーやチームが得点をあまり生み出していないことを意味します。シューティングの効率が低い、アシストが得点につながっていない、フリースローの成功率が低い、またはオフェンシブリバウンドからの得点機会が限られていることを示唆しています。
1-9-1. PProd_FG_Part
プレーヤーのフィールドゴールによる総得点生産を測定するためのものです。この指標は、プレーヤーがフィールドゴール(2ポイントショットおよび3ポイントショット)を通じてどれだけ得点に貢献しているかを評価します。
値が高い場合: プレーヤーがフィールドゴールから多くの得点を生み出していることを意味します。特に、効率的なシューティングや3ポイントショットの成功が、高い得点に貢献していることを示しています。
値が低い場合:プレーヤーがフィールドゴールからそれほど多くの得点を生み出していないことを意味します。シューティングの効率が低いか、フィールドゴールの試投機会が少ないことを示唆しています。
FGM: フィールドゴール成功数。
3FGM: 3ポイントショット成功数。
PTS - FTM: フリースロー以外での得点。
FGA: フィールドゴール試投数。
qAST: プレーヤーがコート上にいるときのチームのアシスト率。
def calculate_PProd_FG_Part(FGM, ThreeFGM, PTS, FTM, FGA, qAST):
PProd_FG_Part = 2 * (FGM + 0.5 * ThreeFGM) * (1 - 0.5 * ((PTS - FTM) / (2 * FGA)) * qAST)
return PProd_FG_Part
1-9-2. PProd_AS_Part
プレーヤーのアシストによるチームの総得点生産を測定する指標です。プレーヤーがアシストを通じてチームの得点にどれだけ貢献しているかを評価します。
値が高い場合:プレーヤーのアシストがチームの得点に大きく貢献していることを意味します。つまりプレーヤーのパスが効果的であり、チームメイトの得点機会を増やしていることを示しています。
値が低い場合:プレーヤーのアシストがチームの得点にそれほど貢献していないことを意味します。プレーヤーのパスが得点に直接つながっていないか、または他のプレーヤーがより自己完結型で得点していることを示している可能性があります。
Team_FGM - FGM: プレーヤー以外のチームメンバーによるフィールドゴール成功数。
Team_3FGM - 3FGM: プレーヤー以外のチームメンバーによる3ポイントショット成功数。
Team_PTS - Team_FTM: チームのフリースロー以外での得点。
PTS - FTM: プレーヤーのフリースロー以外での得点。
Team_FGA - FGA: プレーヤー以外のチームメンバーによるフィールドゴール試投数。
AS: プレーヤーのアシスト数。
def calculate_PProd_AS_Part(Team_FGM, FGM, Team_3FGM, ThreeFGM, Team_PTS, Team_FTM, PTS, FTM, Team_FGA, FGA, AS):
if (Team_FGM - FGM) == 0 or (Team_FGA - FGA) == 0:
return 0
assist_factor = 2 * ((Team_FGM - FGM + 0.5 * (Team_3FGM - ThreeFGM)) / (Team_FGM - FGM))
non_FT_PTS_contribution = 0.5 * (((Team_PTS - Team_FTM) - (PTS - FTM)) / (2 * (Team_FGA - FGA)))
PProd_AS_Part = assist_factor * non_FT_PTS_contribution * AS
return PProd_AS_Part
1-9-3. PProd_OR_Part
プレーヤーのオフェンシブリバウンドがチームの総得点生産にどれだけ貢献しているかを測定するための指標です。この指標は、オフェンシブリバウンドを通じて生み出される得点の量を評価します。
値が高い場合: オフェンシブリバウンドがチームの得点に大きく貢献していることを意味します。つまりオフェンシブリバウンドを通じて多くの追加得点が得られていることを示しています。
値が低い場合:オフェンシブリバウンドがチームの得点にそれほど貢献していないことを意味します。つまりオフェンシブリバウンドからの得点機会が限られているか、オフェンシブリバウンドを効果的に利用していないことを示唆しています。
OR: オフェンシブリバウンドの数。
Team_OR_Weight: オフェンシブリバウンドのチームオフェンスにおける重要性。
Team_Play%: チームのプレイ効率、つまりポゼッションをどれだけ効率的に得点に変換しているかの割合。
Team_PTS / (Team_FGM + (1 - (1 - (Team_FTM / Team_FTA))^2) * 0.4 * Team_FTA): チームの平均得点価値。
def calculate_PProd_OR_Part(OR, Team_OR_Weight, Team_Play, Team_PTS, Team_FGM, Team_FTM, Team_FTA):
if Team_FTA == 0 or (Team_FGM + (1 - (1 - (Team_FTM / Team_FTA))**2) * 0.4 * Team_FTA) == 0:
return 0
scoring_contribution = Team_PTS / (Team_FGM + (1 - (1 - (Team_FTM / Team_FTA))**2) * 0.4 * Team_FTA)
PProd_OR_Part = OR * Team_OR_Weight * Team_Play * scoring_contribution
return PProd_OR_Part
これらの算出ができましたらPProdを求めます。
PProd_FG_Part: フィールドゴールによる得点生産。
PProd_AS_Part: アシストによる得点生産。
FTM: フリースロー成功数。
Team_OR / Team_Scoring_Poss: チームのオフェンシブリバウンド率。
Team_OR_Weight: オフェンシブリバウンドの重要性。
Team_Play%: チームのプレイ効率。
PProd_OR_Part: オフェンシブリバウンドによる得点生産。
def calculate_PProd(PProd_FG_Part, PProd_AS_Part, PProd_OR_Part, FTM, OR, ScPoss, Team_OR_Weight, Team_Play):
if ScPoss == 0:
return 0
PProd = (PProd_FG_Part + PProd_AS_Part + FTM) * (1 - (OR / ScPoss) * Team_OR_Weight * Team_Play) + PProd_OR_Part
return PProd
1-10.ORtg
これでようやくORtgを求めることができます。
プレーヤーのオフェンシブレーティング(Offensive Rating)を計算するための指標です。100ポゼッションあたりの得点生産能力を評価し、プレーヤーのオフェンス効率を数値化しています。ORtg が100を上回る場合、その選手は平均的な攻撃効率を上回っており、100を下回る場合は平均的な攻撃効率を下回っていると言えます。
PProd: プレーヤーやチームによる総得点生産。
TotPoss: プレーヤーやチームが持つ総ポゼッション数。
2.DRtgの算出
2-1.Stops1
プレーヤーがゲーム中に行った守備のストップ(防御成功)の数を推定するための指標です。DR%、DFG%、FMwtを算出する必要があります。
値が高い場合: プレーヤーが守備側で多くのストップ(防御成功)を行っていることを意味します。つまり、スティール、ブロックショット、ディフェンシブリバウンドで効果的な貢献をしており、優れたディフェンス能力を示しています。
値が低い場合: プレーヤーが守備側でそれほど多くのストップを行っていないことを意味します。守備貢献度が低いことを示し、ディフェンスの改善が必要かもしれません。
ST: スティール数。
BS: ブロックショット数。
FMwt: ブロックショットがフィールドゴールミスにつながる確率の重み。
DR%: チームのディフェンシブリバウンド率。
DR: ディフェンシブリバウンド数。
def calculate_Stops1(ST, BS, FMwt, DR_percentage, DR):
Stops1 = ST + BS * FMwt * (1 - 1.07 * DR_percentage) + DR * (1 - FMwt)
return Stops1
2-1-1. DR%
チームのディフェンシブリバウンド率(Defensive Rebound Percentage)を計算するためのものです。この指標は利用可能なリバウンドのうち、どれだけの割合をチームが守備側で確保しているかを示します。
値が高い場合:対戦相手が多くのオフェンシブリバウンドを獲得しており、自チームのディフェンスにおけるリバウンドの確保が不十分であることを意味します。ディフェンスの改善が必要であることを示唆しています。
値が低い場合:自チームが利用可能なリバウンドの大部分を確保しており、効果的なディフェンシブリバウンドを行っていることを意味します。これはディフェンスが良好であることを示しています。
Opponent_OR: 対戦相手チームのオフェンシブリバウンド数。
Team_DR: 自チームのディフェンシブリバウンド数。
def calculate_DR_percentage(Opponent_OR, Team_DR):
DR_percentage = Opponent_OR / (Opponent_OR + Team_DR)
return DR_percentage
2-1-2. DFG%
対戦相手チームのフィールドゴール成功率(Defensive Field Goal Percentage)を計算します。この指標はチームのディフェンスがどれだけ効果的に相手のシュートを防いでいるかを示します。
値が高い場合:対戦相手が高いフィールドゴール成功率を記録しており、自チームのディフェンスが相手のシュートを十分に防いでいないことを意味します。ディフェンスの改善が必要である可能性があります。
値が低い場合:対戦相手のフィールドゴール成功率が低く、自チームのディフェンスが効果的であることを意味します。チームが相手のシュートをうまく防いでいることを示しています。
Opponent_FGM: 対戦相手チームのフィールドゴール成功数。
Opponent_FGA: 対戦相手チームのフィールドゴール試投数。
def calculate_DFG_percentage(Opponent_FGM, Opponent_FGA):
DFG_percentage = Opponent_FGM / Opponent_FGA
return DFG_percentage
2-1-3. FMwt
ディフェンス側のフィールドゴールミス時のリバウンドの重み付け(Field Miss Weight)を計算するためのものです。この指標は、ディフェンスが相手のショットミスを強いた場合に、そのリバウンドをどれだけ確保することができるかの確率を示します。
値が高い場合:ディフェンスがショットミスを強いた際にリバウンドを確保する確率が高いことを意味します。ディフェンスが強く、リバウンドの確保も効果的であることを示しています。
値が低い場合:ディフェンスがショットミスを強いてもリバウンドを確保する確率が低いことを意味します。ディフェンスが相手のショットを抑えてもリバウンドでの支配が不十分であることを示唆しています。
DFG%: ディフェンシブフィールドゴールパーセンテージ(対戦相手のフィールドゴール成功率)。
DR%: ディフェンシブリバウンドパーセンテージ(自チームのディフェンシブリバウンド率)。
def calculate_FMwt(DFG_percentage, DR_percentage):
FMwt = (DFG_percentage * (1 - DR_percentage)) / (DFG_percentage * (1 - DR_percentage) + (1 - DFG_percentage) * DR_percentage)
return FMwt
2-2.Stops2
プレーヤーのディフェンスによる「ストップ」の数をより詳細に計算するための指標です。プレーヤーが守備でどれだけ効果的に相手のポゼッションを終了させているか(つまり、得点を防いでいるか)を評価します。
値が高い場合:プレーヤーが守備で効果的に多くの「ストップ」を行っていることを意味します。相手のショットを防ぎ、ターンオーバーを強いることに成功していることを示し、優れたディフェンス能力を持っていることを示唆しています。
値が低い場合:プレーヤーが守備でそれほど多くの「ストップ」を行っていないことを意味します。守備貢献度が低いことを示し、ディフェンスの改善が必要である可能性があります。
Opponent_FGA, Opponent_FGM, Team_BLK: 対戦相手のフィールドゴール試投数、成功数、および自チームのブロックショット数。
Team_MP, MP: 自チームおよびプレーヤーのプレイ時間。
FMwt: フィールドミス時のリバウンドの重み付け。
DOR%: 対戦相手のオフェンシブリバウンド率。
Opponent_TOV, Team_STL: 対戦相手のターンオーバー数および自チームのスティール数。
PF, Team_PF: プレーヤーのファウル数およびチームの総ファウル数。
Opponent_FTA, Opponent_FTM: 対戦相手のフリースロー試投数および成功数。
def calculate_Stops2(Opponent_FGA, Opponent_FGM, Team_BS, Team_MIN, FMwt, DR_percentage, Opponent_TOV, Team_ST, MIN, F, Team_F, Opponent_FTA, Opponent_FTM):
term1 = ((Opponent_FGA - Opponent_FGM - Team_BS) / Team_MIN) * FMwt * (1 - 1.07 * DR_percentage)
term2 = ((Opponent_TOV - Team_ST) / Team_MIN) * MIN
term3 = (F / Team_F) * 0.4 * Opponent_FTA * (1 - (Opponent_FTM / Opponent_FTA))**2
Stops2 = term1 + term2 + term3
return Stops2
2-3.Stops
プレーヤーが守備で行った総ストップ(防御成功)の数を計算するための指標です。プレーヤーがゲーム中にどれだけの守備効果を発揮して相手の得点機会を阻止したかを示します。
値が高い場合:プレーヤーが守備で多くのストップを行っており、効果的な守備貢献をしていることを意味します。スティール、ブロックショット、ディフェンシブリバウンド、そして全体的なディフェンスのプレイで優れた成績を示している可能性があります。
値が低い場合:プレーヤーが守備でそれほど多くのストップを行っていないことを意味します。これは守備貢献度が低いことを示し、ディフェンスの改善が必要である可能性があります。
Stops1: プレーヤーによるスティール、ブロックショット、ディフェンシブリバウンドなどによる直接的な守備のストップ。
Stops2: プレーヤーのプレイ時間、チームのディフェンスの効率などを考慮した間接的な守備のストップ。
2-4.Stop%
ディフェンスが成功し、相手チームの得点を阻止した状態を指します。この計算式は、特定の選手がコートにいる間に、相手チームのポゼッション(攻撃機会)のうちどれだけをストップ(得点を阻止)できたかをパーセンテージで表します。
値が高い場合:選手がコートにいる間に相手チームの得点機会を効果的に阻止していることを示します。つまり、その選手は優れたディフェンサーである可能性が高いです。
値が低い場合:選手がディフェンスであまり効果を発揮していないことを示します。これは、選手が相手チームにより多くの得点を許していることを意味する可能性があります。
Stops: ディフェンスが成功し得点を阻止した回数。
Opponent_MIN: 選手が対戦している間の相手チームの総プレイ時間(分)。
Opponent_Team_Possessions: 選手がプレイしている間の相手チームの総ポゼッション数。
MIN: 選手のプレイ時間(分)。
def calculate_stop_percentage(Stops, Opponent_MP, Opponent_Team_Possessions, MP):
if Opponent_Team_Possessions == 0 or MP == 0:
return 0
Stop_percentage = (Stops * Opponent_MP) / (Opponent_Team_Possessions * MP)
return Stop_percentage
2-4-1.Opponent_Team_Possessions
相手チームのポゼッション数)を計算するためのものです。ポゼッションは、チームがボールを持ち、得点を試みることができる機会のことを指します。この式は、相手チームの攻撃機会の総数を推定するために用いられます。
値が高い場合:試合が高速でプレイされていること、またはあなたのチームが相手チームに多くの攻撃機会を与えていることを示す可能性があります。多くのポゼッションは一般にスコアが高くなる傾向があります。
値が低い場合:試合が低速でプレイされていること、またはあなたのチームが相手チームの攻撃機会を効果的に制限していることを示すかもしれません。これは通常、スコアが低くなる傾向があります。
Opponent_FGA: 相手チームのフィールドゴール試投数(Field Goal Attempts)。
Opponent_FTA: 相手チームのフリースロー試投数(Free Throw Attempts)。
Opponent_ORB: 相手チームのオフェンスリバウンド数(Offensive Rebounds)。
Opponent_TOV: 相手チームのターンオーバー数(Turnovers)。
0.44: フリースロー試投がポゼッションに与える影響を推定するための係数。フリースローが一つのポゼッションと直接等しいわけではないため、この係数で調整します。
def calculate_opponent_team_possessions(Opponent_FGA, Opponent_FTA, Opponent_ORB, Opponent_TOV):
Opponent_Team_Possessions = Opponent_FGA + 0.44 * Opponent_FTA - Opponent_ORB + Opponent_TOV
return Opponent_Team_Possessions
2-5.D_Pts_per_ScPoss
1つの得点機会あたりの守備で許された平均得点数を計算するためのものです。この指標は相手チームの得点効率を評価するために用いられ、特にディフェンスの効果を測るのに役立ちます。
値が高い場合:相手チームが得点機会を非常に効率的に利用していることを意味します。つまり、あなたのチームの守備が効果的でない可能性があります。
値が低い場合:相手チームの得点効率が低いことを意味します。これは、あなたのチームの守備が効果的であることを示している可能性があります。
Opponent_PTS: 相手チームの総得点数。
Opponent_FGM: 相手チームのフィールドゴール成功数。
Opponent_FTM: 相手チームのフリースロー成功数。
Opponent_FTA: 相手チームのフリースロー試投数。
(1 - (1 - (Opponent_FTM / Opponent_FTA))^2) * Opponent_FTA * 0.4: フリースローによる得点機会の調整。
def calculate_opponent_team_d_pts_per_scposs(Opponent_PTS, Opponent_FGM, Opponent_FTA, Opponent_FTM):
if Opponent_FTA == 0 or (Opponent_FGM + (1 - (1 - (Opponent_FTM / Opponent_FTA))**2) * Opponent_FTA * 0.4) == 0:
return 0
D_Pts_per_Scposs = Opponent_PTS / (Opponent_FGM + (1 - (1 - (Opponent_FTM / Opponent_FTA))**2) * Opponent_FTA * 0.4)
return D_Pts_per_Scposs
2-6.Team_Defensive_Rating
チームのディフェンスの効果を数値化するために使用されます。この指標は、相手チームがどれだけ効率的に得点しているかを示し、チームの守備力を評価するための重要な統計です。
値が高い場合:相手チームが効率的に得点していることを示しています。つまり、チームの守備があまり効果的でない可能性があることを意味します。
値が低い場合:相手チームの得点効率が低いことを示しています。これは、チームの守備が効果的であることを意味し、良い守備力を示していると解釈されます。
Opponent_PTS: 相手チームの総得点数。
Opponent_Team_Possessions: 相手チームの総ポゼッション数。これは、相手チームがゲーム中に得た攻撃機会の総数です。
100: 得点/ポゼッションの値をより読みやすい形に変換するためのスケールファクターです。
def calculate_opponent_team_defensive_rating(Opponent_PTS, Opponent_Team_Possessions):
if Opponent_Team_Possessions == 0:
return 0
Team_Defensive_Rating = 100 * (Opponent_PTS / Opponent_Team_Possessions)
return Team_Defensive_Rating
2-7.DRtg
チームのディフェンスの効率を表す指標で、チームの守備力を数値化して評価するために使用されます。
値が高い場合:相手チームが効率的に得点していることを示しており、チームの守備が効果的でない可能性があります。
値が低い場合:相手チームの得点効率が低いことを示しており、チームの守備が効果的であることを意味します。
Team_Defensive_Rating: チームディフェンスレーティング。これは、相手チームがどれだけ効率的に得点しているかを示します(100ポゼッションあたりの得点)。
D_Pts_per_ScPoss: 一つの得点機会あたりの守備で許された平均得点数。
Stop%: チームのディフェンスが成功して相手の得点を阻止した割合。
0.2: この数値は、チームディフェンスレーティングを調整するための係数です。
def calculate_defensive_rating(Team_Defensive_Rating, D_Pts_per_ScPoss, Stop_percentage):
DRtg = Team_Defensive_Rating + 0.2 * (100 * D_Pts_per_ScPoss * (1 - Stop_percentage) - Team_Defensive_Rating)
return DRtg
3.Pythonでプログラムを書く
前回の記事でB1リーグの選手スタッツをまとめたデータベースを作成しました。
そこでOR_Partを計算する処理を書きたいと思います。GUIはマッチアップする2チームを選ぶだけの最低限のものですが、処理のベースは出来上がったと思います。
このPythonプログラムを動かすためには前の記事で紹介した選手スタッツのデータベースファイルを作成し、今回実行するPythonコードを保存したパスに置く必要があります。
from tkinter import *
from tkinter import ttk
import sqlite3
import pandas as pd
import math
# データベース接続関数
def connect_db():
try:
return sqlite3.connect("bleague_stat.db")
except Exception as e:
print(f"Database connection error: {e}")
return None
# チームデータの取得
def get_team_data(team, conn):
try:
query = f'SELECT * FROM player_stats WHERE team = "{team}"'
return pd.read_sql(query, conn)
except Exception as e:
print(f"Error fetching data: {e}")
return pd.DataFrame()
# 指標計算関数
def calculate_team_scoring_poss(team_fgm, team_ftm, team_fta):
ft_success_rate = team_ftm / team_fta
ft_possessions = (1 - (1 - ft_success_rate) ** 2) * team_fta * 0.4
return team_fgm + ft_possessions
def calculate_team_play_percentage(team_scoring_poss, team_fga, team_fta, team_tov):
return team_scoring_poss / (team_fga + team_fta * 0.4 + team_tov)
def calculate_team_or_percentage(team_or, opponent_dr):
return team_or / (team_or + opponent_dr)
def calculate_team_or_weight(team_or_percentage, team_play_percentage):
numerator = (1 - team_or_percentage) * team_play_percentage
denominator = (1 - team_or_percentage) * team_play_percentage + team_or_percentage * (1 - team_play_percentage)
return numerator / denominator
def calculate_team_dr_percentage(Opponent_OR, Team_DR):
if (Opponent_OR + Team_DR) == 0:
return 0
DR_percentage = Opponent_OR / (Opponent_OR + Team_DR)
return DR_percentage
def calculate_team_dfg_percentage(Opponent_FGM, Opponent_FGA):
if Opponent_FGA == 0:
return 0
DFG_percentage = Opponent_FGM / Opponent_FGA
return DFG_percentage
def calculate_team_fmwt(DFG_percentage, DR_percentage):
denominator = (DFG_percentage * (1 - DR_percentage) + (1 - DFG_percentage) * DR_percentage)
if denominator == 0:
return 0
FMwt = (DFG_percentage * (1 - DR_percentage)) / denominator
return FMwt
def calculate_opponent_team_possessions(Opponent_FGA, Opponent_FTA, Opponent_ORB, Opponent_TOV):
Opponent_Team_Possessions = Opponent_FGA + 0.44 * Opponent_FTA - Opponent_ORB + Opponent_TOV
return Opponent_Team_Possessions
def calculate_opponent_team_d_pts_per_scposs(Opponent_PTS, Opponent_FGM, Opponent_FTA, Opponent_FTM):
if Opponent_FTA == 0 or (Opponent_FGM + (1 - (1 - (Opponent_FTM / Opponent_FTA))**2) * Opponent_FTA * 0.4) == 0:
return 0
D_Pts_per_Scposs = Opponent_PTS / (Opponent_FGM + (1 - (1 - (Opponent_FTM / Opponent_FTA))**2) * Opponent_FTA * 0.4)
return D_Pts_per_Scposs
def calculate_opponent_team_defensive_rating(Opponent_PTS, Opponent_Team_Possessions):
if Opponent_Team_Possessions == 0:
return 0
Team_Defensive_Rating = 100 * (Opponent_PTS / Opponent_Team_Possessions)
return Team_Defensive_Rating
def calculate_OR_Part(ORB, Team_OR_Weight, Team_Play_Percentage):
return ORB * Team_OR_Weight * Team_Play_Percentage
def calculate_FT_Part(FTM, FTA):
if FTA == 0:
return 0
return 0.4 * FTA * (1 - (1 - FTM/FTA)**2)
def calculate_AST_Part(PTS, FTM, FGA, Team_PTS, Team_FTM, Team_FGA, AST):
if (Team_FGA - FGA) == 0:
return 0
non_FT_PTS = Team_PTS - Team_FTM
player_non_FT_PTS = PTS - FTM
AST_Part = 0.5 * ((non_FT_PTS - player_non_FT_PTS) / (2 * (Team_FGA - FGA))) * AST
return AST_Part
def calculate_qAST(MIN, Team_MIN, AS, Team_FGM, FGM, Team_AS):
if Team_MIN == 0 or Team_FGM == 0:
return 0
proportion_of_time_played = MIN / (Team_MIN / 5)
if ((Team_FGM / Team_MIN) * MIN * 5 - FGM) == 0:
second_part = 0
else:
second_part = (((Team_AS / Team_MIN) * MIN * 5 - AS) / ((Team_FGM / Team_MIN) * MIN * 5 - FGM)) * (1 - proportion_of_time_played)
qAST = (proportion_of_time_played * (1.14 * ((Team_AS - AS) / Team_FGM))) + second_part
return qAST
def calculate_FG_Part(FGM, PTS, FTM, FGA, qAST):
if FGA == 0:
return 0
FG_Part = FGM * (1 - 0.5 * ((PTS - FTM) / (2 * FGA)) * qAST)
return FG_Part
def calculate_ScPoss(FG_Part, AST_Part, FT_Part, OR_Part, Team_OR, Team_Scoring_Poss, Team_OR_Weight, Team_Play):
if Team_Scoring_Poss == 0:
return 0
ScPoss = (FG_Part + AST_Part + FT_Part) * (1 - (Team_OR / Team_Scoring_Poss) * Team_OR_Weight * Team_Play) + OR_Part
return ScPoss
def calculate_FGxPoss(FGA, FGM, Team_OR_percent):
FGxPoss = (FGA - FGM) * (1 - 1.07 * Team_OR_percent)
return FGxPoss
def calculate_FTxPoss(FTM, FTA):
if FTA == 0:
return 0
FTxPoss = ((1 - (FTM / FTA))**2) * 0.4 * FTA
return FTxPoss
def calculate_TotPoss(ScPoss, FGxPoss, FTxPoss, TOV):
TotPoss = ScPoss + FGxPoss + FTxPoss + TOV
return TotPoss
def calculate_PProd_FG_Part(FGM, ThreeFGM, PTS, FTM, FGA, qAST):
if FGA == 0:
return 0
PProd_FG_Part = 2 * (FGM + 0.5 * ThreeFGM) * (1 - 0.5 * ((PTS - FTM) / (2 * FGA)) * qAST)
return PProd_FG_Part
def calculate_PProd_AS_Part(Team_FGM, FGM, Team_3FGM, ThreeFGM, Team_PTS, Team_FTM, PTS, FTM, Team_FGA, FGA, AS):
if (Team_FGM - FGM) == 0 or (Team_FGA - FGA) == 0:
return 0
assist_factor = 2 * ((Team_FGM - FGM + 0.5 * (Team_3FGM - ThreeFGM)) / (Team_FGM - FGM))
non_FT_PTS_contribution = 0.5 * (((Team_PTS - Team_FTM) - (PTS - FTM)) / (2 * (Team_FGA - FGA)))
PProd_AS_Part = assist_factor * non_FT_PTS_contribution * AS
return PProd_AS_Part
def calculate_PProd_OR_Part(OR, Team_OR_Weight, Team_Play, Team_PTS, Team_FGM, Team_FTM, Team_FTA):
if Team_FTA == 0 or (Team_FGM + (1 - (1 - (Team_FTM / Team_FTA))**2) * 0.4 * Team_FTA) == 0:
return 0
scoring_contribution = Team_PTS / (Team_FGM + (1 - (1 - (Team_FTM / Team_FTA))**2) * 0.4 * Team_FTA)
PProd_OR_Part = OR * Team_OR_Weight * Team_Play * scoring_contribution
return PProd_OR_Part
def calculate_PProd(PProd_FG_Part, PProd_AS_Part, PProd_OR_Part, FTM, OR, ScPoss, Team_OR_Weight, Team_Play):
if ScPoss == 0:
return 0
PProd = (PProd_FG_Part + PProd_AS_Part + FTM) * (1 - (OR / ScPoss) * Team_OR_Weight * Team_Play) + PProd_OR_Part
return PProd
def calculate_Stops1(ST, BS, FMwt, DR_percentage, DR):
Stops1 = ST + BS * FMwt * (1 - 1.07 * DR_percentage) + DR * (1 - FMwt)
return Stops1
def calculate_Stops2(Opponent_FGA, Opponent_FGM, Team_BS, Team_MIN, FMwt, DR_percentage, Opponent_TOV, Team_ST, MIN, F, Team_F, Opponent_FTA, Opponent_FTM):
if Team_MIN == 0 or Team_F == 0 or Opponent_FTA == 0:
return 0
term1 = ((Opponent_FGA - Opponent_FGM - Team_BS) / Team_MIN) * FMwt * (1 - 1.07 * DR_percentage)
term2 = ((Opponent_TOV - Team_ST) / Team_MIN) * MIN
term3 = (F / Team_F) * 0.4 * Opponent_FTA * (1 - (Opponent_FTM / Opponent_FTA))**2
Stops2 = term1 + term2 + term3
return Stops2
def calculate_stop_percentage(Stops, Opponent_MP, Opponent_Team_Possessions, MP):
if Opponent_Team_Possessions == 0 or MP == 0:
return 0
Stop_percentage = (Stops * Opponent_MP) / (Opponent_Team_Possessions * MP)
return Stop_percentage
def calculate_defensive_rating(Team_Defensive_Rating, D_Pts_per_ScPoss, Stop_percentage):
DRtg = Team_Defensive_Rating + 0.2 * (100 * D_Pts_per_ScPoss * (1 - Stop_percentage) - Team_Defensive_Rating)
return DRtg
# データ収集と計算
def collect_and_calculate_data(tgt_team):
conn = connect_db()
if conn is None:
return
team_data = get_team_data(tgt_team[0], conn)
opponent_data = get_team_data(tgt_team[1], conn)
# データ集計
team = team_data.sum()
opponent = opponent_data.sum()
# チーム指標の計算
team_scoring_poss = calculate_team_scoring_poss(team['fgm'], team['ftm'], team['fta'])
team_play_percent = calculate_team_play_percentage(team_scoring_poss, team['fga'], team['fta'], team['tov'])
team_orb_percentage = calculate_team_or_percentage(team['orb'], opponent['drb'])
team_orb_weight = calculate_team_or_weight(team_orb_percentage, team_play_percent)
team_drb_percentage = calculate_team_dr_percentage(opponent['orb'], team['drb'])
team_dfg_percentage = calculate_team_dfg_percentage(opponent['fgm'], opponent['fga'])
team_fmwt = calculate_team_fmwt(team_dfg_percentage, team_drb_percentage)
opponent_team_possessions = calculate_opponent_team_possessions(opponent['fga'], opponent['fta'], opponent['orb'], opponent['tov'])
opponent_team_d_pts_per_scposs = calculate_opponent_team_d_pts_per_scposs(opponent['pts'], opponent['fgm'], opponent['fta'], opponent['ftm'])
opponent_team_defensive_rating = calculate_opponent_team_defensive_rating(opponent['pts'], opponent_team_possessions)
# プレイヤー指標を計算
for index, player in team_data.iterrows():
player_or_part = calculate_OR_Part(player['orb'], team_orb_weight, team_play_percent)
player_ft_part = calculate_FT_Part(player['ftm'], player['fta'])
player_ast_part = calculate_AST_Part(player['pts'], player['ftm'], player['fga'], team['pts'], team['ftm'], team['fga'], player['asst'])
player_qast = calculate_qAST(player['minute'], team['minute'], player['asst'], team['fgm'], player['fgm'], team['asst'])
player_fg_part = calculate_FG_Part(player['fgm'], player['pts'], player['ftm'], player['fga'], player_qast)
player_scposs = calculate_ScPoss(player_fg_part, player_ast_part, player_ft_part, player_or_part, team['orb'], team_scoring_poss, team_orb_weight, team_play_percent)
player_fgxposs = calculate_FGxPoss(player['fga'], player['fgm'], team_orb_percentage)
player_ftxposs = calculate_FTxPoss(player['ftm'], player['fta'])
player_totposs = calculate_TotPoss(player_scposs, player_fgxposs, player_ftxposs, player['tov'])
player_pprod_fg_part = calculate_PProd_FG_Part(player['fgm'], player['tfgm'], player['pts'], player['ftm'], player['fga'], player_qast)
player_pprod_as_part = calculate_PProd_AS_Part(team['fgm'], player['fgm'], team['tfgm'], player['tfgm'], team['pts'], team['ftm'], player['pts'], player['ftm'], team['fga'], player['fga'], player['asst'])
player_pprod_or_part = calculate_PProd_OR_Part(player['orb'], team_orb_weight, team_play_percent, team['pts'], team['fgm'], team['ftm'], team['fta'])
player_pprod = calculate_PProd(player_pprod_fg_part, player_pprod_as_part, player_pprod_or_part, player['ftm'], player['orb'], player_scposs, team_orb_weight, team_play_percent)
player_ortg = 100 * (player_pprod / player_totposs)
player_stops1 = calculate_Stops1(player['st'], player['bs'], team_fmwt, team_drb_percentage, player['drb'])
player_stops2 = calculate_Stops2(opponent['fga'], opponent['fgm'], team['bs'], team['minute'], team_fmwt, team_drb_percentage, opponent['tov'], team['st'], player['minute'], player['f'], team['f'], opponent['fta'], opponent['ftm'])
player_stops = player_stops1 + player_stops2
player_stop_percentage = calculate_stop_percentage(player_stops, opponent['minute'], opponent_team_possessions, player['minute'])
player_drtg = calculate_defensive_rating(opponent_team_defensive_rating, opponent_team_d_pts_per_scposs, player_stop_percentage)
print(f"{player['name']}: ORtg = {round(player_ortg,2)} / DRtg = {round(player_drtg,2)}")
conn.close()
# UIイベントハンドラ
def show_selected(event):
if combobox_t.get() and combobox_o.get():
match_up = [combobox_t.get(), combobox_o.get()]
collect_and_calculate_data(match_up)
combobox_t.set('')
combobox_o.set('')
# UIの初期化
root = Tk()
root.title('Match_up')
# チームリスト
teams = ['北海道', '仙台', '秋田', '茨城', '宇都宮', '群馬', '千葉J', 'A東京', 'SR渋谷', '川崎', '横浜BC', '富山', '信州', '三遠', '三河', 'FE名古屋', '名古屋D', '京都', '大阪', '島根', '広島', '佐賀', '長崎', '琉球']
combobox_t = ttk.Combobox(master=root, values=teams)
combobox_o = ttk.Combobox(master=root, values=teams)
combobox_t.bind('<<ComboboxSelected>>', show_selected)
combobox_o.bind('<<ComboboxSelected>>', show_selected)
combobox_t.pack()
combobox_o.pack()
root.mainloop()