{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# <h1 style=\"font-family: Trebuchet MS; padding: 20px; font-size: 25px; color: #FF0000; text-align: center; line-height: 0.75;background-color: #0047AB\"><b>Big Data Derby 2022</b><br></h1>","metadata":{}},{"cell_type":"markdown","source":"\n\n### Aim :\n\n- To gain insights about racetracks and different races!\n- To analyze horse performances as well as identify the horse as marathoner or sprinter!\n\n\n### Dataset Attributes :\n\n- This competition has provided 4 csv files with some common features :\n    - **nyra_2019_complete.csv - combined table of three above files**  \n    **3 common features that are found in all the csv files :**\n        - **track_id** : 3 character id for the track the race took place at. \n            - **AQU : Aqueduct**\n            - **BEL : Belmont**\n            - **SAR : Saratoga**\n        - **race_date** : date the race took place. YYYY-MM-DD.\n        - **race_number** : Number of the race. Passed as 3 characters but can be cast or converted to int for this data set.\n    \n    - **nyra_start_table.csv - horse/jockey race data** \n        - **program_number** : Program number of the horse in the race passed as 3 characters. Should remain 3 characters as it isn't limited to just numbers. Is essentially the unique identifier of the horse in the race.\n        - **weight_carried** : An integer of the weight carried by the horse in the race.\n        - **jockey** : Name of the jockey on the horse in the race. 50 character max.\n        - **odds** : Odds to win the race passed as an integer. Divide by 100 to derive the odds to 1. \n            - **Example - 1280 would be 12.8-1**\n        - **position_at_finish** : An integer of the horse's finishing position\n            \n    - **nyra_race_table.csv - racetrack race data** \n        - **distance_id** : Distance of the race in furlongs passed as an integer. \n            - **Example - 600 would be 6 furlongs**\n        - **course_type** : The course the race was run over passed as one character. \n            - **M : Hurdle**\n            - **D : Dirt**\n            - **O - Outer turf** \n            - **I - Inner turf** \n            - **T - turf**\n        - **track_condition** : The condition of the course the race was run on passed as three characters. \n            - **YL : Yielding**\n            - **FM : Firm** \n            - **SY : Sloppy** \n            - **GD : Good** \n            - **FT : Fast** \n            - **MY : Muddy** \n            - **SF : Soft**\n        - **run_up_distance** : Distance in feet of the gate to the start of the race passed as an integer.\n        - **race_type** : The classification of the race passed as as five characters. \n            - **STK : Stakes** \n            - **WCL : Waiver Claiming** \n            - **WMC : Waiver Maiden Claiming** \n            - **SST : Starter Stakes** \n            - **SHP : Starter Handicap** \n            - **CLM : Claiming** \n            - **STR : Starter Allowance** \n            - **AOC : Allowance Optionl Claimer** \n            - **SOC : Starter Optional Claimer** \n            - **MCL : Maiden Claiming** \n            - **ALW : Allowance** \n            - **MSW : Maiden Special Weight**\n        - **purse** : Purse in US dollars of the race passed as an money with two decimal places.\n        - **post_time** : Time of day the race began passed as 5 character. \n            - **Example - 01220 would be 12:20**    \n\n    - **nyra_tracking_table.csv - tracking data** \n        - **program_number** : Program number of the horse in the race passed as 3 characters. Should remain 3 characters as it isn't limited to just numbers. Is essentially the unique identifier of the horse in the race.\n        - **trakus_index** : The common collection of point of the lat / long of the horse in the race passed as an integer. From what we can tell, it's collected every 0.25 seconds.\n        - **latitude** : The latitude of the horse in the race passed as a float.\n        - **longitude** : The longitude of the horse in the race passed as a float.","metadata":{}},{"cell_type":"markdown","source":"### What you will learn :\n- Data Preprocessing\n- Data Visualization\n\n### Lets get started!","metadata":{}},{"cell_type":"markdown","source":"# <center><div style=\"font-family: Trebuchet MS; background-color: #0047AB; color: #000000; padding: 12px; line-height: 1;\">Dataset Preprocessing</div></center>","metadata":{}},{"cell_type":"markdown","source":"### Import the Necessary Libraries :","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport os\nimport matplotlib.pyplot as plt\n%matplotlib inline\nimport seaborn as sns\npd.options.display.float_format = '{:.2f}'.format\nfrom tqdm import tqdm\nimport re\nimport pickle\nimport warnings\nwarnings.filterwarnings('ignore')\nfrom sklearn.preprocessing import LabelEncoder","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:02:58.346233Z","iopub.execute_input":"2023-07-12T06:02:58.347060Z","iopub.status.idle":"2023-07-12T06:02:58.491603Z","shell.execute_reply.started":"2023-07-12T06:02:58.347009Z","shell.execute_reply":"2023-07-12T06:02:58.490558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Accessing CSV Files :","metadata":{}},{"cell_type":"code","source":"complete_table = pd.read_csv('/kaggle/input/big-data-derby-2022/nyra_2019_complete.csv') # Combined table of three above files\n\naadit = pd.DataFrame(columns = range(len(list(complete_table.columns))))\naadit.loc[0] = list(complete_table.columns)\n\ncomplete_table.columns = ['track_id','race_date','race_number','program_number','trakus_index','latitude','longitude','distance_id',\n               'course_type','track_condition','run_up_distance','race_type','purse','post_time','weight_carried',\n               'jockey','odds','position_at_finish']\naadit.columns = ['track_id','race_date','race_number','program_number','trakus_index','latitude','longitude','distance_id',\n             'course_type','track_condition','run_up_distance','race_type','purse','post_time','weight_carried',\n             'jockey','odds','position_at_finish']\n\ncomplete_table = pd.concat([aadit,complete_table])\n\nstart_table = pd.read_csv('/kaggle/input/big-data-derby-2022/nyra_start_table.csv') # Horse / jockey race data\nstart_table.columns = ['track_id','race_date','race_number','program_number','weight_carried','jockey','odds','position_at_finish']\n\n\nrace_table = pd.read_csv('/kaggle/input/big-data-derby-2022/nyra_race_table.csv') # Racetrack race data\n\ntracking_table = pd.read_csv('/kaggle/input/big-data-derby-2022/nyra_tracking_table.csv') # Tracking data","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:02:58.493233Z","iopub.execute_input":"2023-07-12T06:02:58.493776Z","iopub.status.idle":"2023-07-12T06:03:18.431234Z","shell.execute_reply.started":"2023-07-12T06:02:58.493741Z","shell.execute_reply":"2023-07-12T06:03:18.429852Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"complete_table.info()","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:03:18.432787Z","iopub.execute_input":"2023-07-12T06:03:18.433153Z","iopub.status.idle":"2023-07-12T06:03:18.445892Z","shell.execute_reply.started":"2023-07-12T06:03:18.433122Z","shell.execute_reply":"2023-07-12T06:03:18.444763Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Size of this combined file as well as of the other files can be an issue! Hence we reduce the file size by converting the datatypes of the features from object to their respective datatypes! ","metadata":{}},{"cell_type":"markdown","source":"# Dataset Size Reduction :","metadata":{}},{"cell_type":"markdown","source":"# Complete CSV File :","metadata":{}},{"cell_type":"markdown","source":"- For **numerical features**, we check the **number of unique values, the highest and the lowest value present in the feature!**\n- From this information, we decide to convert the datatypes of the features to **int8**, **int16** and **float16**!\n- Features stored stored in **object** datatype occupy the highest memory space!\n- We also convert the **race_date** feature into **datetime** datatype! ","metadata":{}},{"cell_type":"code","source":"# Numerical Column Transformations :\n\ncomplete_table['race_number'] = complete_table['race_number'].astype('int8') # 1 - race_number\n\nr1 = re.compile('\\d+'); is_string = lambda x : type(x) == str  \nl1 = [i.split()[0] if type(i) == str else i for i in tqdm(list(complete_table['program_number']))] ; l2 = []\nfor i in tqdm(l1):\n    if is_string(i) == True:\n        try:\n            if int(r1.findall(i)[0]) == int(i):\n                l2.append(int(r1.findall(i)[0]))\n        except ValueError:\n            l2.append(i)\n    else :\n        l2.append(i)\ncomplete_table['program_number'] = l2 # 2 - program_nuber\n\ncomplete_table['trakus_index'] = complete_table['trakus_index'].astype('int16') # 3 - trakus_index\ncomplete_table['latitude'] = complete_table['latitude'].astype('float16') # 4 - latitude\ncomplete_table['longitude'] = complete_table['longitude'].astype('float16') # 5 - longitude \ncomplete_table['distance_id'] = complete_table['distance_id'].astype('int16') # 6 - distance_id\ncomplete_table['run_up_distance'] = complete_table['run_up_distance'].astype('int16') # 7 - run_up_distance\ncomplete_table['purse'] = complete_table['purse'].astype(float); complete_table['purse'] = complete_table['purse'].astype('int32') # 8 - purse\ncomplete_table['weight_carried'] = complete_table['weight_carried'].astype('int8') # 9 - weight_carried\ncomplete_table['odds'] = complete_table['odds'].astype('int16') # 10 - odds\ncomplete_table['position_at_finish'] = complete_table['position_at_finish'].astype('int8') # 11 - position_at_finish \n\n# DateTime Features\ncomplete_table['post_time'] = complete_table['post_time'].astype(str) # 12 - post_time\nl1 = list(complete_table['post_time']);\nl2 = list(complete_table['race_date']) # year - month - day\n\nl = []\nfor i,j in tqdm(zip(l1,l2)):\n    if len(i) == 3:\n        l.append(i[:1] + ':' + i[1:] + ' ' + j)\n    elif len(i) == 4:\n        l.append(i[:2] + ':' + i[2:] + ' ' + j)\n    elif len(i) == 5:\n        l.append(i[1:3] + ':' + i[3:] + ' ' + j) \nl = pd.to_datetime(pd.Series(l),format = '%H:%M %Y-%m-%d')\ncomplete_table['post_time'] = l\n\ndate_dict = dict(zip(pd.date_range(\"2019-01-01\", \"2019-12-31\").strftime(\"%Y-%m-%d\"),\n                     pd.date_range(\"2019-01-01\", \"2019-12-31\")))\n\ncomplete_table['race_date'] = complete_table.race_date.map(date_dict) # 13 - race_date","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:03:18.448786Z","iopub.execute_input":"2023-07-12T06:03:18.449148Z","iopub.status.idle":"2023-07-12T06:03:43.886412Z","shell.execute_reply.started":"2023-07-12T06:03:18.449116Z","shell.execute_reply":"2023-07-12T06:03:43.885202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- For **text data features**, we check the **number of unique values** and **Label Encode** these values!\n- In this way, we convert the text data into numerical data!","metadata":{}},{"cell_type":"code","source":"le = LabelEncoder()\ntext_data_features = ['track_id', 'course_type', 'track_condition', 'race_type', 'jockey']\nl3 = []; l4 = [];\nprint('Label Encoder Transformation')\nfor i in tqdm(text_data_features):\n    complete_table[i] = le.fit_transform(complete_table[i])\n    l3.append(list(complete_table[i].unique())); l4.append(list(le.inverse_transform(complete_table[i].unique())))\n    print(i,' : ',complete_table[i].unique(),' = ',le.inverse_transform(complete_table[i].unique()))","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:03:43.888096Z","iopub.execute_input":"2023-07-12T06:03:43.888469Z","iopub.status.idle":"2023-07-12T06:03:50.866131Z","shell.execute_reply.started":"2023-07-12T06:03:43.888439Z","shell.execute_reply":"2023-07-12T06:03:50.865206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- We store the label encoded transformations inside a dictionary that gives us the information about the encoded value and it's original value! ","metadata":{}},{"cell_type":"code","source":"tf1 = {}\nfor i in range(len(text_data_features)):\n    tf1[text_data_features[i]] = {}\n    for j,k in zip(l3[i],l4[i]):\n        tf1[text_data_features[i]][j] = k","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:03:50.868129Z","iopub.execute_input":"2023-07-12T06:03:50.868605Z","iopub.status.idle":"2023-07-12T06:03:50.875818Z","shell.execute_reply.started":"2023-07-12T06:03:50.868558Z","shell.execute_reply":"2023-07-12T06:03:50.874871Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"complete_table.info()","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:03:50.876821Z","iopub.execute_input":"2023-07-12T06:03:50.877696Z","iopub.status.idle":"2023-07-12T06:03:50.896083Z","shell.execute_reply.started":"2023-07-12T06:03:50.877661Z","shell.execute_reply":"2023-07-12T06:03:50.895168Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"complete_table.to_pickle('complete_table' + '.pkl',compression = 'gzip' )\nwith open('tf1.pkl','wb') as f:\n    pickle.dump(tf1,f)","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:03:50.897421Z","iopub.execute_input":"2023-07-12T06:03:50.897800Z","iopub.status.idle":"2023-07-12T06:04:52.448530Z","shell.execute_reply.started":"2023-07-12T06:03:50.897769Z","shell.execute_reply":"2023-07-12T06:04:52.447212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- We can clearly see the size of the files have been reduced from **757.9 MB** to **453.7 MB**!\n- Now, we know that these transformations are only retained for the active session and cannot be used afterwards!\n- Hence, we store these transformations along with this modified dataset into pickle files!\n- These pickle files will hold these modifications and we do not need to execute those transformations everytime!","metadata":{}},{"cell_type":"markdown","source":"**We now repeat this same process for the race_table and the start_table files! We will not use it for tracking_table file as it can be easily separated from the combined_file!**","metadata":{}},{"cell_type":"markdown","source":"#### Race Table","metadata":{}},{"cell_type":"code","source":"# Numerical Column Transformations :\n\nrace_table['race_number'] = race_table['race_number'].astype('int8') # 1 - race_number\nrace_table['distance_id'] = race_table['distance_id'].astype('int16') # 2 - distance_id\nrace_table['run_up_distance'] = race_table['run_up_distance'].astype('int16') # 3 - run_up_distance\nrace_table['purse'] = race_table['purse'].astype(float); race_table['purse'] = race_table['purse'].astype('int32') # 8 - purse\n\n# DateTime Features\nrace_table['post_time'] = race_table['post_time'].astype(str) # 12 - post_time\nl1 = list(race_table['post_time']);\nl2 = list(race_table['race_date']) # year - month - day\n\nl = []\nfor i,j in tqdm(zip(l1,l2)):\n    if len(i) == 3:\n        l.append(i[:1] + ':' + i[1:] + ' ' + j)\n    elif len(i) == 4:\n        l.append(i[:2] + ':' + i[2:] + ' ' + j)\n    elif len(i) == 5:\n        l.append(i[1:3] + ':' + i[3:] + ' ' + j) \nl = pd.to_datetime(pd.Series(l),format = '%H:%M %Y-%m-%d')\nrace_table['post_time'] = l\n\ndate_dict = dict(zip(pd.date_range(\"2019-01-01\", \"2019-12-31\").strftime(\"%Y-%m-%d\"),\n                     pd.date_range(\"2019-01-01\", \"2019-12-31\")))\n\nrace_table['race_date'] = race_table.race_date.map(date_dict) # 13 - race_date","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:52.450366Z","iopub.execute_input":"2023-07-12T06:04:52.450744Z","iopub.status.idle":"2023-07-12T06:04:52.651767Z","shell.execute_reply.started":"2023-07-12T06:04:52.450712Z","shell.execute_reply":"2023-07-12T06:04:52.650411Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"le = LabelEncoder()\ntext_data_features = ['track_id', 'course_type', 'track_condition', 'race_type']\nl3 = []; l4 = [];\nprint('Label Encoder Transformation')\nfor i in tqdm(text_data_features):\n    race_table[i] = le.fit_transform(race_table[i])\n    l3.append(list(race_table[i].unique())); l4.append(list(le.inverse_transform(race_table[i].unique())))\n    print(i,' : ',race_table[i].unique(),' = ',le.inverse_transform(race_table[i].unique()))","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:52.657167Z","iopub.execute_input":"2023-07-12T06:04:52.657945Z","iopub.status.idle":"2023-07-12T06:04:52.680468Z","shell.execute_reply.started":"2023-07-12T06:04:52.657903Z","shell.execute_reply":"2023-07-12T06:04:52.679396Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf2 = {}\nfor i in range(len(text_data_features)):\n    tf2[text_data_features[i]] = {}\n    for j,k in zip(l3[i],l4[i]):\n        tf2[text_data_features[i]][j] = k","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:52.682312Z","iopub.execute_input":"2023-07-12T06:04:52.682684Z","iopub.status.idle":"2023-07-12T06:04:52.687861Z","shell.execute_reply.started":"2023-07-12T06:04:52.682651Z","shell.execute_reply":"2023-07-12T06:04:52.687016Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"race_table.to_pickle('race_table' + '.pkl',compression = 'gzip' )\nwith open('tf2.pkl','wb') as f:\n    pickle.dump(tf2,f)","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:52.689082Z","iopub.execute_input":"2023-07-12T06:04:52.689460Z","iopub.status.idle":"2023-07-12T06:04:52.723315Z","shell.execute_reply.started":"2023-07-12T06:04:52.689428Z","shell.execute_reply":"2023-07-12T06:04:52.722411Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Start Table :","metadata":{}},{"cell_type":"code","source":"# Numerical Column Transformations :\n\nstart_table['race_number'] = start_table['race_number'].astype('int8') # 1 - race_number\n\nr1 = re.compile('\\d+'); is_string = lambda x : type(x) == str  \nl1 = [i.split()[0] if type(i) == str else i for i in tqdm(list(start_table['program_number']))] ; l2 = []\nfor i in tqdm(l1):\n    if is_string(i) == True:\n        try:\n            if int(r1.findall(i)[0]) == int(i):\n                l2.append(int(r1.findall(i)[0]))\n        except ValueError:\n            l2.append(i)\n    else :\n        l2.append(i)\nstart_table['program_number'] = l2 # 2 - program_nuber\nstart_table['weight_carried'] = start_table['weight_carried'].astype('int8') # 3 - weight_carried\nstart_table['odds'] = start_table['odds'].astype('int16') # 4 - odds\nstart_table['position_at_finish'] = start_table['position_at_finish'].astype('int8') # 5 - position_at_finish \n\n# DateTime Features\ndate_dict = dict(zip(pd.date_range(\"2019-01-01\", \"2019-12-31\").strftime(\"%Y-%m-%d\"),\n                     pd.date_range(\"2019-01-01\", \"2019-12-31\")))\n\nstart_table['race_date'] = start_table.race_date.map(date_dict) # 6 - race_date","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:52.724577Z","iopub.execute_input":"2023-07-12T06:04:52.725021Z","iopub.status.idle":"2023-07-12T06:04:52.805630Z","shell.execute_reply.started":"2023-07-12T06:04:52.724978Z","shell.execute_reply":"2023-07-12T06:04:52.804465Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"le = LabelEncoder()\ntext_data_features = ['track_id', 'jockey']\nl3 = []; l4 = [];\nprint('Label Encoder Transformation')\nfor i in tqdm(text_data_features):\n    start_table[i] = le.fit_transform(start_table[i])\n    l3.append(list(start_table[i].unique())); l4.append(list(le.inverse_transform(start_table[i].unique())))\n    print(i,' : ',start_table[i].unique(),' = ',le.inverse_transform(start_table[i].unique()))","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:52.806934Z","iopub.execute_input":"2023-07-12T06:04:52.807279Z","iopub.status.idle":"2023-07-12T06:04:52.834443Z","shell.execute_reply.started":"2023-07-12T06:04:52.807249Z","shell.execute_reply":"2023-07-12T06:04:52.833159Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf3 = {}\nfor i in range(len(text_data_features)):\n    tf3[text_data_features[i]] = {}\n    for j,k in zip(l3[i],l4[i]):\n        tf3[text_data_features[i]][j] = k","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:52.835945Z","iopub.execute_input":"2023-07-12T06:04:52.836276Z","iopub.status.idle":"2023-07-12T06:04:52.842115Z","shell.execute_reply.started":"2023-07-12T06:04:52.836245Z","shell.execute_reply":"2023-07-12T06:04:52.840983Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"start_table.to_pickle('start_table' + '.pkl',compression = 'gzip' )\nwith open('tf3.pkl','wb') as f:\n    pickle.dump(tf3,f)","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:52.843582Z","iopub.execute_input":"2023-07-12T06:04:52.844346Z","iopub.status.idle":"2023-07-12T06:04:52.988950Z","shell.execute_reply.started":"2023-07-12T06:04:52.844300Z","shell.execute_reply":"2023-07-12T06:04:52.987520Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- We will load the pickle files and check these files!","metadata":{}},{"cell_type":"code","source":"df1 = pd.read_pickle('./complete_table.pkl',compression = 'gzip')\ndf2 = pd.read_pickle('./race_table.pkl',compression = 'gzip')\ndf3 = pd.read_pickle('./start_table.pkl',compression = 'gzip')\n\nwith open('./tf1.pkl', 'rb') as file:  \n    tf1 = pickle.load(file)\nwith open('./tf2.pkl', 'rb') as file:  \n    tf2 = pickle.load(file)    \nwith open('./tf3.pkl', 'rb') as file:  \n    tf3 = pickle.load(file)\n    \ncolors = ['#0047AB','000000']","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:52.990476Z","iopub.execute_input":"2023-07-12T06:04:52.991324Z","iopub.status.idle":"2023-07-12T06:04:54.910718Z","shell.execute_reply.started":"2023-07-12T06:04:52.991289Z","shell.execute_reply":"2023-07-12T06:04:54.909456Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**We are now all set to use the datasets!**","metadata":{}},{"cell_type":"markdown","source":"# <center><div style=\"font-family: Trebuchet MS; background-color: #0047AB; color: #000000; padding: 12px; line-height: 1;\">Analysis of RaceTracks</div></center>","metadata":{}},{"cell_type":"markdown","source":"- **We aim to gain insights about the racetrack and it's different characteristics!**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,5))\nax = sns.countplot('race_number',data = df2,palette = colors, edgecolor = 'black')\nfor rect in ax.patches:\n    ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height() + 2, rect.get_height(), horizontalalignment='center', fontsize = 11)\ntitle = 'Total Number of Races : ' + str(sum(df2['race_number'].value_counts()))\nplt.title(title);","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:54.912594Z","iopub.execute_input":"2023-07-12T06:04:54.913051Z","iopub.status.idle":"2023-07-12T06:04:55.249003Z","shell.execute_reply.started":"2023-07-12T06:04:54.912994Z","shell.execute_reply":"2023-07-12T06:04:55.248171Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Competition organizers have shared the data of **2000** races.\n- These races have been labeled with integer values from **1 - 13**.\n- The number of races drops from the cliff value of **212** of **race_number 8** to **3** of **race_number 13**.\n- We need to dig more to get information about the differences in these **race_number** values but first we need to check where these races are conducted!","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,5))\nax = sns.countplot('track_id',data = df2,palette = colors, edgecolor = 'black')\nfor rect in ax.patches:\n    ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height() + 2, rect.get_height(), horizontalalignment='center', fontsize = 11)\nax.set_xticklabels(tf2['track_id'].values())\ntitle = 'Number of Races conducted on Different Racetracks'\nplt.title(title);","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:55.250150Z","iopub.execute_input":"2023-07-12T06:04:55.251361Z","iopub.status.idle":"2023-07-12T06:04:55.474606Z","shell.execute_reply.started":"2023-07-12T06:04:55.251294Z","shell.execute_reply":"2023-07-12T06:04:55.473342Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- The data collected is from the 3 racetracks used for horse racing :\n    - **AQU(Aqueduct)**\n    - **BEL(Belmont)**\n    - **SAR(Saratoga)**\n- We can see that **AQU(Aqueduct)** conducted the highest number of races, **825**, followed by **BEL(Belmont)** with **772** races. **SAR(Saratoga)** comes at the last position with **403** races.\n- We will now check during which months the above tracks were utilised for horse racing!","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,5))\nsns.lineplot(x = 'race_date', y = 'race_number',data = df2, hue = 'track_id',ci = None)\nplt.legend(tf2['track_id'].values())\nplt.title('Races Throughout the Year on Different Tracks');","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:55.476625Z","iopub.execute_input":"2023-07-12T06:04:55.477782Z","iopub.status.idle":"2023-07-12T06:04:55.822101Z","shell.execute_reply.started":"2023-07-12T06:04:55.477730Z","shell.execute_reply":"2023-07-12T06:04:55.820947Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- We can say that the season of horse racing probably begins at the **end of October - start of Novemeber** because of the huge spike present that touches the **race_number 1** on the y-axis.\n- **AQU(Aqueduct)** hosts races from months of **October / November - April**. It is then followed by a **2 month** period of  races conducted at the **BEL(Belmont)** race that gets interrupted by the races conducted at **SAR(Saratoga)** racetrack.\n- Races at **BEL(Belmont)** resume again in the month of **September till the end of October - start of Novemeber**.\n- We can speculate that the races conducted on the **AQU(Aqueduct)** track are some of kind of qualifying races that heads into the knockout stages which is carried out on the remaining 2 racetracks.","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,5))\nax = sns.boxplot(x = 'track_id',y = 'distance_id',data = df2, palette = colors);\nlines = ax.get_lines()\ncategories = ax.get_xticks()\n\nfor cat in categories:\n    y = round(lines[4+cat*6].get_ydata()[0],1) \n    ax.text(cat,y,f'{y}',ha='center',va='center',fontweight='semibold',size=12,color='white',bbox=dict(facecolor='#828282', edgecolor='#828282'))    \nax.set_xticklabels(tf2['track_id'].values())\nplt.title('Distance of each Tracks');","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:55.823603Z","iopub.execute_input":"2023-07-12T06:04:55.823931Z","iopub.status.idle":"2023-07-12T06:04:56.093634Z","shell.execute_reply.started":"2023-07-12T06:04:55.823903Z","shell.execute_reply":"2023-07-12T06:04:56.092599Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- All the 3 racetracks have a median distance of **700 - 7 furlongs**. \n- Outliers with values above **1400 - 14 furlongs** can also be found at **BEL(Belmont)** & **SAR(Saratoga)** racetracks.","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,5))\nax = sns.countplot('track_condition',hue = 'track_id',data = df2,palette = colors, edgecolor = 'black')\nax.set_xticklabels([tf2['track_condition'][i] for i in sorted(df2['track_condition'].unique())])\nplt.legend(tf2['track_id'].values())\ntitle = 'Track Conditions for the Races'\nplt.title(title);","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:56.095264Z","iopub.execute_input":"2023-07-12T06:04:56.095634Z","iopub.status.idle":"2023-07-12T06:04:56.396134Z","shell.execute_reply.started":"2023-07-12T06:04:56.095603Z","shell.execute_reply":"2023-07-12T06:04:56.394843Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- All the 3 racetracks have been conditioned to be **FT - Fast** for the most of the races.\n- **BEL(Belmont)** racetrack has been made **FM - Firm** for a significant amount of races.\n- **SF - Soft** is the least prepared track for the races. ","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,5))\nax = sns.boxplot(x = 'track_id',y = 'run_up_distance',data = df2, palette = colors);\nlines = ax.get_lines()\ncategories = ax.get_xticks()\n\nfor cat in categories:\n    y = round(lines[4+cat*6].get_ydata()[0],1) \n    ax.text(cat,y,f'{y}',ha='center',va='center',fontweight='semibold',size=12,color='white',bbox=dict(facecolor='#828282', edgecolor='#828282'))    \nax.set_xticklabels(tf2['track_id'].values())\nplt.title('Distance from Gate to the Start of the Race of the Race Tracks');","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:56.397773Z","iopub.execute_input":"2023-07-12T06:04:56.398187Z","iopub.status.idle":"2023-07-12T06:04:56.646093Z","shell.execute_reply.started":"2023-07-12T06:04:56.398154Z","shell.execute_reply":"2023-07-12T06:04:56.643780Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Median **run_up_distance** of **AQU(Aqueduct)** & **SAR(Saratoga)** are same i.e **52 ft**!\n- **BEL(Belmont)'s** **run_up_distance** is higher than the other 2 racetracks with **65ft**!\n- The highest **run_up_distance** value including the outliers is found at **SAR(Saratoga)** racetrack with more than **250 ft**.","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,5))\nax = sns.countplot('race_type',hue = 'track_id',data = df2,palette = colors, edgecolor = 'black')\nax.set_xticklabels([tf2['race_type'][i] for i in sorted(df2['race_type'].unique())])\nplt.legend(tf2['track_id'].values())\ntitle = 'Different Types of Races Conducted at Different Race Tracks'\nplt.title(title);","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:56.647558Z","iopub.execute_input":"2023-07-12T06:04:56.647874Z","iopub.status.idle":"2023-07-12T06:04:57.022031Z","shell.execute_reply.started":"2023-07-12T06:04:56.647847Z","shell.execute_reply":"2023-07-12T06:04:57.020659Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- All the 3 racetracks conducted a host of the following types of races :\n    - **ALW - Allowance**\n    - **AOC - Allowance Optional Claimer**\n    - **CLM - Claiming**\n    - **MCL - Maiden Claiming**\n    - **MSW - Maiden Special Weight**\n    - **STK - Stakes**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,5))\nax = sns.boxplot(x = 'track_id',y = 'purse',data = df2, palette = colors);\nlines = ax.get_lines()\ncategories = ax.get_xticks()\n\nfor cat in categories:\n    y = round(lines[4+cat*6].get_ydata()[0],1) \n    ax.text(cat,y,f'{y}',ha='center',va='center',fontweight='semibold',size=12,color='white',bbox=dict(facecolor='#828282', edgecolor='#828282'))    \nax.set_xticklabels(tf2['track_id'].values())\nplt.title('Purse values at Different Racetracks');","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:57.023758Z","iopub.execute_input":"2023-07-12T06:04:57.024133Z","iopub.status.idle":"2023-07-12T06:04:57.285325Z","shell.execute_reply.started":"2023-07-12T06:04:57.024093Z","shell.execute_reply":"2023-07-12T06:04:57.284426Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- **BEL(Belmont)** racetrack's highest outlier **purse** value is more than **1400000**.\n- Despite conducting low number of races at **SAR(Saratoga)** racetrack, it's median **purse** value of **80000** is more than the other 2 racetracks.","metadata":{}},{"cell_type":"markdown","source":"# <center><div style=\"font-family: Trebuchet MS; background-color: #0047AB; color: #000000; padding: 12px; line-height: 1;\">Analysis of Different Races & Horse Performances</div></center>","metadata":{}},{"cell_type":"markdown","source":"- **We now aim to find insights about the varied races, performances of horses in those races!**","metadata":{}},{"cell_type":"code","source":"pt = []\nfor i in df2['post_time']:\n    i = str(i.time())\n    pt.append((i[0:2],i[3:5]))\nhrs = [ i[0] + ':30 - ' +str(int(i[0]) + 1) if int(i[1]) > 30 else i[0] + ' - ' + i[0] + ':30' for i in pt]\ndf2['Hours'] = hrs","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:57.286756Z","iopub.execute_input":"2023-07-12T06:04:57.287936Z","iopub.status.idle":"2023-07-12T06:04:57.303635Z","shell.execute_reply.started":"2023-07-12T06:04:57.287883Z","shell.execute_reply":"2023-07-12T06:04:57.302646Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- First step, we create a new column named **Hours** and store it's values in string datatype! Let's visualize and check if we can find anything interesting about the **race_number** and time!  ","metadata":{}},{"cell_type":"code","source":"fig = plt.subplots(nrows = 4,ncols = 3,figsize = (25,20))\nfor i in range(1,13):\n    plt.subplot(4,3,i)\n    ax = sns.countplot('Hours', data = df2[df2['race_number'] == i], palette = colors,edgecolor = 'black');\n    for rect in ax.patches:\n        ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height() + 1, rect.get_height(), horizontalalignment='center', fontsize = 11)\n    plt.title('race_number ' + str(i) + ' : Timings');\n\nfig = plt.subplots(nrows = 1,ncols = 1,figsize = (3,3))\nplt.subplot(1,1,1)\nax = sns.countplot('Hours', data = df2[df2['race_number'] == 13], palette = colors,edgecolor = 'black');\nfor rect in ax.patches:\n    ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height(), rect.get_height(), horizontalalignment='center', fontsize = 11)\nplt.title('race_number ' + str(13) + ' : Timings');","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:04:57.304811Z","iopub.execute_input":"2023-07-12T06:04:57.305522Z","iopub.status.idle":"2023-07-12T06:05:00.077690Z","shell.execute_reply.started":"2023-07-12T06:04:57.305480Z","shell.execute_reply":"2023-07-12T06:05:00.076458Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- **race_number 1** has the earliest timing of conducting races between **11 - 11:30** & **race_number 13** conducted the most late race between **8 - 8:30**.\n- All of the **race_number** have a dominant time period where the most number of races have been conducted.\n- These **race_number** values probably signify the order of the races that are conducted during the day. This can be a strong indicator to identify the **race_number**.\n- We will also try to find it's significance with the **race_type** & **course_type** as well!","metadata":{}},{"cell_type":"code","source":"fig = plt.subplots(nrows = 4,ncols = 3,figsize = (25,20))\nfor i in range(1,13):\n    plt.subplot(4,3,i)\n    ax = sns.countplot('race_type', data = df2[df2['race_number'] == i], palette = colors,edgecolor = 'black');\n    for rect in ax.patches:\n        ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height(), rect.get_height(), horizontalalignment='center', fontsize = 11)\n    ax.set_xticklabels([tf2['race_type'][j] for j in sorted(df2[df2['race_number'] == i]['race_type'].unique())])\n    plt.title('race_number ' + str(i) + ' : race_type');\n\nfig = plt.subplots(nrows = 1,ncols = 1,figsize = (4,3))\nplt.subplot(1,1,1)\nax = sns.countplot('race_type', data = df2[df2['race_number'] == 13], palette = colors,edgecolor = 'black');\nfor rect in ax.patches:\n    ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height(), rect.get_height(), horizontalalignment='center', fontsize = 11)\nax.set_xticklabels([tf2['race_type'][i] for i in sorted(df2[df2['race_number'] == 13]['race_type'].unique())])\nplt.title('race_number ' + str(13) + ' : race_type');","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:05:00.083139Z","iopub.execute_input":"2023-07-12T06:05:00.083560Z","iopub.status.idle":"2023-07-12T06:05:03.047472Z","shell.execute_reply.started":"2023-07-12T06:05:00.083524Z","shell.execute_reply":"2023-07-12T06:05:03.046422Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- From the above visualization, **CLM - Claiming** &  **MSW - Maiden Special Weight** types of races are found in near about all the **race_number**. \n- We can also see the reason behind the drop of the number of races from **race_number 9 - 13**. From these **race_number**, we can also see the number of **STK - Stake** races increase.  \n- **race_types** drops for the **race_number 9 - 13** probably because the **day is about to end**.","metadata":{}},{"cell_type":"code","source":"fig = plt.subplots(nrows = 4,ncols = 3,figsize = (25,20))\nfor i in range(1,13):\n    plt.subplot(4,3,i)\n    ax = sns.countplot('course_type', data = df2[df2['race_number'] == i], palette = colors,edgecolor = 'black');\n    for rect in ax.patches:\n        ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height(), rect.get_height(), horizontalalignment='center', fontsize = 11)\n    ax.set_xticklabels([tf2['course_type'][j] for j in sorted(df2[df2['race_number'] == i]['course_type'].unique())])\n    plt.title('race_number ' + str(i) + ' : course_type');\n\nfig = plt.subplots(nrows = 1,ncols = 1,figsize = (3,3))\nplt.subplot(1,1,1)\nax = sns.countplot('course_type', data = df2[df2['race_number'] == 13], palette = colors,edgecolor = 'black');\nfor rect in ax.patches:\n    ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height(), rect.get_height(), horizontalalignment='center', fontsize = 11)\nax.set_xticklabels([tf2['course_type'][i] for i in sorted(df2[df2['race_number'] == 13]['course_type'].unique())])\nplt.title('race_number ' + str(13) + ' : course_type');","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:05:03.049025Z","iopub.execute_input":"2023-07-12T06:05:03.049892Z","iopub.status.idle":"2023-07-12T06:05:05.099124Z","shell.execute_reply.started":"2023-07-12T06:05:03.049853Z","shell.execute_reply":"2023-07-12T06:05:05.097726Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- This visualization is similar to **race_type**! All the **race_number** races have **D - Dirt** courses and alot of races are conducted on it!\n- Just like **race_type**, **course_type** gets reduced for the **race_number 9 - 13** & narrows down to **2 course_types** only.\n\n**All of these visualizations explain the drop off in number of races from race_number 9 - 13!**\n\n**Thus, managing the energies of the horses for races on different tracks for multiple courses during the varied time slots is key!**\n\n**We will now move our attention towards the perfomances of the horses in these races!**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,5))\nax = sns.countplot('program_number',data = df3,palette = colors, edgecolor = 'black')\nfor rect in ax.patches:\n    ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height() + 2, rect.get_height(), horizontalalignment='center', fontsize = 11)\nplt.title('Number of Races played by Horses');","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:05:05.101863Z","iopub.execute_input":"2023-07-12T06:05:05.102405Z","iopub.status.idle":"2023-07-12T06:05:05.541072Z","shell.execute_reply.started":"2023-07-12T06:05:05.102367Z","shell.execute_reply":"2023-07-12T06:05:05.539662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- A clear cut difference in the endurance of the horses can be observed from the number of races played by each horse!","metadata":{}},{"cell_type":"code","source":"fig = plt.subplots(nrows = 4,ncols = 3,figsize = (25,20))\nfor i in range(1,13):\n    plt.subplot(4,3,i)\n    ax = sns.countplot('program_number', data = df3[df3['race_number'] == i], palette = colors,edgecolor = 'black');\n    for rect in ax.patches:\n        ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height(), rect.get_height(), horizontalalignment='center', fontsize = 11)\n    plt.title('race_number '+ str(i));\n\nfig = plt.subplots(nrows = 1,ncols = 1,figsize = (4,3))\nplt.subplot(1,1,1)\nax = sns.countplot('program_number', data = df3[df3['race_number'] == 13], palette = colors,edgecolor = 'black');\nfor rect in ax.patches:\n    ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height(), rect.get_height(), horizontalalignment='center', fontsize = 11)\nplt.title('race_number ' + str(13));","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:05:05.542957Z","iopub.execute_input":"2023-07-12T06:05:05.543391Z","iopub.status.idle":"2023-07-12T06:05:09.986156Z","shell.execute_reply.started":"2023-07-12T06:05:05.543345Z","shell.execute_reply":"2023-07-12T06:05:09.984804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Horses with **program_number : 1, 2, 3, 4, 5, 6** are playing heavily in all the **race_number**. \n- From the above visualizations, we can say that these horses are very well maintained and conditioned for adapting to different types of turfs. \n- They are not fazed by the **track_conditions** or **course_type** presented to them from these **race_number**. They display their solid endurance by playing races throughout the day!","metadata":{}},{"cell_type":"code","source":"fig = plt.subplots(nrows = 3,ncols = 1,figsize = (15,15))\nfor i in range(3):\n    plt.subplot(3,1,i+1)\n    ax = sns.countplot('program_number', data = df3[(df3['position_at_finish'] <= 3) & (df3['track_id'] == i)], palette = colors,edgecolor = 'black');\n    for rect in ax.patches:\n        ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height(), rect.get_height(), horizontalalignment='center', fontsize = 11)\n    plt.title('Top 3 Finishes at '+ tf3['track_id'][i]);","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:05:09.988159Z","iopub.execute_input":"2023-07-12T06:05:09.988531Z","iopub.status.idle":"2023-07-12T06:05:11.074876Z","shell.execute_reply.started":"2023-07-12T06:05:09.988500Z","shell.execute_reply":"2023-07-12T06:05:11.073661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- Horses with **program_number : 1, 2, 3, 4, 5, 6** dominate the top 3 finishes on all the 3 tracks.\n- Clearly, these 6 horses can be classed as elite.\n- We will check the odds against these horses!","metadata":{}},{"cell_type":"code","source":"fig = plt.subplots(nrows = 2, ncols = 3, figsize = (15,10))\nfor i in range(1,7):\n    plt.subplot(2,3,i)\n    ax = sns.barplot('track_id','odds',data = df3[(df3['program_number'] == i)],palette = colors, edgecolor = 'black',ci = None)               \n    ax.set_xticklabels(tf3['track_id'].values())\n    plt.title('Odds of Winning : Horse ' + str(i));","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:05:11.076320Z","iopub.execute_input":"2023-07-12T06:05:11.076718Z","iopub.status.idle":"2023-07-12T06:05:11.861204Z","shell.execute_reply.started":"2023-07-12T06:05:11.076685Z","shell.execute_reply":"2023-07-12T06:05:11.860083Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- **Horse 6** has the highest odds of winning the races at **AQU(Aqueduct)** as well as **BEL(Belmont)** racetrack. People back this horse to win alot!\n- All of the horses have the highest odds of winning races at **AQU(Aqueduct)** racetrack.\n- We now check their success rate in races where we define the success rate as the finishing in the top 3!","metadata":{}},{"cell_type":"code","source":"sr1 = [round(len(df3[(df3['program_number'] == 1) & (df3['position_at_finish'] <= 3) & (df3['race_number'] == i)]) / len(df3[(df3['program_number'] == 1) & (df3['race_number'] == i)]) * 100) for i in range(1,14)]\nsr2 = [round(len(df3[(df3['program_number'] == 2) & (df3['position_at_finish'] <= 3) & (df3['race_number'] == i)]) / len(df3[(df3['program_number'] == 2) & (df3['race_number'] == i)]) * 100) for i in range(1,14)]\nsr3 = [round(len(df3[(df3['program_number'] == 3) & (df3['position_at_finish'] <= 3) & (df3['race_number'] == i)]) / len(df3[(df3['program_number'] == 3) & (df3['race_number'] == i)]) * 100) for i in range(1,14)]\nsr4 = [round(len(df3[(df3['program_number'] == 4) & (df3['position_at_finish'] <= 3) & (df3['race_number'] == i)]) / len(df3[(df3['program_number'] == 4) & (df3['race_number'] == i)]) * 100) for i in range(1,14)]\nsr5 = [round(len(df3[(df3['program_number'] == 5) & (df3['position_at_finish'] <= 3) & (df3['race_number'] == i)]) / len(df3[(df3['program_number'] == 5) & (df3['race_number'] == i)]) * 100) for i in range(1,14)]\nsr6 = [round(len(df3[(df3['program_number'] == 6) & (df3['position_at_finish'] <= 3) & (df3['race_number'] == i)]) / len(df3[(df3['program_number'] == 6) & (df3['race_number'] == i)]) * 100) for i in range(1,14)]\n\nsr = [sr1, sr2, sr3, sr4, sr5, sr6]\n\nfig = plt.subplots(nrows = 6, ncols = 1, figsize = (15,35))\nfor i in range(len(sr)):\n    plt.subplot(6,1,i+1)\n    ax = sns.barplot(df3['race_number'].unique(),sr[i], palette = colors, edgecolor = 'black')\n    for rect in ax.patches:\n        ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height() + 1, rect.get_height(), horizontalalignment='center', fontsize = 11)\n    plt.xlabel('Race_Number (1 - 13)')\n    plt.title('Top 3 Finish (%) in race_number (1 - 13) : Horse ' + str(i+1))","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:05:11.862737Z","iopub.execute_input":"2023-07-12T06:05:11.863351Z","iopub.status.idle":"2023-07-12T06:05:14.181560Z","shell.execute_reply.started":"2023-07-12T06:05:11.863295Z","shell.execute_reply":"2023-07-12T06:05:14.180688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- From all of these graphs, we can see many trends!\n- **Horse 5** seems to have a stable performance over all the **race_number 1 - 13**. This highlights it's adaptability to the various courses as well as adjusting to the time slots of these races.\n- **Horse 3** and **Horse 1** can be considered to be the 2nd & 3rd pick after **Horse 5**. Their performances are formidable as well!\n- **Horse 2** and **Horse 4** display a declining performance as the day comes to an end!\n- **Horse 6** displays promising signs during the early times of the day but eventually falters in performance.","metadata":{}},{"cell_type":"markdown","source":"# <center><div style=\"font-family: Trebuchet MS; background-color: #0047AB; color: #000000; padding: 12px; line-height: 1;\">Horse Identification : Marathoner or Sprinter</div></center>","metadata":{}},{"cell_type":"markdown","source":"- **We aim to find if the horse is a marathoner or spinner!**\n- Identifying the characteristics of the horse is crucial.","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,5))\nax = sns.countplot(df1['distance_id'], palette = colors,edgecolor = 'black');\nfor rect in ax.patches:\n        ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height() + 0.5, rect.get_height(), horizontalalignment='center', fontsize = 11)\nplt.title('Track Distances');","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:05:14.182750Z","iopub.execute_input":"2023-07-12T06:05:14.183547Z","iopub.status.idle":"2023-07-12T06:05:20.943687Z","shell.execute_reply.started":"2023-07-12T06:05:14.183511Z","shell.execute_reply":"2023-07-12T06:05:20.942368Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- We will consider the races with distances more than **1800** as **marathons**.\n- Races with distances less than **1800** will be considered as **sprints**.\n- From the above graph, we can say that there are more **sprints** than **marathons**.","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,5))\nax = sns.countplot('program_number', data = df1[(df1['distance_id'] > 1800) & (df1['position_at_finish'] <= 3)], palette = colors,edgecolor = 'black');\nfor rect in ax.patches:\n    ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height(), rect.get_height(), horizontalalignment='center', fontsize = 11)\nplt.title('Marathons : Horses with Total Number of Top 3 Finishes');","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:05:20.945249Z","iopub.execute_input":"2023-07-12T06:05:20.945668Z","iopub.status.idle":"2023-07-12T06:05:21.718598Z","shell.execute_reply.started":"2023-07-12T06:05:20.945635Z","shell.execute_reply":"2023-07-12T06:05:21.717273Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- **Horse 3** & **Horse 5** are solid marathoners.\n- **Horse 2** is also a formidable marathoner.\n- Outside of the **Horse 1 - 8**, other horses need to be train more! ","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (15,5))\nax = sns.countplot('program_number', data = df1[(df1['distance_id'] <= 1800) & (df1['position_at_finish'] <= 3)], palette = colors,edgecolor = 'red');\nfor rect in ax.patches:\n    ax.text(rect.get_x() + rect.get_width() / 2, rect.get_height(), rect.get_height(), horizontalalignment='center', fontsize = 11)\nplt.title('Sprints : Horses with Total Number of Top 3 Finishes');","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:09:39.568308Z","iopub.execute_input":"2023-07-12T06:09:39.568928Z","iopub.status.idle":"2023-07-12T06:09:41.628824Z","shell.execute_reply.started":"2023-07-12T06:09:39.568880Z","shell.execute_reply":"2023-07-12T06:09:41.627468Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- **Horse 1 - 6** are solid sprinters. \n- Except **Horse 1X** and **Horse 3X**, all the horses have scored a top 3 finish.\n- Clearly, horses are trained more for **Sprint** races than **Marathon**. \n- We will just check the **purse** value to check if money is the motivation behind jockeys training their horses to be more equipped for sprinters than being marathoners.","metadata":{}},{"cell_type":"code","source":"fig = plt.subplots(nrows = 1, ncols = 2, figsize = (15,5))\ndf = [df1[(df1['distance_id'] <= 1800)], df1[(df1['distance_id'] > 1800)]]\nf1 = ['Purse Values of Sprint Races', 'Purse Values of Marathon Races']\nfor i in range(len(df)):\n    plt.subplot(1,2,i + 1)\n    ax = sns.boxplot(x = 'purse', data = df[i], palette = colors, orient = 'v')\n    plt.title(f1[i])","metadata":{"execution":{"iopub.status.busy":"2023-07-12T06:05:23.733132Z","iopub.execute_input":"2023-07-12T06:05:23.734065Z","iopub.status.idle":"2023-07-12T06:05:26.501665Z","shell.execute_reply.started":"2023-07-12T06:05:23.734025Z","shell.execute_reply":"2023-07-12T06:05:26.500772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- This proves that money is a huge motivation!\n- The highest **purse** value of **Sprint** races is more than **1400000** whereas the highest **purse** value of **Marathon** races is more than **140000**.\n- Overall, **Horse 1 - 6** have pretty much equipped themselves to be competent enough for both formats!","metadata":{}},{"cell_type":"markdown","source":"### References & Resources :\n\n- https://www.science.org/content/article/best-way-win-horse-race-mathematicians-may-have-answer\n- https://practicalpunting.com.au/pp-online/a-z-of-betting/form-analysis/jockeystrainers/the-secret-tactics-19861104\n\n- https://sharkcoder.com/data-visualization/seaborn-boxplot\n-https://www.dalzellcoaching.com/domain-6-skills--tactics.html","metadata":{}},{"cell_type":"markdown","source":"# <center><div style=\"font-family: Trebuchet MS; background-color: #0047AB; color: #FFFF00; padding: 12px; line-height: 1;\">Please upvote if you like the work!</div><div style=\"font-family: Trebuchet MS; background-color: #0047AB; color: #800000; padding: 12px; line-height: 1;\">Any sort of feedback is appreciated!</div><div style=\"font-family: Trebuchet MS; background-color: #0047AB; color: #000000; padding: 12px; line-height: 1;\">Thank you!</div></center>","metadata":{}}]}