this is what I have so far

from collections import defaultdict
from typing import List

import numpy as np
from numpy.ma import exp
from scipy.optimize import minimize, minimize\_scalar
from scipy.special import expit

from ncaa.round\_winners import RoundWinners
from ncaa.team\_metric import TeamMetric

HISTORICAL\_SEED\_WIN\_RATES = {
 (1, 16): 1.000,
 (2, 15): 0.917,
 (3, 14): 0.833,
 (4, 13): 0.750,
 (5, 12): 0.667,
 (6, 11): 0.583,
 (7, 10): 0.583,
 (8, 9): 0.500,
}
class Tournament:
 def \_\_init\_\_(self, team\_metrics: List[TeamMetric]):
 self.teams = [team\_metric.team\_name for team\_metric in team\_metrics]
 self.adj\_matrix = self.calculate\_adj\_matrix(team\_metrics)
 self.k = self.find\_best\_k()
 self.round\_winners = {}

 def calculate\_adj\_matrix(self, team\_metrics: List[TeamMetric]):
 num\_teams = len(team\_metrics)
 adj\_matrix = np.zeros((num\_teams, num\_teams))

 for i, team\_i in enumerate(team\_metrics):
 for j, team\_j in enumerate(team\_metrics):
 if i != j:
 p\_win = self.calculate\_win\_probability(team\_i, team\_j)
 adj\_matrix[i, j] = p\_win
 adj\_matrix[j, i] = 1 - p\_win

 return adj\_matrix

 @staticmethod
 def error\_function(k, average\_kenpom\_difference):
 error = 0
 for matchup, historical\_probability in HISTORICAL\_SEED\_WIN\_RATES.items():
 difference = average\_kenpom\_difference[matchup]
 probability = 1 / (1 + exp(-k \* difference))
 error += (probability - historical\_probability) \*\* 2
 return error

 @staticmethod
 def average\_kenpom\_difference(max\_seed=16, kenpom\_range=(0, 40)):
 min\_kenpom, max\_kenpom = kenpom\_range
 kenpom\_increment = (max\_kenpom - min\_kenpom) / max\_seed
 average\_difference = {}

 for higher\_seed in range(1, max\_seed + 1):
 for lower\_seed in range(higher\_seed + 1, max\_seed + 1):
 higher\_seed\_kenpom = max\_kenpom - (higher\_seed - 1) \* kenpom\_increment
 lower\_seed\_kenpom = max\_kenpom - (lower\_seed - 1) \* kenpom\_increment
 average\_difference[(higher\_seed, lower\_seed)] = higher\_seed\_kenpom - lower\_seed\_kenpom

 return average\_difference

 @staticmethod
 def find\_best\_k():
 average\_difference = Tournament.average\_kenpom\_difference()
 result = minimize\_scalar(Tournament.error\_function, args=(average\_difference,))
 return result.x

 @staticmethod
 def calculate\_win\_probability(team\_i: TeamMetric, team\_j: TeamMetric, k: float):
 seed\_diff = team\_j.team\_seed - team\_i.team\_seed
 ken\_pom\_diff = team\_i.ken\_pom\_score - team\_j.ken\_pom\_score
 return expit(k \* (ken\_pom\_diff + seed\_diff))

 def play\_rounds(self):
 remaining\_teams = list(range(len(self.teams)))
 round\_num = 0

 while len(remaining\_teams) > 1:
 winners = []
 for i in range(0, len(remaining\_teams), 2):
 team\_i = remaining\_teams[i]
 team\_j = remaining\_teams[i + 1]

 p\_win\_i = self.adj\_matrix[team\_i, team\_j]
 win\_i = np.random.rand() < p\_win\_i

 winner = team\_i if win\_i else team\_j
 winners.append(winner)

 self.round\_winners[round\_num] = [self.teams[i] for i in winners]
 remaining\_teams = winners
 round\_num += 1

 def run\_simulations(self, num\_simulations):
 simulation\_results = defaultdict(int)

 for \_ in range(num\_simulations):
 self.play\_rounds()
 winner = self.teams[self.round\_winners[len(self.round\_winners) - 1][0]]
 simulation\_results[winner] += 1

 # Convert to probability
 for team in simulation\_results:
 simulation\_results[team] /= num\_simulations

 round\_winners = RoundWinners(self.round\_winners)
 return simulation\_results, round\_winners
이것이 내가 지금까지 가지고있는 것입니다.컬렉션에서 기본 딕셔너리 가져 오기를 입력해서 목록 가져오기numpy를 np로 임포트numpy.ma에서 exp 임포트scipy.optimize에서 가져 오기 최소화, 최소화 \_ 스칼라from scipy.special import expitncaa.round\_winners에서 RoundWinners 가져오기ncaa.team\_metric에서 TeamMetric 가져오기historical\_seed\_win\_rates = { (1, 16): 1.000, (2, 15): 0.917, (3, 14): 0.833, (4, 13): 0.750, (5, 12): 0.667, (6, 11): 0.583, (7, 10): 0.583, (8, 9): 0.500,}토너먼트 클래스: def \_\_init\_\_(self, team\_metrics: List[TeamMetric]): self.teams = [team\_metrics의 팀\_metric에 대한 팀\_metric.team\_이름] self.adj\_matrix = self.calculate\_adj\_matrix(team\_metrics) self.k = self.find\_best\_k() self.round\_winners = {} def calculate\_adj\_matrix(self, team\_metrics: List[TeamMetric]): num\_teams = len(team\_metrics) adj\_matrix = np.zeros((num\_teams, num\_teams)) for i, team\_i in enumerate(team\_metrics): for j, team\_j in enumerate(team\_metrics): IF I != J: p\_win = self.calculate\_win\_probability(team\_i, team\_j) adj\_matrix[i, j] = p\_win adj\_matrix[j, i] = 1 - p\_win 반환 adj\_matrix 정적 메서드 def error\_function(k, average\_kenpom\_difference): error = 0 매치업의 경우, HISTORICAL\_SEED\_WIN\_RATES.items()의 historical\_probability: 차이 = 평균\_켄폼\_차이[매치업] 확률 = 1 / (1 + exp(-k \* 차이)) error += (확률 - 과거\_확률) \*\* 2 반환 오류 정적 메서드 def average\_kenpom\_difference(max\_seed=16, kenpom\_range=(0, 40)): MIN\_KENPOM, MAX\_KENPOM = KENPOM\_RANGE kenpom\_increment = (max\_kenpom - min\_kenpom) / max\_seed 평균\_차이 = {} 범위(1, 최대\_씨드 + 1)에서 더 높은\_씨드의 경우: FOR LOWER\_SEED IN RANGE(HIGHER\_SEED + 1, MAX\_SEED + 1): higher\_seed\_kenpom = max\_kenpom - (higher\_seed - 1) \* kenpom\_increment lower\_seed\_kenpom = max\_kenpom - (lower\_seed - 1) \* kenpom\_increment average\_difference[(higher\_seed, lower\_seed)] = higher\_seed\_kenpom - lower\_seed\_kenpom 반환 평균\_difference @staticmethod def find\_best\_k(): average\_difference = Tournament.average\_kenpom\_difference() result = minimize\_scalar(Tournament.error\_function, args=(average\_difference,)) 반환 결과.x 정적 메서드 def calculate\_win\_probability(team\_i: 팀메트릭, team\_j: 팀메트릭, k: float): seed\_diff = team\_j.team\_seed - team\_i.team\_seed ken\_pom\_diff = team\_i.ken\_pom\_score - team\_j.ken\_pom\_score return expit(k \* (ken\_pom\_diff + seed\_diff)) def play\_rounds(self): remaining\_teams = list(range(len(self.teams))) round\_num = 0 while len(remaining\_teams) > 1: winners = [] for i in range(0, len(remaining\_teams), 2): team\_i = remaining\_teams[i] team\_j = 남은\_팀[i + 1] p\_win\_i = self.adj\_matrix[team\_i, team\_j] win\_i = np.random.rand() < p\_win\_i winner = team\_i if win\_i else team\_j winners.append(winner) self.round\_winners[round\_num] = [self.teams[i] for i in winners] 남은\_팀 = 우승자 round\_num += 1 def run\_simulations(self, num\_simulations): 시뮬레이션\_결과 = 기본 딕셔너리(int) for \_ in range(num\_simulations): self.play\_rounds() winner = self.teams[self.round\_winners[len(self.round\_winners) - 1][0]] simulation\_results[winner] += 1 # 확률로 변환 확률로 변환합니다: 시뮬레이션\_결과[팀] /= num\_simulations 라운드\_승자 = 라운드승자(self.round\_승자) 반환 시뮬레이션\_결과, 라운드\_승자