here is the code

import argparse
import csv
import math
import os
from collections import Counter
from typing import List

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

PARENT\_DIR = os.path.dirname(os.path.realpath(\_\_file\_\_))

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,
}
@dataclasses.dataclass
class Team:
 team\_name: str
 team\_seed: int
 ken\_pom\_score: float

 @classmethod
 def extract\_teams(cls, file\_path: str):
 with open(os.path.join(PARENT\_DIR, file\_path), "r", newline="") as csvfile:
 return [cls(
 team\_name=row["team"],
 team\_seed=int(row["seed"]),
 ken\_pom\_score=float(row["score"])
 ) for row in (csv.DictReader(csvfile))]
class Tournament:

 def \_\_init\_\_(self, team\_metrics: List[Team]):
 self.team\_metrics: List[Team] = team\_metrics
 self.team\_names = [team.team\_name for team in team\_metrics]
 self.teams = {i: team.team\_name for i, team in enumerate(team\_metrics)}
 self.k = self.find\_best\_k()
 self.adj\_matrix = self.calculate\_adj\_matrix()

 num\_teams = len(self.teams)
 self.num\_rounds = int(math.log2(num\_teams))

 self.round\_winners = {0: list(self.teams.keys())}
 self.round\_win\_counts = {}
 # Construct the bracket
 num\_matches = num\_teams // 2
 self.bracket = {}
 for round\_num in range(1, self.num\_rounds + 1):
 self.bracket[round\_num] = list(range(num\_matches))
 num\_matches //= 2

 # Used for printing results
 self.round\_names = {
 1: "Round of 64",
 2: "Round of 32",
 3: "Sweet Sixteen",
 4: "Elite Eight",
 5: "Final Four",
 6: "Championship",
 }
 self.round\_spacing = {
 1: 2,
 2: 4,
 3: 8,
 4: 16,
 5: 32,
 6: 64,
 }

 def get\_opponent(self, round\_num, team\_index):
 if round\_num == 0:
 opponent\_index = team\_index + 1 if team\_index % 2 == 0 else team\_index - 1
 else:
 previous\_round\_winners = self.round\_winners[round\_num - 1]
 print(f"Previous round winners: {previous\_round\_winners}") # Debugging print
 team\_position = previous\_round\_winners.index(team\_index)
 opponent\_index = previous\_round\_winners[team\_position + 1 if team\_position % 2 == 0 else team\_position - 1]

 print(f"Team index: {team\_index}, Opponent index: {opponent\_index}") # Debugging print
 return opponent\_index

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

 for i, team\_i in enumerate(self.team\_metrics):
 for j, team\_j in enumerate(self.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

 def calculate\_win\_probability(self, team\_i: Team, team\_j: Team):
 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(self.k \* (ken\_pom\_diff + seed\_diff))

 def play\_single\_round(self, remaining\_teams):
 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
 winning\_team\_index = team\_i if win\_i else team\_j
 winners.append(winning\_team\_index)

 return winners

 def get\_remaining\_teams(self, round\_num):
 if round\_num == 0:
 return list(range(len(self.teams)))

 remaining\_teams = []
 for i, team in enumerate(self.teams):
 if self.round\_winners[round\_num - 1].count(team) > 0:
 remaining\_teams.append(i)

 return remaining\_teams

 def simulate\_round\_n(self, round\_num, num\_simulations):
 round\_win\_counts = Counter()

 for \_ in range(num\_simulations):
 remaining\_teams = self.get\_remaining\_teams(round\_num)
 winners = self.play\_single\_round(remaining\_teams)
 for winner in winners:
 round\_win\_counts[self.teams[winner]] += 1

 # Update the round\_winners and round\_win\_counts
 sorted\_teams = sorted(round\_win\_counts.items(), key=lambda x: x[1], reverse=True)
 self.round\_winners[round\_num] = [team for i, (team, count) in enumerate(sorted\_teams) if i % 2 == 0]
 self.round\_win\_counts[round\_num] = round\_win\_counts

 return round\_win\_counts

 def run\_all\_rounds(self, num\_simulations):
 for round\_num in range(1, self.num\_rounds + 1): # Iterate through all rounds in the tournament
 round\_win\_counts = self.simulate\_round\_n(round\_num, num\_simulations)
 print(f"{self.round\_names[round\_num]} results:")
 for i, (team\_index, count) in enumerate(round\_win\_counts.most\_common()):
 print(f"Team index: {team\_index}") # Debugging print
 team = self.teams[team\_index]
 opponent\_index = self.get\_opponent(round\_num, team\_index)
 opponent = self.teams[opponent\_index]
 win\_percentage = (count / num\_simulations) \* 100
 print(f" {i + 1}. {team} over {opponent} with {win\_percentage:.2f}%")
 print()

 @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
if \_\_name\_\_ == "\_\_main\_\_":
 parser = argparse.ArgumentParser(
 description="NCAA Tournament Simulation"
 )
 parser.add\_argument(
 '-f', '--file',
 default='2023ncaab.csv',
 help="Path to the data file (default: '2023ncaab.csv')"
 )
 parser.add\_argument(
 '-n', '--num-simulations',
 type=int,
 default=100000,
 help="Number of simulations to run (default: 100000)"
 )
 args = parser.parse\_args()
 teams = Team.extract\_teams(args.file)
 tournament = Tournament(teams)
 tournament.run\_all\_rounds(args.num\_simulations)
and the error

Team index: purd
Traceback (most recent call last):
 File "/home/blake/workspace/gpt-madness/tournament.py", line 214, in 
 tournament.run\_all\_rounds(args.num\_simulations)
 File "/home/blake/workspace/gpt-madness/tournament.py", line 159, in run\_all\_rounds
 team = self.teams[team\_index]
KeyError: 'purd'
코드는 다음과 같습니다.import argparseimport csvimport mathimport os컬렉션에서 임포트 카운터입력에서 임포트 목록데이터 클래스 임포트numpy를 np로 임포트numpy.ma에서 exp 임포트scipy.optimize에서 가져 오기 최소화\_스칼라from scipy.special import expitPARENT\_DIR = os.path.dirname(os.path.realpath(\_\_file\_\_))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,}@dataclasses.dataclass팀 클래스: team\_name: str 팀\_씨앗: int ken\_pom\_score: float @classmethod def extract\_teams(cls, file\_path: str): with open(os.path.join(PARENT\_DIR, file\_path), "r", newline="") as csvfile: return [cls( team\_name=row["team"], team\_seed=int(row["seed"]), ken\_pom\_score=float(row["score"]) ) for row in (csv.DictReader(csvfile))]토너먼트 클래스: def \_\_init\_\_(self, team\_metrics: List[Team]): self.team\_metrics: List[Team] = team\_metrics self.team\_names = [team\_metrics의 팀에 대한 팀.팀\_이름] self.teams = {i: 팀에 대한 팀.팀\_이름, 팀에 대한 열거(팀\_메트릭)} self.k = self.find\_best\_k() self.adj\_matrix = self.calculate\_adj\_matrix() num\_teams = len(self.teams) self.num\_rounds = int(math.log2(num\_teams)) self.round\_winners = {0: list(self.teams.keys())} self.round\_win\_counts = {} # 대진표 구성 num\_matches = num\_teams // 2 self.bracket = {} for round\_num in range(1, self.num\_rounds + 1): self.bracket[round\_num] = list(range(num\_matches)) num\_matches //= 2 # 결과 인쇄에 사용 self.round\_names = { 1: "64의 라운드", 2: "32강" 3: "스위트 식스틴", 4: "엘리트 8강", 5: "파이널 4", 6: "챔피언십", } self.round\_spacing = { 1: 2, 2: 4, 3: 8, 4: 16, 5: 32, 6: 64, } def get\_opponent(self, round\_num, team\_index): if round\_num == 0: opponent\_index = team\_index + 1 if team\_index % 2 == 0 else team\_index - 1 else: 이전\_라운드\_승자 = self.round\_승자[round\_num - 1] print(f"이전 라운드 우승자: {previous\_round\_winners}") # 디버깅 인쇄 팀\_포지션 = 이전\_라운드\_승자.인덱스(팀\_인덱스) 상대\_인덱스 = 이전\_라운드\_승자[팀\_포지션 + 1 if team\_포지션 % 2 == 0 else team\_포지션 - 1] print(f"팀 인덱스: {team\_index}, 상대 인덱스: {opponent\_index}") # 디버깅 인쇄 반환 상대\_인덱스 def calculate\_adj\_matrix(self): num\_teams = len(self.team\_metrics) adj\_matrix = np.zeros((num\_teams, num\_teams)) for i, team\_i in enumerate(self.team\_metrics): for j, team\_j in enumerate(self.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 calculate\_win\_probability(self, team\_i: 팀, team\_j: 팀): 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(self.k \* (ken\_pom\_diff + seed\_diff)) def play\_single\_round(self, remaining\_teams): 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 winning\_team\_index = team\_i if win\_i else team\_j winners.append(winning\_team\_index) 우승자 반환 def get\_remaining\_teams(self, round\_num): if round\_num == 0: return list(range(len(self.teams))) remaining\_teams = [] for i, team in enumerate(self.teams): if self.round\_winners[round\_num - 1].count(team) > 0: remaining\_teams.append(i) 반환 남은\_팀 def simulate\_round\_n(self, round\_num, num\_simulations): round\_win\_counts = Counter() for \_ in range(num\_simulations): 남은\_팀 = self.get\_remaining\_팀(round\_num) winners = self.play\_single\_round(remaining\_teams) 승자의 경우 라운드\_승리\_counts[self.teams[winner]] += 1 # 라운드\_승자 및 라운드\_승수\_count 업데이트 sorted\_teams = sorted(round\_win\_counts.items(), key=lambda x: x[1], reverse=True) self.round\_winners[round\_num] = [team for i, (team, count) in enumerate(sorted\_teams) if i % 2 == 0] self.round\_win\_counts[round\_num] = round\_win\_counts 반환 라운드\_승수\_counts def run\_all\_rounds(self, num\_simulations): for round\_num in range(1, self.num\_rounds + 1): # 토너먼트의 모든 라운드를 반복합니다. round\_win\_counts = self.simulate\_round\_n(round\_num, num\_simulations) print(f"{self.round\_names[round\_num]} results:") for i, (team\_index, count) in enumerate(round\_win\_counts.most\_common()): print(f"팀 인덱스: {team\_index}") # 디버깅 인쇄 team = self.teams[team\_index] 상대\_인덱스 = self.get\_opponent(라운드\_넘버, 팀\_인덱스) 상대 = self.teams[상대\_index] win\_percentage = (카운트/넘수\_simulations) \* 100 print(f" {i + 1}. {팀}이 {상대팀}을 {승률\_퍼센트:.