vignesh-99/nfl
0
1 2from collections import Counter3import numpy as np4import seaborn as sns5import matplotlib.pyplot as plt6import pandas as pd7from concurrent.futures import ThreadPoolExecutor8import os9 10 11TRAIN_INPUT_FILE_PATH = 'C:/Users/vigne/nfl/train_input'12TRAIN_OUTPUT_FILE_PATH = 'C:/Users/vigne/nfl/train_output'13 14 15def get_train_file_paths():16 17 def get_output_file(input_filename):18 return input_filename.replace('input', 'output')19 20 input_file_paths = []21 output_file_paths = []22 input_files_dir = TRAIN_INPUT_FILE_PATH23 for w in range(1, 19):24 input_filename = f'input_2023_w{w:02d}.csv'25 if os.path.isfile(f'{input_files_dir}/{input_filename}'):26 output_filename = get_output_file(input_filename)27 input_file_path = os.path.join(TRAIN_INPUT_FILE_PATH, input_filename)28 output_file_path = os.path.join(TRAIN_OUTPUT_FILE_PATH, output_filename)29 input_file_paths.append(input_file_path)30 output_file_paths.append(output_file_path)31 else:32 raise Exception(f'input file for week {w} does not exist')33 34 return (input_file_paths, output_file_paths)35 36def load_file(file_path):37 return pd.read_csv(file_path)38 39def get_input_output_df():40 input_file_paths, output_file_paths = get_train_file_paths()41 42 with ThreadPoolExecutor(max_workers = 8) as executor:43 input_dfs = executor.map(load_file, input_file_paths)44 input_df = pd.concat(input_dfs, axis=0)45 46 with ThreadPoolExecutor(max_workers = 8) as executor:47 output_dfs = executor.map(load_file, output_file_paths)48 output_df = pd.concat(output_dfs, axis=0)49 50 return input_df.reset_index(drop=True), output_df.reset_index(drop=True)51 52def plot_distribution_of_features(input_df, output_df):53 predict_players_position = Counter()54 predict_players_role = Counter()55 predict_players_side = Counter()56 57 num_frames_to_predict = Counter()58 no_players_prediction_in_a_play = Counter()59 60 61 plays = input_df.groupby(['game_id', 'play_id'], as_index = False)62 63 per_play_change_in_dists = []64 per_frame_change_in_dists = []65 per_frame_change_in_x_dists = []66 per_frame_change_in_y_dists = []67 for _, play in plays:68 69 predict_players = play[play['player_to_predict']]70 71 no_players_prediction_in_a_play[predict_players['nfl_id'].nunique()]+=172 73 74 num_frames_output = play['num_frames_output'].iloc[0].item()75 num_frames_to_predict[num_frames_output]+=176 77 predict_players_last_frame = predict_players.groupby(['nfl_id'], as_index=False).last()78 for index, p_l in predict_players_last_frame.iterrows():79 game_id = p_l['game_id']80 play_id = p_l['play_id']81 p_nfl_id = p_l['nfl_id']82 p_output = output_df[(output_df['game_id'] == game_id) & (output_df['play_id'] == play_id) & (output_df['nfl_id'] == p_nfl_id)]83 84 85 s = np.array([p_l['x'], p_l['y']])86 87 total_dis = 088 for _,p_o in p_output.iterrows():89 e = np.array([p_o['x'].item(), p_o['y'].item()])90 current_dis = np.linalg.norm(e - s)91 per_frame_change_in_dists.append(current_dis)92 per_frame_change_in_x_dists.append(np.abs(e[0] - s[0]))93 per_frame_change_in_y_dists.append(np.abs(e[1] - s[1]))94 95 total_dis+= current_dis96 s = e97 98 per_play_change_in_dists.append(total_dis)99 100 101 position = p_l['player_position']102 role = p_l['player_role']103 side = p_l['player_side']104 105 predict_players_position[position]+=1106 predict_players_role[role]+=1107 predict_players_side[side]+=1108 109 def plot_bargraph(dict_items, name):110 plt.figure(figsize=(10, 6))111 df = pd.DataFrame(list(dict_items), columns = [name, 'count'])112 df = df.sort_values(by='count', ascending=False)113 sns.barplot(data=df, x=name, y='count')114 plt.show()115 116 117 plot_bargraph(predict_players_position.items(), 'predict_player position')118 plot_bargraph(predict_players_role.items(), 'predict_player role')119 plot_bargraph(predict_players_side.items(), 'predict_player side')120 121 plot_bargraph(no_players_prediction_in_a_play.items(), 'num of player to predict in a play')122 plot_bargraph(num_frames_to_predict.items(), 'num of frames to predict in a play')123 124 125 def plot_density_plot(data, title, x):126 plt.figure(figsize=(10, 6))127 sns.kdeplot(data, fill=True, color="dodgerblue")128 plt.title(title)129 plt.xlabel(x)130 plt.ylabel('Density')131 plt.show()132 133 134 plot_density_plot(per_play_change_in_dists, 'total distance moved by a player in a play', 'distance')135 plot_density_plot(per_frame_change_in_dists, 'distance moved by a player per frame', 'distance')136 plot_density_plot(per_frame_change_in_x_dists, 'distance moved by a player along x per frame', 'distance')137 plot_density_plot(per_frame_change_in_y_dists, 'distance moved by a player along y per frame', 'distance')138 139 140def get_last_frame(df):141 142 df_sorted = df.sort_values(['game_id', 'play_id', 'nfl_id', 'frame_id']).reset_index(drop=True)143 144 group_by_cols = ['game_id', 'play_id', 'nfl_id']145 146 feature_cols = ['x', 'y', 'o', 'dir', 's', 'a']147 148 df_sorted[[f'{c}_prev' for c in feature_cols]] = df_sorted.groupby(group_by_cols)[feature_cols].shift(1)149 150 #last() takes non none values from the last possible col151 #so even if last frame misses a feature , value is taken from the previous available one152 df_last_frame = df_sorted.groupby(group_by_cols, as_index=False).last()153 154 df_last_frame = df_last_frame.rename(columns={'x':'x_last', 'y':'y_last'})155 156 return df_last_frame157 158 159def predict_physics_baseline(input_df, output_df):160 161 def convert_to_radians(degrees):162 return degrees * np.pi / 180163 164 def sin(theta):165 return np.sin(convert_to_radians(theta))166 167 def cos(theta):168 return np.cos(convert_to_radians(theta))169 170 171 input_df = input_df.copy()172 173 output_df = output_df.copy()174 175 df_last_frame = get_last_frame(input_df)176 177 df_last_frame = df_last_frame[['game_id', 'play_id', 'nfl_id', 'x_last', 'y_last', 'o', 'dir', 's', 'a', 'num_frames_output']]178 179 df = output_df.merge(df_last_frame, on=['game_id', 'play_id', 'nfl_id'], how='left')180 181 sum_ = 0182 for _, group_df in df.groupby(['game_id', 'play_id', 'nfl_id'], as_index=False):183 184 group_df = group_df.sort_values('frame_id').reset_index(drop=True)185 186 prev = (group_df.iloc[0]['x'], group_df.iloc[0]['y'])187 for row in group_df.itertuples():188 dt = 0.1189 190 velocity_x = row.s * sin(row.dir)191 velocity_y_ = row.s * cos(row.dir)192 acc_x_ = row.a * sin(row.dir)193 acc_y_ = row.a * cos(row.dir)194 195 proj_x = prev[0] + velocity_x*dt + 0.5*acc_x_*(dt**2)196 proj_y = prev[1] + velocity_y_*dt + 0.5*acc_y_*(dt**2)197 198 sum_+= (row.x - proj_x)**2 + (row.y - proj_y)**2199 prev = (proj_x, proj_y)200 201 num_ele = df.shape[0]*2202 rmse = np.sqrt(sum_ / num_ele)203 print(f'RMSE of the simple physics based model is {rmse}')204 205 206input_df, output_df = get_input_output_df()207POSITION_MAPPING = [208 "FS --> Free Safety",209 "SS --> Strong Safety",210 "CB --> Cornerback",211 "MLB --> Middle Linebacker",212 "WR --> Wide Receiver",213 "TE --> Tight End",214 "QB --> Quarterback",215 "OLB --> Outside Linebacker",216 "ILB --> Inside Linebacker",217 "RB --> Running Back",218 "DE --> Defensive End",219 "FB --> Fullback",220 "NT --> Nose Tackle",221 "DT --> Defensive Tackle",222 "S --> Safety",223 "T --> Tackle",224 "LB --> Linebacker",225 "P --> Punter",226 "K --> Kicker"227]228 229PLAYER_ROLES = ['Defensive Coverage' 'Other Route Runner' 'Passer' 'Targeted Receiver']230 231PLAYER_SIDES = ['Defense', 'Offense']232 233print(f'player positions are {POSITION_MAPPING}')234print(f'player roles are {PLAYER_ROLES}')235print(f'player roles are {PLAYER_SIDES}')236 237# plot_distribution_of_features(input_df[:1_000_00], output_df)238 239predict_physics_baseline(input_df, output_df)