{"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":"# Making Latitude and Longitude Usable For Distances\nThe Big Data Derby data set uses latitude and longitude to track the horses' positions. Using the coordinates directly as units of distance poses a problem. One degree of latitude is not equal to one degree of longitude at most points on Earth, including New York State where the tracks are located. Also, the coordinates as given have the track on an angle which makes measuring speeds and distances more complicated.\n\nThis notebook is my solution to these issues. I convert the latitude and longitude units to an approximation in feet, and rotate the track so the main straights are oriented horizontally.","metadata":{}},{"cell_type":"code","source":"\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport math\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n#import the data\npath_to_file = \"/kaggle/input/big-data-derby-2022/nyra_tracking_table.csv\"\n\ntracking = pd.read_csv(path_to_file)\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-09-09T21:40:10.588181Z","iopub.execute_input":"2022-09-09T21:40:10.588535Z","iopub.status.idle":"2022-09-09T21:40:13.963387Z","shell.execute_reply.started":"2022-09-09T21:40:10.588509Z","shell.execute_reply":"2022-09-09T21:40:13.962324Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"First, I calculate an approximation of feet per longitudinal degree at Belmont race track (I will use the 2019 Belmont Stakes as the example for this notebook). We only need to calculate longitude because one degree of latitude is roughly equal to 69 miles at every point on Earth because these lines run parallel (however there are slight variations). Longitudinal lines run from pole to pole and the distance between them converges to zero at the poles.","metadata":{}},{"cell_type":"code","source":"#the distance between longitudinal lines depends on the latitude \ntrack_latitude = tracking.loc[tracking.track_id==\"BEL\", \"latitude\"].mean()\n#the distance between longitude lines at the equator \nequator_mi_per_lon = 69.172\n\n#covert latitude to radians\nlat_radian = (math.pi  * track_latitude)/180\n#take cosin\ncos_radian = math.cos(lat_radian)\n#multiple by ratio at the equator\nmi_per_lon= equator_mi_per_lon * cos_radian\n#constant for latitude distance\nmi_per_lat = 69\n\n#convert to feet\nfeet_per_longitude = mi_per_lon * 5280\nfeet_per_latitude = mi_per_lat * 5280\n\nprint(\"Average latitude of Belmont Track: \"+str(track_latitude))\nprint(\"At Belmont, one degree of longitude equals approximately \"+str(feet_per_longitude)+\" feet.\")\nprint(\"One degree of latitude equals approximately \"+str(feet_per_latitude)+ \" feet\")","metadata":{"execution":{"iopub.status.busy":"2022-09-09T21:40:13.965207Z","iopub.execute_input":"2022-09-09T21:40:13.965480Z","iopub.status.idle":"2022-09-09T21:40:14.308139Z","shell.execute_reply.started":"2022-09-09T21:40:13.965455Z","shell.execute_reply":"2022-09-09T21:40:14.307057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Next, I'll get the data from the 2019 Belmont Stakes for our example, and add columns for the conversions from lat/long degrees to feet.","metadata":{}},{"cell_type":"code","source":"race_no = 11\ndate = \"2019-06-08\"\n \nbelmont_19 = tracking.loc[(tracking.race_number ==race_no) & (tracking.race_date == date)]\nbelmont_19 = belmont_19.sort_values('trakus_index', axis=0)\n\nbelmont_19[\"latitudeFT\"] = (belmont_19.latitude )* feet_per_latitude\nbelmont_19[\"longitudeFT\"] = (belmont_19.longitude ) * feet_per_longitude\n\nprint(belmont_19.head())","metadata":{"execution":{"iopub.status.busy":"2022-09-09T21:40:14.309868Z","iopub.execute_input":"2022-09-09T21:40:14.310187Z","iopub.status.idle":"2022-09-09T21:40:14.631020Z","shell.execute_reply.started":"2022-09-09T21:40:14.310163Z","shell.execute_reply":"2022-09-09T21:40:14.630006Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now Let's take a look at what the track looks like.","metadata":{}},{"cell_type":"code","source":"g= sns.scatterplot(data= belmont_19, x = \"longitudeFT\", y= \"latitudeFT\",hue=\"program_number\"\\\n               ,size=\"trakus_index\",legend=False)\n","metadata":{"execution":{"iopub.status.busy":"2022-09-09T21:40:14.633122Z","iopub.execute_input":"2022-09-09T21:40:14.633359Z","iopub.status.idle":"2022-09-09T21:40:15.060248Z","shell.execute_reply.started":"2022-09-09T21:40:14.633336Z","shell.execute_reply":"2022-09-09T21:40:15.058169Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"It would be easier to work with the track if it was oriented horizontally, so let's write some functions to do that.","metadata":{}},{"cell_type":"code","source":"#this function will rotate the track by the selected radians, and list the coordiantes\n#in new columns\ndef rotateTrack(df, theta):\n    new = df.copy()\n    \n    sin_theta = math.sin(theta)\n    cos_theta = math.cos(theta)\n    \n    new[\"x_coord\"] = (new[\"longitudeFT\"] * cos_theta) + (new[\"latitudeFT\"] * sin_theta)\n    new[\"y_coord\"] = (-1 * new[\"longitudeFT\"] * sin_theta) + (new[\"latitudeFT\"] * cos_theta)\n\n    return new\n\n#This function approximates the best angle to rotate the track based on minimizing\n#the distance between the highest and lowest Y coordiante. \ndef findOrientation(df, max_iter):\n    new = df.copy()\n    \n    best_theta = 2 * math.pi\n    theta = math.pi\n    \n    i = 0\n    while (i<max_iter):\n        new = rotateTrack(new, best_theta)\n        best_outcome = max(new[\"y_coord\"]) - min(new[\"y_coord\"])\n        \n        new = rotateTrack(new, theta)      \n        new_outcome = max(new[\"y_coord\"]) - min(new[\"y_coord\"])\n        \n        if (new_outcome< best_outcome): \n            old_theta = best_theta\n            best_theta = theta\n            theta = (best_theta + old_theta)/2\n            \n        else:\n            theta = (best_theta+theta) /2\n            \n        i+=1\n            \n    return rotateTrack(new, best_theta)","metadata":{"execution":{"iopub.status.busy":"2022-09-09T21:40:15.063362Z","iopub.execute_input":"2022-09-09T21:40:15.063742Z","iopub.status.idle":"2022-09-09T21:40:15.075042Z","shell.execute_reply.started":"2022-09-09T21:40:15.063715Z","shell.execute_reply":"2022-09-09T21:40:15.073672Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's apply the functions to the 2019 belmont stakes","metadata":{}},{"cell_type":"code","source":"belmont_19 = findOrientation(belmont_19, 100)\n\n#let's also make the new coordinates into an easier range of numbers\nbelmont_19.x_coord = belmont_19.x_coord - min(belmont_19.x_coord)\nbelmont_19.y_coord = belmont_19.y_coord - min(belmont_19.y_coord)\n\n#and show the new track\nsns.set(rc={'figure.figsize':(5,5)})\n   \ng= sns.scatterplot(data= belmont_19, x = \"x_coord\", y= \"y_coord\",hue=\"program_number\"\\\n                ,size=\"trakus_index\",legend=False)\n\n#create the window so that the track dimensions are equal\nupper_long = max(belmont_19.x_coord) +100\nlower_long = min(belmont_19.x_coord) - 100\n\nrange_axis = upper_long - lower_long\n\nlower_lat = min(belmont_19.y_coord) -100\nupper_lat = lower_lat + range_axis\n\ng.set(xlim=(lower_long, upper_long))\ng.set(ylim=(lower_lat,  upper_lat))\n","metadata":{"execution":{"iopub.status.busy":"2022-09-09T21:40:32.955785Z","iopub.execute_input":"2022-09-09T21:40:32.956135Z","iopub.status.idle":"2022-09-09T21:40:33.802136Z","shell.execute_reply.started":"2022-09-09T21:40:32.956111Z","shell.execute_reply":"2022-09-09T21:40:33.800755Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The new coordinates should be a very close approximation\nto feet, but not quite exact. To get the exact numbers you would need to find the exact distance between lattitudes at the track which can vary based on the eliptical shape of the earth. Also its possible that the track is not perfectly horizontally aligned from my function. \n\nI think these transformations make the data easier to work with. I'd like to hear any ideas that could improve this.","metadata":{}},{"cell_type":"markdown","source":"","metadata":{}}]}