{"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":"# Analysis and prediction of the nect movement of a horse","metadata":{}},{"cell_type":"markdown","source":"> ### The objective of this notebook is to do a little data analysis while we prepare and transform the data to do a predictive model to know the next position a horse will have in a race depending on different params. I think the best idea would be to use this transformation of data and modeling to make horse races simulations.","metadata":{}},{"cell_type":"markdown","source":"## Importing libraries","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport math\nimport plotly.express as px\nimport pickle\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.model_selection import train_test_split\nfrom sklearn import metrics","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Reading the  data","metadata":{}},{"cell_type":"markdown","source":"> The horse_ids and horse_names data identifies a unique horse in all the races independently of the program_number.","metadata":{}},{"cell_type":"code","source":"horse_ids = pd.read_csv(\"../input/big-data-derby-2022-global-horse-ids-and-places/horse_ids.csv\", index_col=0)\nhorse_ids.drop(index = 7545, inplace=True)\nhorse_ids.reset_index(inplace=True, drop=True)\nhorse_ids.rename(columns = {\"race\" :\"race_number\", \"finishing_place\":\"position_at_finish\"}, inplace=True)\nhorse_ids[\"program_number\"].replace({'1':'1  ', '2':'2  ', '3':'3  ', '4':'4  ', '5': '5  ', '6':'6  ', '7':'7  ', '8':'8  ', '1A':'1A ', '10':'10 ', '9':'9  ', '11':'11 ', '12':'12 ', '13':'13 ', '14':'14 ',\n'2B': '2B ', '15':'15 ', '16':'16 ', '3X':'3X ', '1X':'1X '}, inplace=True)","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"horse_names = pd.read_csv(\"../input/big-data-derby-2022-global-horse-ids-and-places/horse_names.csv\", index_col=0)","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### *Start dataframe indicates the properties of each horse in each competition*","metadata":{}},{"cell_type":"code","source":"start = pd.read_csv(\"../input/big-data-derby-2022/nyra_start_table.csv\", names = [\"track_id\", \"race_date\", \"race_number\", \"program_number\", \"weight_carried\", \"jockey\", \"odds\", \"position_at_finish\"])\nstart.head()","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### *Race dataframe grants us information about the track and the racing*","metadata":{}},{"cell_type":"code","source":"race = pd.read_csv(\"../input/big-data-derby-2022/nyra_race_table.csv\")\nrace.head()","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### Tracking dataframe indicates the position of each horse every 0.25 seconds*","metadata":{}},{"cell_type":"code","source":"tracking = pd.read_csv(\"../input/big-data-derby-2022/nyra_tracking_table.csv\")\ntracking.head()","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"merge_start_horse_ids = pd.merge(start, horse_ids, on=[\"track_id\", \"race_date\", \"race_number\",\"program_number\", \"position_at_finish\"])","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"start = pd.merge(merge_start_horse_ids, horse_names, on= \"horse_id\")","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"----","metadata":{}},{"cell_type":"markdown","source":"> #### *This are the identifiers of the horses in a race*","metadata":{}},{"cell_type":"code","source":"tracking[\"program_number\"].unique()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Deleting all incoherent data","metadata":{}},{"cell_type":"code","source":"for x in race.index.copy():\n    tracking_selected = tracking[(tracking[\"track_id\"] == race[\"track_id\"][x]) & (tracking[\"race_date\"] == race[\"race_date\"][x]) & (tracking[\"race_number\"] == race[\"race_number\"][x])]\n    start_selected = start[(start[\"track_id\"] == race[\"track_id\"][x]) & (start[\"race_date\"] == race[\"race_date\"][x]) & (start[\"race_number\"] == race[\"race_number\"][x])]\n    if len(tracking_selected[\"program_number\"].unique()) != len(start_selected[\"program_number\"].unique()):\n        race.drop(index = x, inplace = True)\n        start.drop(index = list(start_selected.index), inplace = True)\n        tracking.drop(index = list(tracking_selected.index), inplace = True)","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"race.reset_index(inplace = True, drop = True)\nstart.reset_index(inplace = True, drop = True)\ntracking.reset_index(inplace = True, drop = True)","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Visualyzing the route of one horse","metadata":{}},{"cell_type":"markdown","source":"#### **Define a variable which represents the tracking dataframe filtered by one racing**","metadata":{}},{"cell_type":"code","source":"tracking_example = tracking[(tracking[\"track_id\"] == race[\"track_id\"][0]) & (tracking[\"race_date\"] == race[\"race_date\"][0]) & (tracking[\"race_number\"] == race[\"race_number\"][0])].sort_values(by = [\"trakus_index\"])","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### *We can see all horses is tracked the same times*","metadata":{}},{"cell_type":"code","source":"tracking_example[\"program_number\"].value_counts()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **Visualize the track**","metadata":{}},{"cell_type":"code","source":"sns.scatterplot(data = tracking[tracking[\"track_id\"] == \"AQU\"].sort_values(by = \"trakus_index\"), x = \"longitude\", y = \"latitude\")","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **Visualize the cordenades as points of the previously created variable filtered by only one horse**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (10,10))\nsns.scatterplot(data = tracking_example[tracking_example[\"program_number\"] == \"5  \"], x = \"longitude\", y = \"latitude\", hue = \"trakus_index\");","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **Now we're going to do the same but showing all the horses**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (10,10))\nsns.scatterplot(data = tracking_example, x = \"longitude\", y = \"latitude\", hue = \"program_number\",hue_order=[\"1  \", \"2  \", \"3  \", \"4  \", \"5  \"]);","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **Watch the next animation about the race**","metadata":{}},{"cell_type":"code","source":"fig=px.scatter(tracking_example, x=\"longitude\", y=\"latitude\", animation_frame=\"trakus_index\", animation_group=\"program_number\", color = \"program_number\", hover_name = \"program_number\",\nrange_x=[tracking_example[\"longitude\"].min()-0.0002, tracking_example[\"longitude\"].max()+0.0002], range_y=[tracking_example[\"latitude\"].min()-0.0002, tracking_example[\"latitude\"].max()+0.0002])\nfig.update_layout(showlegend=True, autosize = False, width = 800, height = 800, template = \"plotly_dark\", title = \"Example of a horse race tracking\")","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **Now we're going to do the same but focusing in the final, middle and beginning part of the race**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(25,10))\nplt.subplot(1,3,1)\nplt.title(\"Final\")\nsns.scatterplot(data = tracking_example[1000:], x = \"longitude\", y = \"latitude\", hue = \"program_number\",hue_order=[\"1  \", \"2  \", \"3  \", \"4  \", \"5  \"]);\nplt.title\nplt.subplot(1,3,2)\nplt.ylim((40.6728, 40.6764))\nplt.title(\"Middle\")\nsns.scatterplot(data = tracking_example[500:1000], x = \"longitude\", y = \"latitude\", hue = \"program_number\",hue_order=[\"1  \", \"2  \", \"3  \", \"4  \", \"5  \"]);\nplt.subplot(1,3,3)\nplt.title(\"Beginning\")\nsns.scatterplot(data = tracking_example[:500], x = \"longitude\", y = \"latitude\", hue = \"program_number\",hue_order=[\"1  \", \"2  \", \"3  \", \"4  \", \"5  \"]);","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### We can see each horse takes a different route","metadata":{}},{"cell_type":"markdown","source":"## Calculate the position of each horse in the race","metadata":{}},{"cell_type":"markdown","source":"> #### The plan is to trace a mean route of the race in which the last point will be the last position of the winning horse. After that,  we are going to calculate the distance of each horse to the nearest position of the mean route and then calculate the distance to the follow point successively to the last point for later to sum all the values. We have to do this because the track isn't a straight line. In summary, we are going to measure the lenght of a line representing a route instead of a straight line. I'm going to simply representate it graphically. In the next graphic, the green line is the line to measure and the blue line is the track.","metadata":{}},{"cell_type":"markdown","source":"#### **Visualize the calculation we want to do**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(25,10))\nplt.subplot(2,2,1)\nplt.title(\"first measure\")\nplt.plot(tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"longitude\"], tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"latitude\"],\"-\", linewidth = 20)\nplt.plot(tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"longitude\"], tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"latitude\"], \"--\", color = \"g\", linewidth = 9)\nplt.subplot(2,2,2)\nplt.title(\"second measure\")\nplt.plot(tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"longitude\"], tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"latitude\"], \"-\", linewidth = 20)\nplt.plot(tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"longitude\"].iloc[25:], tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"latitude\"].iloc[25:], \"--\", color = \"g\", linewidth = 9)\nplt.xlabel(\"longitude\")\nplt.ylabel(\"latitude\");\nplt.subplot(2,2,3)\nplt.title(\"third measure\")\nplt.plot(tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"longitude\"], tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"latitude\"], \"-\", linewidth = 20)\nplt.plot(tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"longitude\"].iloc[50:], tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"latitude\"].iloc[50:], \"--\", color = \"g\", linewidth = 9)\nplt.subplot(2,2,4)\nplt.title(\"fourth measure\")\nplt.plot(tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"longitude\"], tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"latitude\"], \"-\", linewidth = 20)\nplt.plot(tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"longitude\"].iloc[75:], tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"latitude\"].iloc[75:], \"--\", color = \"g\", linewidth = 9)\nsns.scatterplot(x = [tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"longitude\"].iloc[75]], y = [tracking_example[tracking_example[\"program_number\"] == \"1  \"][\"latitude\"].iloc[75]])","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **Create new data grouping the dataframe by the index of tracking and calculate the mean of each horse both longitude and latitude**","metadata":{}},{"cell_type":"code","source":"tracking_example_mean_route = tracking_example.groupby(\"trakus_index\")[[\"latitude\", \"longitude\"]].mean()#This variable will represent the track.","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tracking_example_mean_route.head()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **Add the lasts coordenates of the winning horse**","metadata":{}},{"cell_type":"code","source":"lasts_coordenates = tracking_example[(tracking_example[\"program_number\"] == \nstart[(start[\"track_id\"] == tracking_example[\"track_id\"].iloc[0]) \n& (start[\"race_date\"] == tracking_example[\"race_date\"].iloc[0]) \n& (start[\"race_number\"] == tracking_example[\"race_number\"].iloc[0])\n& (start[\"position_at_finish\"] == 1)][\"program_number\"].iloc[0])\n& (tracking_example[\"trakus_index\"] == 316)][[\"latitude\", \"longitude\"]]\ntracking_example_mean_route.loc[317] = [lasts_coordenates[\"latitude\"].iloc[0], lasts_coordenates[\"longitude\"].iloc[0]]","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tracking_example_mean_route.loc[317] = [lasts_coordenates[\"latitude\"].iloc[0], lasts_coordenates[\"longitude\"].iloc[0]]\ntracking_example_mean_route.reset_index(drop = True, inplace = True)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tracking_example_mean_route","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### *The coordenates will always be ordered because, though some horses go further back and others go further forward, no horse will go back so the mean of the coordenates will always go forward.*","metadata":{}},{"cell_type":"markdown","source":"#### **The reference points of the track**","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (10,10))\nsns.scatterplot(data = tracking_example_mean_route, x = \"longitude\", y = \"latitude\");","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **Now we are going to make a function that calculates the distance between a point and the next**","metadata":{}},{"cell_type":"code","source":"def two_points_distance(coordenates1, coordenates2):\n    difference_latitude = np.abs(coordenates1[\"latitude\"]-coordenates2[\"latitude\"])\n    difference_longitude = np.abs(coordenates1[\"longitude\"]-coordenates2[\"longitude\"])\n    hypotenuse = np.sqrt((difference_latitude ** 2) + (difference_longitude ** 2))\n    return hypotenuse","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **So let's see which horse goes first in real time**","metadata":{}},{"cell_type":"markdown","source":"> #### *The next function is used to select the corresponding data of each dataframe depending on the race num selected. This will be useful for later.*","metadata":{}},{"cell_type":"code","source":"def tracking_position_horses(trackingdata, meanroutedata):\n    first_horse = []#Variable with as many list of tuples as trakus_index unique values.\n    for trakus in trackingdata[\"trakus_index\"].unique():#This loop is used to know which horse goes first in each trakus_index.\n        horse_distance = []# Variable used to know which horse is closer to the goal for each trakus_index.\n        for register in trackingdata[trackingdata[\"trakus_index\"] == trakus].index:# This loop iterates through each row to compare all the horses in a single trakus_index.\n            distance_coordenates =[]# This variable has all distances from the coordenates of the horse to all the other coordenates.\n            for coordenate in meanroutedata.index:# This loop calculates the distance of one coordenate of a horse to all others coordenates of the track.\n                distance_coordenates.append(two_points_distance(trackingdata.loc[register][[\"latitude\", \"longitude\"]], meanroutedata.iloc[coordenate]))\n            index_min_distance = distance_coordenates.index(np.min(distance_coordenates))# Index of the nearest coordenate.\n            distances = []# This variable has the distances of all the points that remain to reach the goal.\n            distances.append(two_points_distance(trackingdata.loc[register][[\"latitude\", \"longitude\"]], meanroutedata.iloc[index_min_distance]))# Append the distance from the horse point to the nearest track reference point.\n            for x in meanroutedata[index_min_distance:-1].index:# This loop is used to calculate the distance between a point and the next iterating over all remaining points.\n                distances.append(two_points_distance(meanroutedata.iloc[x], meanroutedata.iloc[x+1]))\n            distance_to_end = np.sum(distances)# The sum of the remaining points. This represent the remaining distance to the goal.\n            horse_distance.append((trackingdata.loc[register][\"program_number\"], distance_to_end))\n        first_horse.append(sorted(horse_distance, key = lambda x:x[1]))# for each trakus_index append a list of tuples in which the first element is the horse that goes first.\n    return first_horse","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"first_horse_example = tracking_position_horses(tracking_example, tracking_example_mean_route)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### *We can see the horse that finished in first position is the one that in the last trakus_index has lenght 0 to the final point*","metadata":{}},{"cell_type":"code","source":"print(\"lenght of the list:\", len(first_horse_example))\nprint(\"last trakus_index:\", first_horse_example[-1])\nprint(\"winning horse program_number:\", tracking_example[(tracking_example[\"program_number\"] == \nstart[(start[\"track_id\"] == tracking_example[\"track_id\"].iloc[0]) \n& (start[\"race_date\"] == tracking_example[\"race_date\"].iloc[0]) \n& (start[\"race_number\"] == tracking_example[\"race_number\"].iloc[0])\n& (start[\"position_at_finish\"] == 1)][\"program_number\"].iloc[0])][\"program_number\"].unique())","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Machine Learning","metadata":{}},{"cell_type":"markdown","source":"#### **Predictive Model**","metadata":{}},{"cell_type":"markdown","source":"> #### This is the central part of this notebook. We are going to make a model to predict the next position of a horse depending on the jockey, the condition of the track, the type of race, the distance of the race, the course type, the weight carried and, the most important thing, all the previus coordenates. This could be used to make simulations of horses racing and predict which horse is going to win depending on the jockey, depending on the weight, or other differenct parametters. This is also useful for the riders and horse owners to take decissions around all this parametters, they could plan strategies to increase the equine performance. This might continue evolve to the equine welfare terrain, know good practices and prevent horses injuries with this simulations.","metadata":{}},{"cell_type":"markdown","source":"> #### *This function is made to get all the necessary data of a race*","metadata":{}},{"cell_type":"code","source":"def select_data(racenum):\n    race_data = race.iloc[racenum]\n    start_data = start[(start[\"track_id\"] == race_data[\"track_id\"]) & (start[\"race_date\"] == race_data[\"race_date\"]) & (start[\"race_number\"] == race_data[\"race_number\"])]\n    tracking_data = tracking[(tracking[\"track_id\"] == race_data[\"track_id\"]) & (tracking[\"race_date\"] == race_data[\"race_date\"]) & (tracking[\"race_number\"] == race_data[\"race_number\"])]\n    winner = start_data[start_data[\"position_at_finish\"] == 1][\"program_number\"].iloc[0]\n    mean_route = tracking_data.groupby(\"trakus_index\")[[\"latitude\", \"longitude\"]].mean()\n    lasts_coordenates = tracking[(tracking[\"program_number\"] == winner) & (tracking[\"trakus_index\"] == 316)][[\"latitude\", \"longitude\"]]\n    mean_route.loc[317] = [lasts_coordenates[\"latitude\"].iloc[0], lasts_coordenates[\"longitude\"].iloc[0]]\n    mean_route.reset_index(drop = True, inplace = True)\n    return race_data, start_data, tracking_data, mean_route","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"start2 = start.copy()\nstart2 = pd.get_dummies(data = start2, columns = [\"jockey\"])\nstart2.drop(columns = [\"position_at_finish\",\"horse_name\"], inplace = True)\nstart2","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"race2 = pd.merge(race, start2, on = [\"track_id\", \"race_date\", \"race_number\"])\nrace2 = pd.get_dummies(data = race2, columns = [\"course_type\", \"track_condition\", \"race_type\"])\nrace2","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"columns_lat = []\nfor x in range(tracking[\"trakus_index\"].max()):\n    columns_lat.append(\"last_lat_track\" + str(x+1))\ncolumns_long = []\nfor x in range(tracking[\"trakus_index\"].max()):\n    columns_long.append(\"last_long_track\" + str(x+1))\ncolumns = columns_lat + columns_long\ntracking2 = pd.DataFrame(columns = columns)","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### *This function create the necessary data for the model. The \"last_lat_track1\" and \"last_long_track1\" columns refers to the current position of the horse. The \"last_lat_track2\" column refers to the last position of the horse and the \"last_lat_track3\" column to the penultimate position*","metadata":{}},{"cell_type":"code","source":"def tracking_function():\n    num = 0\n    for race_index in race.index[:100]:\n        tracking_selected = tracking[(tracking[\"track_id\"] == race[\"track_id\"][race_index]) & (tracking[\"race_date\"] == race[\"race_date\"][race_index]) & (tracking[\"race_number\"] == race[\"race_number\"][race_index])]\n        for program_number in tracking_selected[\"program_number\"].unique():\n            print(\"race = \", race_index, \"program_number = \", program_number)\n            track_exa = tracking_selected[tracking_selected[\"program_number\"] == program_number].sort_values(by = \"trakus_index\")\n            for trakus_index in track_exa[\"trakus_index\"].values[1:]:\n                num2 = 0\n                if (trakus_index == 300):\n                    print(\"trakus_index =\", 300)\n                for index in range(trakus_index, 0, -1):\n                    point = track_exa[track_exa[\"trakus_index\"] == index]\n                    tracking2.loc[num, columns_lat[num2]] = point[\"latitude\"].iloc[0]\n                    tracking2.loc[num, columns_long[num2]] = point[\"longitude\"].iloc[0]\n                    num2 += 1\n                num += 1","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### *This function get the columns of each row created of the previus DataFrame to merge them*","metadata":{}},{"cell_type":"code","source":"def columns_tracking_function():\n    global id_tracking2\n    id_tracking2 = pd.DataFrame(columns = [\"track_id\", \"race_date\", \"race_number\", \"program_number\", \"trakus_index\"])\n    num = 0\n    for race_index in race.index[:100]:\n        tracking_selected = tracking[(tracking[\"track_id\"] == race[\"track_id\"][race_index]) & (tracking[\"race_date\"] == race[\"race_date\"][race_index]) & (tracking[\"race_number\"] == race[\"race_number\"][race_index])]\n        for program_number in tracking_selected[\"program_number\"].unique():\n            print(\"race = \", race_index, \"program_number = \", program_number)\n            track_exa = tracking_selected[tracking_selected[\"program_number\"] == program_number].sort_values(by = \"trakus_index\")\n            for trakus_index in track_exa[\"trakus_index\"].values[1:]:\n                if (trakus_index == 300):\n                    print(\"trakus_index =\", 300)\n                id_tracking2 = id_tracking2.append({\"track_id\":tracking_selected[\"track_id\"].iloc[0], \"race_date\":tracking_selected[\"race_date\"].iloc[0], \"race_number\":tracking_selected[\"race_number\"].iloc[0], \"program_number\":program_number, \"trakus_index\":trakus_index}, ignore_index=True)\n                if len(id_tracking2) == len(tracking2):\n                    return\n                num += 1","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### *I stopped the function in the 19th race because it takes too long to finish.*","metadata":{}},{"cell_type":"code","source":"tracking_function()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"columns_tracking_function()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# tracking_function tooks too long so I decided to save this variable\nwith open(\"tracking2.pickle\", \"wb\") as f:\n    pickle.dump(tracking2, f)","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tracking2","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trackingDef = pd.concat([id_tracking2, tracking2], axis = 1)","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trackingDef","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data = pd.merge(left=race2, right = trackingDef, on= [\"track_id\", \"race_date\", \"race_number\", \"program_number\"])\ndata.drop(columns = [\"program_number\"], inplace = True)\ndata = pd.get_dummies(data = data, columns = [\"horse_id\"])\ndata","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data.fillna(0, inplace = True)","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y = data[[\"last_lat_track1\", \"last_long_track1\"]]\nx = data.drop(columns = [\"last_lat_track1\", \"last_long_track1\",\"track_id\", \"race_date\", \"race_number\"])\nxtrain, xtest, ytrain, ytest = train_test_split(x, y, test_size = 0.2, random_state = 20)\nmodel = RandomForestRegressor(n_jobs = -1, n_estimators = 10)\nmodel.fit(xtrain, ytrain)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### We can see the errors are very small. On average, the values are 0.0000004 above or below. And with the mean squared error(MSE) we can see that we don't have many big errors. But this doesn't mean enything if we don't know how much the values vary between each other.","metadata":{}},{"cell_type":"code","source":"print(\"MAE:\", metrics.mean_absolute_error(model.predict(xtest), ytest, multioutput = \"uniform_average\"))\nprint(\"MSE:\", metrics.mean_squared_error(model.predict(xtest), ytest, multioutput = \"uniform_average\"))\nprint(\"RMSE:\", np.sqrt(metrics.mean_squared_error(model.predict(xtest), ytest, multioutput = \"uniform_average\")))","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **Model check and feature importance**","metadata":{}},{"cell_type":"markdown","source":"> #### Here we can see the values of the data choosed go from 40.668 to 40.676.","metadata":{}},{"cell_type":"code","source":"sns.histplot(data[\"last_lat_track1\"])","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### And here we can see the values are principaly concentrated betweed 40.671 and 50.674.","metadata":{}},{"cell_type":"code","source":"sns.boxplot(data[\"last_lat_track1\"])","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### To ensure the accuracy of our model we are going to see the values of the coordenated of one race","metadata":{}},{"cell_type":"code","source":"sns.histplot(tracking_example[\"latitude\"])","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.histplot(tracking_example[\"longitude\"])","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### We can see the values vary a 0.5 more or less so we can definetively say our model has a good precission.","metadata":{}},{"cell_type":"markdown","source":"> #### *Here we can see which variable are the most important for the model and we see it's the \"last_lat_track2\" columns. So the most important data to predict the next positon is the last previous position*","metadata":{}},{"cell_type":"code","source":"sorted(list(enumerate(model.feature_importances_)), key = lambda x:x[1], reverse=True)[0]","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"list(x.columns)[209]","metadata":{"_kg_hide-input":false},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model improvement","metadata":{}},{"cell_type":"markdown","source":"#### **Kneighbours**","metadata":{}},{"cell_type":"code","source":"from sklearn.neighbors import KNeighborsRegressor","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model2 = KNeighborsRegressor(n_jobs = -1, n_neighbors=2000)\nmodel2.fit(xtrain, ytrain)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"MAE:\", metrics.mean_absolute_error(model2.predict(xtest), ytest, multioutput = \"uniform_average\"))\nprint(\"MSE:\", metrics.mean_squared_error(model2.predict(xtest), ytest, multioutput = \"uniform_average\"))\nprint(\"RMSE:\", np.sqrt(metrics.mean_squared_error(model2.predict(xtest), ytest, multioutput = \"uniform_average\")))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **Linear Regression**","metadata":{}},{"cell_type":"code","source":"from sklearn.linear_model import LinearRegression","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model3 = LinearRegression()\nmodel3.fit(xtrain, ytrain)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"MAE:\", metrics.mean_absolute_error(model3.predict(xtest), ytest, multioutput = \"uniform_average\"))\nprint(\"MSE:\", metrics.mean_squared_error(model3.predict(xtest), ytest, multioutput = \"uniform_average\"))\nprint(\"RMSE:\", np.sqrt(metrics.mean_squared_error(model3.predict(xtest), ytest, multioutput = \"uniform_average\")))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> #### *The best model is the first choosed*","metadata":{}},{"cell_type":"markdown","source":"#### **GridSearch**","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import GridSearchCV","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = RandomForestRegressor(n_jobs = -1, max_depth = 90)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"GS = GridSearchCV(estimator = model, param_grid = {\"n_estimators\" : [78,79, 80, 81]}, verbose = 2.1, cv = 2)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"GS.fit(xtrain, ytrain)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Best Model","metadata":{}},{"cell_type":"code","source":"print(\"MAE:\", metrics.mean_absolute_error(GS.predict(xtest), ytest, multioutput = \"uniform_average\"))\nprint(\"MSE:\", metrics.mean_squared_error(GS.predict(xtest), ytest, multioutput = \"uniform_average\"))\nprint(\"RMSE:\", np.sqrt(metrics.mean_squared_error(GS.predict(xtest), ytest, multioutput = \"uniform_average\")))","metadata":{"_kg_hide-input":true},"execution_count":null,"outputs":[]}]}