{"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":"<div align=\"center\"><p style=\"font-size:36px; font-family: Helvetica; font-weight: bold; color:teal\">Big Data Derby 2022: Jockey's decisions and Odds of winning</p></div>","metadata":{}},{"cell_type":"markdown","source":"<div style='background-color: teal; color: white; font-family: Helvetica; font-size: 24px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"1\">Executive Summary</div>\n\n<div style=\"font-family: Helvetica; font-size: 16px; font-weight:normal;  padding: 6px 12px; margin-bottom: 5px;\"> \n\nThis analysis starts with some introduction about horse racing, then continues with an exploratory analysis of the 2019 horse racing data to understand the core elements of horse racing through graphs. The basic elements can be summarized as <mark> WHEN, WHERE, and HOW</mark>. WHERE includes the tracks, courses; HOW includes course conditions, distances, race types, number of races on a race day, number of racehorses in a race; WHEN includes what day in the week and what time in the day were the races.\n<br><br>\n    \n\n    \nAfter gaining the basic knowledge about the details on racing setups, the analysis goes deep on jockeys. First, the performance of jockeys: the overall win rate and place rate of jockeys, if there is a preferred (or lucky) track or distance for top jockeys, how does the win rate and place rate for top jockeys change over the year.  Second, the competition among jockeys: how often jockeys compete against each other, how two jockeys defeat each other throughout the year. And finally, how to jockeys make their decisions in tuning their speed in a race to achieve good performance.\n<br><br>\n      \n    \nAfter a thorough analysis on the <mark>WHO, WHERE, WHEN, and HOW</mark> elements of horse races, the analysis goes into the part that people are truly interested in: the odds and bets. According to the <mark>Efficient-market hypothesis</mark>, if markets are efficient, then all information is already incorporated into prices, and so there is no way to \"beat\" the market because there are no undervalued or overvalued securities available. Does this theory apply to horse racing, meaning the odds reflects the all the information about horses and jockeys, and making profits by beating the odds is unlikely? In this analysis, we look at factors that drive the odds. \n    \n</div>\n    \n","metadata":{}},{"cell_type":"markdown","source":"<div style='color: teal; font-family: Helvetica; font-size: 18px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px; ' >Key numbers</div>\n\n<div style='font-family: Helvetica; font-size: 16px; font-weight:normal; padding: 6px 12px; margin-bottom: 5px; '>\n    \n1. There were 14,915 starts in 2,000 races on 217 race days by 178 jockeys on 3 racing tracks in 2019.\n<br>\n    \n2. Over than two-fifths races were raced on Aqueduct; over two-thirds of races were on dirt track; over one-fourth races were in 6 furlongs (i.e 600)\n<br>\n    \n3. Over 60% races were either Claiming, Maiden Special Weight, or Maiden Claiming races. Most race days had 9 races; most races had 6 racehorses.\n<br>\n\n4. Most races on Dirt track were 6 furlongs; Most races on Turf track were 8.5 furlongs. The track condition for most races was Fast on Dirt track; The track condition for most races was Firm on Turf track.\n<br>\n\n5. Throughout the year, most horse races took place on Friday and the whole weekend. Most races took place between 1pm and 6pm.\n<br>\n    \n6. Races from Nov to Apr took place mostly on Aqueduct track; races in May,Jun, Oct were mostly on Belmont track; races from Jul to Sep were mostly on Saratoga track.\n\n</div>\n\n\n","metadata":{}},{"cell_type":"markdown","source":"<div style='color: teal; font-family: Helvetica; font-size: 18px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' >The jockeys</div>\n\n<div style='font-family: Helvetica; font-size: 16px; font-weight:normal; padding: 6px 12px; margin-bottom: 5px; '>\n    \n1. Manuel Franco took part in 1274 (63.7%) races and won 214 of them. This means among all the races took place in 2019, over one in ten races had the 1st place taken by Manuel Franco. He finished in top 3 positions in 620 races, which is 31% of all races.\n<br>\n\n2. Jose Lezcano raced in 990 races, won 206 races and had win rate of 20.8%. He finished in top 3 positions in 491 races, which is 49.6% out of all races he participated.  \n<br>    \n    \n3. Javier Castellano and Jose Lezcano had a win rate around 21%. Four jockeys had place rate more than 50%, and they were Javier Castellano, Irad Ortiz Jr. Joel Rosario, and Jose L. Ortiz.\n<br>\n\n4. Manuel Franco had an overall win rate around 17%, but his win rate at Aqueduct was more than 22%. His performance on Saratoga dragged the overall rate down. \n<br>\n\n5. Manuel Franco and Dylan Davis competed against each in the highest number of races. They ran together in 726 races, which accounted for more than 36% of all races in 2019.\n<br>\n\n6. Manuel Franco vs Dylan Davis: after the initial fluctuations in the first 100ish races, these two gained certain equilibrium.\n\n</div>","metadata":{}},{"cell_type":"markdown","source":"<div style='color: teal; font-family: Helvetica; font-size: 18px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px; '>The odds</div>\n\n<div style='font-family: Helvetica; font-size: 16px; font-weight:normal; padding: 6px 12px; margin-bottom: 5px; '>\n\nHigh correlation between odds and finishing position: The density plot of Odds shows that \"the market expectations\" (i.e. speculations on winning chances) had a high correlation to the actual wins: the odds concentrated on the very left for jockeys/horses finished in 1st place. \n<br>    \n\nOdds, jockeys, and tracks: Some jockeys performed better on certain tracks than other tracks, the odds also reflected the differences in performances on different tracks, showing that the expectations on winning factored in not only jockey's overall performances but also performances on each track. \n<br>    \n\nOdds and previous 30-day win rates/place rates: When a jockey's win rate in previous 30 race days was below 0.2 (i.e. win rate less than 20%), there was no obvious pattern on odds; when the rate was above 0.2, the odds were low in comparison.When a jockey's place rate in previous 30 race days was below 0.6 (i.e. less than 60% place rate), there was no obvious pattern on odds; when the rate was above 0.6, the odds were low in comparison.\n\n</div>","metadata":{}},{"cell_type":"markdown","source":"<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"toc\">Table of Contents</div>\n\n\n        \n- [1. Introduction](#1)\n    - [1.1 What is horse racing](#1.1)\n    - [1.2 NYRA and NYTHA](#1.2)\n    \n\n- [2. When and where: the basics of horse racing](#2)\n    - [2.1 Undertand the basic elements of horse racing through charts](#2.1)\n    - [2.2 Racing course types - How do they differ from each other](#2.2)\n    - [2.3 Dates and time: When did the races take place](#2.3)\n    \n    \n- [3. Who: the jockeys](#3)\n    - [3.1 Win win win!](#3.1)\n    - [3.2 How did jockeys' performance progress over time?](#3.2)\n    - [3.3 Zero-sum game](#3.3)\n    - [3.4 Speed analysis and Jockey's decisions](#3.4)\n    \n    \n- [4. Bets: odds of winning](#4)\n    - [4.1 Odd by finishing position](#4.1)\n    - [4.2 Odds of top 15 jockeys by track](#4.2)\n    - [4.3 Odds and Win/Place rate in previous 30 race days](#4.3)\n    \n    \n- [5. Final thoughts](#5)\n\n- [6. Appendix](#8) \n\n","metadata":{}},{"cell_type":"markdown","source":"\n<div style='background-color: teal; color: white; font-family: Helvetica; font-size: 25px; padding: 6px 12px; margin-bottom: 5px;' id=\"1\">1. Introduction</div>\n\n[back to top](#toc)","metadata":{}},{"cell_type":"markdown","source":"<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"1.1\">1.1 What is horse racing?</div>\n\n\n**Thoroughbred racing** is a sport and industry involving the racing of Thoroughbred horses. There are two forms of the sport – flat racing and jump racing.[wiki](https://en.wikipedia.org/wiki/Thoroughbred_racing).\n\nHorse racing typically involving two or more horses ridden by jockeys (or sometimes driven without riders) over a set distance for competition. \n\nHorse races vary widely in format. Variations include restricting races to particular breeds, running over obstacles, running over different distances, running on different track surfaces, and running in different gaits. In some races, horses are assigned different weights to carry to reflect differences in ability, a process known as handicapping.\n\n\n**Flat racing** is the most common form of horse racing seen worldwide. Flat racing tracks are typically oval in shape and are generally level. Track surfaces vary, with turf most common in Europe and dirt more common in North America and Asia. \n\nIndividual flat races are run over distances ranging from 440 yards (400 m) up to two and a half miles (4 km), with distances between five and twelve furlongs (1.0 and 2.4 km) being most common. Short races are generally referred to as \"sprints\", while longer races are known as \"routes\" in the United States or \"staying races\" in Europe. Although fast acceleration (\"a turn of foot\") is usually required to win either type of race, in general sprints are seen as a test of speed, while long-distance races are seen as a test of stamina. T\n\nIn the most prestigious races, horses are generally allocated the same weight to carry for fairness, with allowances given to younger horses and female horses running against males. These races are called conditions races and offer the biggest purses. There is another category of races called handicap races where each horse is assigned a different weight to carry based on its ability.Besides the weight they carry, horses' performance can also be influenced by position relative to the inside barrier, gender, jockey, and training.[wiki](https://en.wikipedia.org/wiki/Horse_racing)\n\n![flat racing](https://upload.wikimedia.org/wikipedia/commons/thumb/1/12/Suffolk_Downs_horse_racing.JPG/1920px-Suffolk_Downs_horse_racing.JPG)\n\n\n<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"1.2\">1.2 NYRA and NYTHA</div>\n\nThe **`NYRA (New York Racing Association, Inc.)`** is the not-for-profit corporation that operates the three largest Thoroughbred horse racing tracks in the state of New York, United States: Aqueduct Racetrack in South Ozone Park, Queens; Belmont Park in Elmont; and Saratoga Race Course in Saratoga Springs.\n\nThe [**`NY Thoroughbred Horseman's Association (NYTHA)`**](https://nytha.com/about/)\n\n>For over half a century, the New York Thoroughbred Horsemen’s Association (NYTHA) has represented the interests of Thoroughbred owners and trainers at New York Racing Association (NYRA) tracks. NYTHA was founded with the objective of serving as a collective voice for the broad interests of New York’s horsemen, and to improve and increase the effectiveness of its constituents in the day-to-day business of racing. Today, NYTHA serves as the New York State Gaming Commission’s recognized representative of owners and trainers, striving to protect the economic interests of all horsemen and to gain public recognition of horse racing as a vital industry, deserving support, protection and preservation.","metadata":{}},{"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport matplotlib.pyplot as plt\nimport matplotlib.lines as mlines\nimport matplotlib.ticker as mtick\nimport matplotlib.gridspec as grid_spec\nfrom matplotlib.patches import Rectangle\n\nimport pandas as pd\nimport statsmodels.api as sm\nimport seaborn as sns\n\nimport pyarrow.parquet as pq\nimport pyarrow as pa\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:06.938700Z","iopub.execute_input":"2022-11-10T14:29:06.939510Z","iopub.status.idle":"2022-11-10T14:29:08.750151Z","shell.execute_reply.started":"2022-11-10T14:29:06.939368Z","shell.execute_reply":"2022-11-10T14:29:08.748376Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Load data","metadata":{"_kg_hide-input":true}},{"cell_type":"code","source":"#/kaggle/input/derby-2022-merge-and-convert-data-to-parquet-file/nyra_2019_complete.parquet\n\nrace_table = pd.read_csv('/kaggle/input/big-data-derby-2022/nyra_race_table.csv')\nstart_table = pd.read_csv('/kaggle/input/big-data-derby-2022/nyra_start_table.csv', header=None)\n# tracking_table = pd.read_csv('/kaggle/input/big-data-derby-2022/nyra_tracking_table.csv')\nstart_table.columns=['track_id', 'race_date', 'race_number', 'program_number', 'weight_carried', 'jockey', 'odds', 'position_at_finish']","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:08.755225Z","iopub.execute_input":"2022-11-10T14:29:08.755741Z","iopub.status.idle":"2022-11-10T14:29:08.812415Z","shell.execute_reply.started":"2022-11-10T14:29:08.755674Z","shell.execute_reply":"2022-11-10T14:29:08.811132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"race_type_dict =   {  '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                      }\n\ntrack_id_dict = dict(AQU = 'Aqueduct', BEL = 'Belmont', SAR = 'Saratoga')\ncourse_type_dict = dict(M = 'Hurdle', D = 'Dirt', O = 'Outer turf', I = 'Inner turf', T = 'turf')\ntrack_condition_dict =  dict(YL = 'Yielding', FM ='Firm', SY = 'Sloppy', GD = 'Good', FT = 'Fast', MY = 'Muddy', SF = 'Soft')\n\nrace_table['race_type'] = race_table['race_type'].map(race_type_dict)\nrace_table['track_id'] = race_table['track_id'].map(track_id_dict)\nrace_table['course_type'] = race_table['course_type'].map(course_type_dict)\n\nrace_table['track_condition']=race_table['track_condition'].apply(lambda x:x.replace(\" \", ''))\nrace_table['track_condition'] = race_table['track_condition'].map(track_condition_dict)\n\n\nstart_table['track_id'] = start_table['track_id'].map(track_id_dict)\n\nprint(start_table.shape, race_table.shape)\nstart_table = start_table.merge(race_table, on=['track_id','race_date', 'race_number'], how='inner')\nprint(start_table.shape, race_table.shape)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:08.816287Z","iopub.execute_input":"2022-11-10T14:29:08.816642Z","iopub.status.idle":"2022-11-10T14:29:08.876994Z","shell.execute_reply.started":"2022-11-10T14:29:08.816612Z","shell.execute_reply":"2022-11-10T14:29:08.875534Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n<div style='background-color: teal; color: white; font-family: Helvetica; font-size: 25px; padding: 6px 12px; margin-bottom: 5px;' id=\"2\">2. When and where: the basics of horse racing</div>\n\n[back to top](#toc)\n","metadata":{}},{"cell_type":"code","source":"#https://www.kaggle.com/code/joshuaswords/awesome-eda-2021-happiness-population\nhigh_c = 'teal'\nlow_c = 'tomato'\n\nfig = plt.figure(figsize=(6,3),dpi=100)\ngs = fig.add_gridspec(1, 1)\ngs.update(wspace=0.2, hspace=0.4)\nax0 = fig.add_subplot(gs[0, 0])\n\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\nax0.set_facecolor(background_color) \n\nax0.text(1.167,0.85,\"Derby 2022 - NYRA/NYTHA Horse Racing 2019\",color='#323232',fontsize=20, fontweight='bold', fontfamily='sanserif',ha='center')\nax0.text(1.13,-0.35,\"Key Numbers\",color='lightgray',fontsize=18, fontweight='bold', fontfamily='monospace',ha='center')\n\nax0.text(0.2,0.4,race_table['track_id'].nunique(),color=high_c,fontsize=18, fontweight='bold', fontfamily='monospace',ha='center')\nax0.text(0.2,0.1,\"Tracks\",color='gray',fontsize=15, fontfamily='monospace',ha='center')\n\nax0.text(0.7,0.4,race_table['race_date'].nunique(),color=high_c,fontsize=18, fontweight='bold', fontfamily='monospace',ha='center')\nax0.text(0.7,0.1,\"Race days\",color='gray',fontsize=15, fontfamily='monospace',ha='center')\n\nax0.text(1.2,0.4,race_table.shape[0],color=high_c,fontsize=18, fontweight='bold', fontfamily='monospace',ha='center')\nax0.text(1.2,0.1,\"Races\",color='gray',fontsize=15, fontfamily='monospace',ha='center')\n\nax0.text(1.7,0.4,start_table['jockey'].nunique(),color=low_c,fontsize=18, fontweight='bold', fontfamily='monospace',ha='center')\nax0.text(1.7,0.1,\"Jockeys\",color='gray',fontsize=15, fontfamily='monospace',ha='center')\n\nax0.text(2.2,0.4,start_table.shape[0],color=low_c,fontsize=18, fontweight='bold', fontfamily='monospace',ha='center')\nax0.text(2.2,0.1,\"Starts\",color='gray',fontsize=15, fontfamily='monospace',ha='center')\n\nax0.set_yticklabels('')\nax0.set_xticklabels('')\nax0.tick_params(axis='both',length=0)\n\nfor s in ['top','right','left','bottom']:\n    ax0.spines[s].set_visible(False)\n    \nimport matplotlib.lines as lines\nl1 = lines.Line2D([0.15, 1.95], [0.67, 0.67], transform=fig.transFigure, figure=fig,color = 'gray', linestyle='-',linewidth = 1.1, alpha = .5)\nfig.lines.extend([l1])\nl2 = lines.Line2D([0.15, 1.95], [0.07, 0.07], transform=fig.transFigure, figure=fig,color = 'gray', linestyle='-',linewidth = 1.1, alpha = .5)\nfig.lines.extend([l2])\n    \nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:08.881147Z","iopub.execute_input":"2022-11-10T14:29:08.882164Z","iopub.status.idle":"2022-11-10T14:29:09.182354Z","shell.execute_reply.started":"2022-11-10T14:29:08.882106Z","shell.execute_reply":"2022-11-10T14:29:09.181005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"2.1\">2.1 Undertand the basic elements of horse racing through charts</div>\n\n\n[back to top](#toc)\n","metadata":{}},{"cell_type":"code","source":"#https://www.kaggle.com/code/gaetanlopez/how-to-make-clean-visualizations\ncs = race_table['track_id'].value_counts().sort_values(ascending=False)\ncs1 = race_table['course_type'].value_counts().sort_values(ascending=False)[:-1]\n\n\nfig, ax = plt.subplots(1, 2, figsize=(14, 6))\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\n\n#colormap1=['firebrick','LightCoral','Salmon','DarkSalmon','mistyrose']\n#colormap2=['mistyrose','LightCoral','firebrick','Salmon','DarkSalmon','LightSalmon']\n\ncolormap1 = ['lightseagreen', 'salmon', 'lightskyblue', 'mediumseagreen', 'sandybrown', 'lightslategray', 'wheat', 'crimson']\ncolormap2 = ['turquoise', 'tomato', 'skyblue', 'wheat', 'peru', 'slategray', 'tan',  'firebrick']\n\nax[0].text(-0,1.45,\"% of races on each track\",fontsize=18,fontweight='bold', fontfamily='monospace',ha='center')\nax[0].text(-0,1.25,\"more than two-fifths races were raced on Aqueduct\",fontsize=15, ha='center')\nax[1].text(-0,1.4,\"% of races by course type\",fontsize=18,fontweight='bold', fontfamily='monospace',ha='center')\nax[1].text(-0,1.2,\"more than two-thirds of races were on dirt track\",fontsize=15,ha='center')\n\nax[0].pie(cs.values, explode=[0.1,0.1,0.1],labels=cs.index.values, autopct='%1.1f%%',\n        shadow=True, startangle=90,colors=colormap1, )\n\nax[1].pie(cs1.values, explode=[0.,0.1,0.1, 0.],labels=cs1.index.values, autopct='%1.1f%%',\n        shadow=True, startangle=90,colors=colormap2)\n\nax[0].axis('equal')\nax[1].axis('equal')\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.3, hspace=None) \nplt.tight_layout()\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:09.183872Z","iopub.execute_input":"2022-11-10T14:29:09.184262Z","iopub.status.idle":"2022-11-10T14:29:09.560897Z","shell.execute_reply.started":"2022-11-10T14:29:09.184216Z","shell.execute_reply":"2022-11-10T14:29:09.559510Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#https://www.kaggle.com/code/joshuaswords/netflix-data-visualization\ndata = race_table['distance_id'].value_counts().sort_values(ascending=False)/20\ndata.index = data.index.astype(str)\ndata = data[data>0.1]\n# Plot\n\ncolor_map = ['lightseagreen' ]*5 + ['wheat']*(data.size - 5)\n\n\nfig, ax = plt.subplots(1,1, figsize=(12, 6), dpi=100)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\nax.set_facecolor(background_color) \n\nax.bar(data.index, data, width=0.5, \n       #edgecolor='darkgray',\n       linewidth=0.6,color=color_map, alpha=0.8)\n\n#annotations\nfor i in data.index:\n    ax.annotate(f\"{data[i]}\", \n                   xy=(i, data[i] + 1.250), \n                   va = 'center', ha='center',fontweight='light', )\n\n\n\n# Remove border from plot\n\nfor s in ['top', 'left', 'right']:\n    ax.spines[s].set_visible(False)\n    \n\nfig.text(0.09, 1, '% of races by distance (600 means 6 furlongs)', color='#323232', fontsize=15, fontweight='bold', fontfamily='monospace')\n\nfig.text(0.09, 0.95, 'The top 5 distances are highlighted, only display distances with more than 1% of races.', \n         fontsize=13, fontweight='light', fontfamily='monospace', )\n\nfig.text(1., 1.0, 'Insight', fontsize=15, fontweight='bold', fontfamily='monospace')\n\nfig.text(1., 0.45, '''\nThe distances of races ranged from 4.5 furlongs \nto 14 furlongs. \n\n6 to 8.5 furlongs were top 5 distances in terms\nof % of races in 2019. \n\nMost number of races - more than \none-fourth races - were in 6 furlongs (i.e 600).\n\n8 furlongs accounted for about one-fifth races. \n\nLess than 10% races in total were \nabove 10 furlongs.\n'''\n         , fontsize=13, fontweight='light', )\n\nax.grid(axis='y', linestyle='-', alpha=0.4)   \n\n# grid_y_ticks = np.arange(0, 35, 5) # y ticks, min, max, then step\n# ax.set_yticks(grid_y_ticks)\nax.set_yticks([])\nax.set_axisbelow(True)\n\nplt.axhline(y = 0, color = 'black', linewidth = 1.3, alpha = .7)\n\nax.tick_params(axis='both', which='major', labelsize=12)\nax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\nax.spines[['top', 'right']].set_visible(False)\nax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n\nimport matplotlib.lines as lines\nl1 = lines.Line2D([0.95, 0.95], [0.1, 1.05], transform=fig.transFigure, figure=fig,color='black',lw=0.2)\nfig.lines.extend([l1])\n\nax.tick_params(axis=u'both', which=u'both',length=0)\n\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:09.563050Z","iopub.execute_input":"2022-11-10T14:29:09.563497Z","iopub.status.idle":"2022-11-10T14:29:10.000342Z","shell.execute_reply.started":"2022-11-10T14:29:09.563440Z","shell.execute_reply":"2022-11-10T14:29:09.999071Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#https://www.kaggle.com/code/joshuaswords/netflix-data-visualization\ndata = race_table['race_type'].value_counts().sort_values()/20\ndata.index = data.index.astype(str)\ndata = data[data>0.1]\n# Plot\n\ncolor_map =  ['wheat']*(data.size - 3) + ['lightseagreen' ]*3\n\n\nfig, ax = plt.subplots(1,1, figsize=(15, 7), dpi=120)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\nax.set_facecolor(background_color) \n\n\nax.barh(y = data.index.values, width = data.values, height=0.8, color=color_map, alpha=0.8)\nax.bar_label(ax.containers[0], labels=data.values, label_type='edge', color='gray', fontsize=10, fontweight=\"bold\")\n\n    \n\nfig.text(0.0, 0.97, '% of races by race type', fontsize=18, fontweight='bold', fontfamily='monospace')\nfig.text(0.0, 0.915, 'The top 3 race types are highlighted', fontsize=15, fontweight='light', fontfamily='monospace')\n\nfig.text(0.95, 0.97, 'Insight', fontsize=18, fontweight='bold', fontfamily='monospace')\n\nfig.text(0.95, 0.4, '''\nClaiming races accounted for more than 23% races.  \nMaiden Special Weight races accounted for \naround 20% races.\n\nMaiden Claiming races are for horses that \nhave never won a race and are eligible to be claimed.\nThis type accounted for 16% races.\n\nStakes race is a horse race in which the prize \noffered is made up at least in part of money \n(such as entry fees) put up by the owners of the \nhorses entered. This type of races accounted for\nabout 13% races.\n'''\n         , fontsize=14, fontweight='light', )\n\nax.grid(axis='y', linestyle='-', alpha=0.4)   \nax.set_xticks([])\n\n\nax.tick_params(axis='both', which='major', labelsize=12)\nax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\nax.spines[['top', 'right']].set_visible(False)\nax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n\nfor s in ['top', 'left', 'right']:\n    ax.spines[s].set_visible(False)\n    \n    \nimport matplotlib.lines as lines\nl1 = lines.Line2D([0.93, 0.93], [0.1, 1.03], transform=fig.transFigure, figure=fig,color='black',lw=0.2)\nfig.lines.extend([l1])\n\nax.tick_params(axis=u'both', which=u'both',length=0)\n\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:10.002235Z","iopub.execute_input":"2022-11-10T14:29:10.002733Z","iopub.status.idle":"2022-11-10T14:29:10.487404Z","shell.execute_reply.started":"2022-11-10T14:29:10.002671Z","shell.execute_reply":"2022-11-10T14:29:10.486074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"datas = [\n    race_table[['race_date', 'race_number']].groupby('race_date').count()['race_number'].value_counts().sort_index(),  \n    start_table[['race_date', 'race_number', 'program_number']].groupby(['race_date', 'race_number',]).count()['program_number'].value_counts().sort_index(), \n]\ncaptions = [\n    'Num of race dates by number of races in the same day',\n    'Num of races by number of horse in a race'\n]\n\n\nfig, axs = plt.subplots(1, 2, figsize=(14, 4.5),gridspec_kw={'width_ratios': [6, 8]}, dpi=90)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\n\n\nfig.text(0.115, 1.1, '''\nTypically there were 8 - 10 races in a race day and 5-10 racehorses in a race. \n''', \n         fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(0.115, .85, '''\n\nThe days that had 5 or less races on the day are outliers.\nThe races that had less than 5 horses or more than 12 horses are outliers.\n\n\n\n''', \n         fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\n    \nfor i, data in enumerate(datas):\n    if data.index.dtype in ['int64', 'int32', 'float64', 'float32']:\n        data.index = data.index.astype(str)\n        \n    rankn_val = data.nlargest(4).min()\n    color_map =  np.array(['lightseagreen' ]*data.size)\n    color_map[data<rankn_val] = 'wheat'\n\n    color_map = list(color_map)\n\n\n    axs[i].bar(data.index.values, data.values, color=color_map, width=.5, alpha=0.8)\n    axs[i].bar_label(axs[i].containers[0], labels=data.values, label_type='edge', fontsize=10, )#fontweight=\"bold\"\n    #axs[i].grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    axs[i].grid(visible=False)\n    axs[i].spines[['top', 'right']].set_visible(False)\n    axs[i].spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n\n    #axs[i].set_ylabel(data.name)\n    axs[i].set_yticks([])\n    axs[i].set_title(captions[i], fontsize=12, loc='left')\n    \n    axs[i].set_facecolor(background_color) \n\n\n\n#     plt.suptitle('')\n\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.3, hspace=None) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:10.488957Z","iopub.execute_input":"2022-11-10T14:29:10.489327Z","iopub.status.idle":"2022-11-10T14:29:10.947953Z","shell.execute_reply.started":"2022-11-10T14:29:10.489295Z","shell.execute_reply":"2022-11-10T14:29:10.946760Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cs = race_table.groupby('course_type')['distance_id'].value_counts().unstack().sort_index().fillna(0).astype(int).T\ncs['Turf'] = cs[['Inner turf','Outer turf','turf']].sum(axis=1)\ncs = cs[['Dirt', 'Turf']].T\ncs.columns = cs.columns.astype(str)\ndirt = cs.loc['Dirt']\nturf = - cs.loc['Turf']\n\n\nfig, ax = plt.subplots(1,1, figsize=(18, 8), dpi=90)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\nax.set_facecolor(background_color) \n\nax.bar(dirt.index, dirt, width=0.5, color='lightseagreen', alpha=0.8, label='Dirt Track')\nax.bar(turf.index, turf, width=0.5, color='salmon', alpha=0.8, label='Turf Track')\n#ax.set_ylim(-35, 50)\n\n# Annotations\nfor i in dirt.index:\n    ax.annotate(f\"{dirt[i]}\", \n                   xy=(i, dirt[i] + 10 ),\n                   va = 'center', ha='center',fontweight='light', \n                   color='teal')   \n\nfor i in turf.index:\n    ax.annotate(f\"{-turf[i]}\", \n                   xy=(i, turf[i] - 10),\n                   va = 'center', ha='center',fontweight='light', \n                   color='tomato')\n    \nfor s in ['top', 'left', 'right', 'bottom']:\n    ax.spines[s].set_visible(False)\n\n#ax.set_xticklabels(cs.columns, fontfamily='serif')\nax.set_yticks([]) \nax.set_xlabel('Distance')\n\nax.legend().set_visible(False)\nfig.text(0.1, 1.06, 'Number of races by distance on Dirt & Turf track', \n          fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(0.1, 0.87, \n'''\nOn Dirt track, 6 and 8 furlongs were the top 2 by number of races; \nOn Turf track, 8.5 and 6 furlongs were the top 2 by number of races;\n\nLong distance (9.5 furlongs and above) were mostly on Turf track. \n\n'''\n\n,  fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\n\nfig.text(0.785,0.924,\"Dirt\", fontweight=\"bold\", fontfamily='monospace', fontsize=15, color='lightseagreen')\nfig.text(0.815,0.924,\"|\", fontweight=\"bold\", fontfamily='monospace', fontsize=15, color='black')\nfig.text(0.825,0.924,\"Turf\", fontweight=\"bold\", fontfamily='monospace', fontsize=15, color='salmon')\n\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:10.949694Z","iopub.execute_input":"2022-11-10T14:29:10.950072Z","iopub.status.idle":"2022-11-10T14:29:11.829581Z","shell.execute_reply.started":"2022-11-10T14:29:10.950039Z","shell.execute_reply":"2022-11-10T14:29:11.828324Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"datas = [\n    race_table[race_table['course_type']=='Dirt']['track_condition'].value_counts().sort_index(),  \n    race_table[~race_table['course_type'].isin(['Dirt', 'Hurdle'])]['track_condition'].value_counts().sort_index(), \n]\n\nfig, axs = plt.subplots(1, 3, figsize=(18, 5) ,sharey=True ,gridspec_kw={'width_ratios': [8,8, 2]}, dpi=100)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\n\nfig.text(0.115, 0.95, '''\nNumber of races by track conditions on Dirt track\n''', \n         fontsize=14, fontweight='bold', fontfamily='monospace')\n\nfig.text(0.485, 0.95, '''\nNumber of races by track conditions on Turf track\n''', \n         fontsize=14, fontweight='bold', fontfamily='monospace')\n\nfig.text(0.855, 1.0, 'Insight', fontsize=18, fontweight='bold', fontfamily='monospace')\n\nfig.text(0.855, 0.4, '''\n\nThe condition of the course the race was run on depended on \nthe course type (Dirt or Turf) and the weather before the race. \n\nHeavy rains can make the track soft while sunny days can \nmake the track firm. \n\nThe track condition for most races were Fast on Dirt track;\nThe track condition for most races were Firm on Turf track.\n\n\n'''\n         , fontsize=14, fontweight='light', )\n    \nfor i, data in enumerate(datas):\n    if data.index.dtype in ['int64', 'int32', 'float64', 'float32']:\n        data.index = data.index.astype(str)\n        \n    rankn_val = data.nlargest(4).min()\n    color_map =  np.array(['lightseagreen' ]*data.size)\n    color_map[data<rankn_val] = 'wheat'\n\n    color_map = list(color_map)\n\n\n    axs[i].bar(data.index.values, data.values, color=color_map, width=.5, alpha=0.8)\n    axs[i].bar_label(axs[i].containers[0], labels=data.values, label_type='edge', fontsize=10, )#fontweight=\"bold\"\n    axs[i].grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    axs[i].spines[['top', 'right']].set_visible(False)\n    axs[i].spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n\n    #axs[i].set_ylabel(data.name)\n    axs[i].set_yticks([])\n    #axs[i].set_title(captions[i], fontsize=12, loc='left')\n    axs[i].set_facecolor(background_color) \n\n\naxs[2].grid(visible=False)\naxs[2].spines[['top', 'right', 'bottom', 'left']].set_visible(False)\naxs[2].set_yticks([])\naxs[2].set_xticks([])\naxs[2].set_facecolor(background_color) \n\nl1 = lines.Line2D([0.835, 0.835], [0.1, 1.19], transform=fig.transFigure, figure=fig,color='black',lw=0.2)\nfig.lines.extend([l1])\n\n\n#plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.3, hspace=None) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:11.835360Z","iopub.execute_input":"2022-11-10T14:29:11.835841Z","iopub.status.idle":"2022-11-10T14:29:12.404117Z","shell.execute_reply.started":"2022-11-10T14:29:11.835802Z","shell.execute_reply":"2022-11-10T14:29:12.403169Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"top6types = race_table['race_type'].value_counts().head(6).index.values\ncs = race_table[race_table['race_type'].isin(top6types)].groupby('race_type')['distance_id'].value_counts().unstack().fillna(0).astype(int).T\ncs.index = cs.index.astype(str)\n\nfig, axs = plt.subplots(3, 2, figsize=(18, 12), sharex=False, sharey=True, dpi=130)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\ni=0\nfor rt in top6types:\n    data = cs[rt]\n    caption=f\"{rt}\"\n    ax = axs[i//2, i%2]\n        \n    rankn_val = data.nlargest(3).min()\n    color_map =  np.array(['lightseagreen' ]*data.size)\n    color_map[data<rankn_val] = 'wheat'\n    color_map = list(color_map)\n\n\n    ax.bar(data.index.values, data.values, color=color_map, width=.5, alpha=0.8)\n    ax.bar_label(ax.containers[0], labels=data.values, fmt='%.0d', label_type='edge', fontsize=10, )#fontweight=\"bold\"\n    ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n\n    #axs[i].set_ylabel(data.name)\n    ax.set_yticks([])\n    ax.set_title(caption, fontsize=12, loc='left')\n    ax.set_facecolor(background_color) \n    \n    i = i + 1\n    \n\n\nfig.text(.012, 1.035, '''\nDoes the distances differ between different type of races? [Top 6 race types by num. of races]\n\n''', fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(0.012, .98, '''\n\nStarter and Waiver races were normally short distance races and mostly within 8 furlongs \nStakes races had almost all distances of races\n\n''', fontfamily='monospace',fontweight='light',fontsize=14,color='#323232', ha='left')\n\n    \nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.2, hspace=0.2) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:12.405546Z","iopub.execute_input":"2022-11-10T14:29:12.405961Z","iopub.status.idle":"2022-11-10T14:29:14.629194Z","shell.execute_reply.started":"2022-11-10T14:29:12.405924Z","shell.execute_reply":"2022-11-10T14:29:14.627919Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"2.2\">2.2 Racing course types - How do they differ from each other</div>\n\n\n[back to top](#toc)\n","metadata":{}},{"cell_type":"code","source":"def plot_track(data, figsize=(14, 8), caption='', groupby='program_number'):\n    plt.figure(figsize=(14, 8), dpi=100, )\n\n    i = 0\n    for pn in data[groupby].unique():\n        plt.scatter('latitude', 'longitude',\n                    data=data[data[groupby]==pn],\n                    s=20, c=colors[i], label='',  marker='o', alpha=0.5) \n        plt.scatter('latitude', 'longitude',\n                        data=data[(data[groupby]==pn) & (data['trakus_index']<5)],\n                        s=300, c=colors[i], label='',  marker='*')    \n        i = i + 1\n        if i >7:\n            break\n\n     \n\n    plt.title(caption,  fontsize=14, loc='left')\n\n    plt.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.1)\n    plt.gca().spines[['top', 'right']].set_visible(False)\n    plt.gca().spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n\n    plt.yticks(fontsize=9, )#rotation=90\n    plt.xticks(fontsize=9, )#rotation=90\n    plt.tight_layout()\n    plt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:14.631468Z","iopub.execute_input":"2022-11-10T14:29:14.631909Z","iopub.status.idle":"2022-11-10T14:29:14.650535Z","shell.execute_reply.started":"2022-11-10T14:29:14.631871Z","shell.execute_reply":"2022-11-10T14:29:14.649036Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#tracking_table = pd.read_csv('/kaggle/input/big-data-derby-2022/nyra_tracking_table.csv')\ntracking_table = pd.read_parquet('/kaggle/input/derby-2022-merge-and-convert-data-to-parquet-file/nyra_2019_complete.parquet')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:14.652341Z","iopub.execute_input":"2022-11-10T14:29:14.652877Z","iopub.status.idle":"2022-11-10T14:29:18.680897Z","shell.execute_reply.started":"2022-11-10T14:29:14.652828Z","shell.execute_reply":"2022-11-10T14:29:18.679824Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# df['race_type'] = df['race_type'].map(race_type_dict)\n# df['track_id'] = df['track_id'].map(track_id_dict)\ntracking_table['course_type'] = tracking_table['course_type'].map(course_type_dict)\n\n# df['track_condition']=df['track_condition'].apply(lambda x:x.replace(\" \", ''))\n# df['track_condition'] = df['track_condition'].map(track_condition_dict)\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:18.681902Z","iopub.execute_input":"2022-11-10T14:29:18.682224Z","iopub.status.idle":"2022-11-10T14:29:19.114577Z","shell.execute_reply.started":"2022-11-10T14:29:18.682195Z","shell.execute_reply":"2022-11-10T14:29:19.113386Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"colors = ['lightseagreen', 'salmon', 'lightskyblue', 'mediumseagreen', 'sandybrown', 'lightslategray', 'wheat', 'crimson']\nmcolors = ['teal', 'tomato', 'skyblue', 'mediumseagreen', 'peru', 'slategray', 'tan',  'firebrick']","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:19.116435Z","iopub.execute_input":"2022-11-10T14:29:19.117053Z","iopub.status.idle":"2022-11-10T14:29:19.122586Z","shell.execute_reply.started":"2022-11-10T14:29:19.117015Z","shell.execute_reply":"2022-11-10T14:29:19.121441Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#https://www.kaggle.com/code/iamleonie/big-data-derby-step-by-step-analysis\ncolor_dict = {'Dirt' : 'lightseagreen',\n             'Inner turf' : 'lightskyblue',\n             'Outer turf' : 'salmon',\n             'turf' : 'mediumseagreen',\n             'Hurdle' : 'wheat'}\n\n# fig, ax = plt.subplots(1, 3, figsize=(18, 6.5))\nfig, ax = plt.subplots(3, 1, figsize=(12, 3*6.5), dpi=100)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\n\ni = 0\nfor track_id in ['AQU', 'BEL', 'SAR']:\n    \n    sns.scatterplot(data = tracking_table[(tracking_table[\"track_id\"] == track_id) & (tracking_table[\"program_number\"] == '1  ')], \n                    x = \"longitude\", y = \"latitude\", \n                    hue = \"course_type\", \n                    marker='o',ax=ax[i],\n                   palette=color_dict, )\n\n\n    \n    ax[i].grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax[i].spines[['top', 'right']].set_visible(False)\n    ax[i].spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n\n    ax[i].set_title(track_id_dict[track_id],  loc='center',fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232',)\n    ax[i].set_facecolor(background_color)\n    \n    \n    \n    i = i + 1\n\nplt.tight_layout()\nplt.legend()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.3, hspace=None) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:19.123913Z","iopub.execute_input":"2022-11-10T14:29:19.124952Z","iopub.status.idle":"2022-11-10T14:29:42.285906Z","shell.execute_reply.started":"2022-11-10T14:29:19.124912Z","shell.execute_reply":"2022-11-10T14:29:42.284348Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"2.3\">2.3 Dates and time: When did the races take place</div>\n\n[back to top](#toc)\n","metadata":{}},{"cell_type":"code","source":"def post_time_(x):\n    v = '12:00'\n    if (x is None)|(x is np.nan):\n        return v\n    else:\n        x = str(x)\n        x1_ = int(x[:-2])\n        x2_ = int(x[-2:])\n        if x1_<10:\n            x1_ = x1_ + 12\n        if x2_<22:\n            v = f'{x1_}:00'\n        elif x2_< 48: \n            v = f'{x1_}:30'\n        else: \n            v = f'{x1_+1}:00'\n    return v","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:42.287571Z","iopub.execute_input":"2022-11-10T14:29:42.288485Z","iopub.status.idle":"2022-11-10T14:29:42.296246Z","shell.execute_reply.started":"2022-11-10T14:29:42.288440Z","shell.execute_reply":"2022-11-10T14:29:42.294739Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"race_date = pd.to_datetime(race_table['race_date'])\n\nrd = pd.DataFrame(data={'weekday': race_date.dt.weekday, \n                        'month_name':race_date.dt.strftime(\"%b\"),\n                        'month':race_date.dt.month,\n                        'week': race_date.dt.isocalendar().week,\n                        'day_name': race_date.dt.day_name(),\n                        'race_number': race_table['race_number'], \n                        'post_time': race_table['post_time'].apply(post_time_),\n                        'track': race_table['track_id'] ,\n                       }\n                 )","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:42.297626Z","iopub.execute_input":"2022-11-10T14:29:42.298242Z","iopub.status.idle":"2022-11-10T14:29:42.346801Z","shell.execute_reply.started":"2022-11-10T14:29:42.298201Z","shell.execute_reply":"2022-11-10T14:29:42.345744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#-----data-------------------------------------\ncs = pd.pivot_table(rd, index=['track'], columns=['month'], values='day_name', aggfunc=np.size)\n\nmnth_map = rd[['month', 'month_name']].drop_duplicates().sort_values(by='month').set_index(keys='month').to_dict()['month_name']\n\ncs.columns = [mnth_map[a] for a in cs.columns]\n#cs.index = [day_map[a] for a in cs.index]\ncs.index.name=''\n\n\n#------plot-----------------------------------------------------\nfig, ax = plt.subplots(1, 1, figsize=(10, 4), dpi=80)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\nax.set_facecolor(background_color)\n\nmask = np.zeros_like(cs, dtype=bool)\n#mask = np.triu(np.ones_like(cs, dtype=bool)) #uncomment if only show under the diagnoal line\n\nvmax = np.round(np.nanmax(cs.where(~mask)) - 0.05, 2)\nvmin = np.round(np.nanmin(cs.where(~mask)) + 0.05, 2)\n\n\n# Specify kwargs for the heatmap\nkwargs = {\n    \"mask\": mask,\n    \"cmap\": \"BrBG\",\n    \"annot\": True,\n    \"vmax\": vmax,\n    \"vmin\": vmin,\n    \"square\": True,\n    \"linewidths\": 1.5,\n    \"annot_kws\": {\"fontsize\": 12},\n    \"cbar\":False, \n    #\"cbar_kws\": {\"shrink\": 0.95, \"aspect\": 30},\n}\n\n# Draw heatmap with mask and default settings\nsns.heatmap(cs, center=0, fmt=\".0f\",ax=ax, **kwargs)\n# sns.heatmap(cs, xticklabels=cs.columns, yticklabels=cs.index, cmap='RdYlGn', square=True, linewidth=2.5,cbar=False,\n#             center=0, annot=True,  fmt='.0f', \n#             ax=ax,annot_kws={\"fontsize\":12})#YlGnBu#RdYlGn\n\n\nax.spines['top'].set_visible(True)\n\nfig.text(.012, 1.01, 'Which months did races take place on each track?', \n         fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(0.012, 0.85, '''\nAqueduct: races took place from Nov to Apr; \nBelmont: races in May/Jun/Sep/Oct, and a few in Apr and and Jul. \nSaratoga: races only from Jul to Sep.''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\nax.set_yticklabels(ax.get_yticklabels(), rotation = 0, fontsize=12)\nax.set_xticklabels(ax.get_xticklabels(), rotation=0, fontsize=12)#fontfamily='serif', \n\nax.set_ylabel('')    \nax.set_xlabel('')\nax.tick_params(axis=u'both', which=u'both',length=0)\n\n# plt.xticks(fontsize=10)\n# plt.yticks(fontsize=10)\n\nplt.tight_layout()\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:42.348439Z","iopub.execute_input":"2022-11-10T14:29:42.348846Z","iopub.status.idle":"2022-11-10T14:29:42.741054Z","shell.execute_reply.started":"2022-11-10T14:29:42.348812Z","shell.execute_reply":"2022-11-10T14:29:42.739766Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#-----data-------------------------------------\ncs = pd.pivot_table(rd, index=['weekday'], columns=['month'], values='day_name', aggfunc=np.size)\n\nmnth_map = rd[['month', 'month_name']].drop_duplicates().sort_values(by='month').set_index(keys='month').to_dict()['month_name']\nday_map = rd[['weekday', 'day_name']].drop_duplicates().sort_values(by='weekday').set_index(keys='weekday').to_dict()['day_name']\n\ncs.columns = [mnth_map[a] for a in cs.columns]\ncs.index = [day_map[a] for a in cs.index]\n\n#------plot-----------------------------------------------------\nfig, ax = plt.subplots(1, 1, figsize=(12, 10), dpi=80)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\nax.set_facecolor(background_color)\n\n\nmask = np.zeros_like(cs, dtype=bool)\n#mask = np.triu(np.ones_like(cs, dtype=bool)) #uncomment if only show under the diagnoal line\n\nvmax = np.round(np.nanmax(cs.where(~mask)) - 0.05, 2)\nvmin = np.round(np.nanmin(cs.where(~mask)) + 0.05, 2)\n\n\n# Specify kwargs for the heatmap\nkwargs = {\n    \"mask\": mask,\n    \"cmap\": \"BrBG\",\n    \"annot\": True,\n    \"vmax\": vmax,\n    \"vmin\": vmin,\n    \"square\": True,\n    \"linewidths\": 1.5,\n    \"annot_kws\": {\"fontsize\": 12},\n    \"cbar\":False, \n    #\"cbar_kws\": {\"shrink\": 0.95, \"aspect\": 30},\n}\n\n# Draw heatmap with mask and default settings\nsns.heatmap(cs, center=0, fmt=\".0f\",ax=ax, **kwargs)\n# sns.heatmap(cs, xticklabels=cs.columns, yticklabels=cs.index, cmap='RdYlGn', square=True, linewidth=2.5,cbar=False,\n#             center=0, annot=True,  fmt='.0f', \n#             ax=ax,annot_kws={\"fontsize\":12})#YlGnBu#RdYlGn\n\n\nax.spines['top'].set_visible(True)\n\nfig.text(.012, .965, 'What day in the week did races take place?',\n         fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(0.012, 0.8, '''\nThroughout the year, most horse races took place on Friday and the whole weekend. \nThere were a few races on Mondays and Tuesdays, and those days were holidays. \n\nFor example, the races on Tuesdays were at track `Aqueduct` on Jan 1st (New Year) and \nDec 31st (Last day in the Year). \nFrom Jun to Nov, there were also races on Wednesdays.\n\n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\n\nax.set_yticklabels(ax.get_yticklabels(), rotation = 0, fontsize=12)\nax.set_xticklabels(ax.get_xticklabels(), rotation=0, fontsize=12)#fontfamily='serif', \n\nax.set_ylabel('')    \nax.set_xlabel('')\nax.tick_params(axis=u'both', which=u'both',length=0)\n\n# plt.xticks(fontsize=10)\n# plt.yticks(fontsize=10)\n\nplt.tight_layout()\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:42.743330Z","iopub.execute_input":"2022-11-10T14:29:42.743741Z","iopub.status.idle":"2022-11-10T14:29:43.428661Z","shell.execute_reply.started":"2022-11-10T14:29:42.743673Z","shell.execute_reply":"2022-11-10T14:29:43.426888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#-----data-------------------------------------\ncs = pd.pivot_table(rd, index=['weekday'], columns=['post_time'], values='day_name', aggfunc=np.size)\nday_map = rd[['weekday', 'day_name']].drop_duplicates().sort_values(by='weekday').set_index(keys='weekday').to_dict()['day_name']\ncs.columns.name=''\ncs.index = [day_map[a] for a in cs.index]\n\n#------plot-----------------------------------------------------\nfig, ax = plt.subplots(1, 1, figsize=(15, 7), dpi=90)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\nax.set_facecolor(background_color)\n\n\nmask = np.zeros_like(cs, dtype=bool)\n#mask = np.triu(np.ones_like(cs, dtype=bool)) #uncomment if only show under the diagnoal line\n\nvmax = np.round(np.nanmax(cs.where(~mask)) - 0.05, 2)\nvmin = np.round(np.nanmin(cs.where(~mask)) + 0.05, 2)\n\n\n# Specify kwargs for the heatmap\nkwargs = {\n    \"mask\": mask,\n    \"cmap\": \"BrBG\",\n    \"annot\": True,\n    \"vmax\": vmax,\n    \"vmin\": vmin,\n    \"square\": True,\n    \"linewidths\": 1.5,\n    \"annot_kws\": {\"fontsize\": 12},\n    \"cbar\":False, \n    #\"cbar_kws\": {\"shrink\": 0.95, \"aspect\": 30},\n}\n\n# Draw heatmap with mask and default settings\nsns.heatmap(cs, center=0, fmt=\".0f\",ax=ax, **kwargs)\n# sns.heatmap(cs, xticklabels=cs.columns, yticklabels=cs.index, cmap='RdYlGn', square=True, linewidth=2.5,cbar=False,\n#             center=0, annot=True,  fmt='.0f', \n#             ax=ax,annot_kws={\"fontsize\":12})#YlGnBu#RdYlGn\n\n\nax.spines['top'].set_visible(True)\n\nfig.text(.012, 1.02, 'What time in the day did races take place?', \n         fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(0.012, 0.82, '''\n\nThe majority of races took place between 1pm and 6pm; only few races started after 6PM. \n\nThe 1st race typically started before 1:30PM.\n\n\n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\n\nax.set_yticklabels(ax.get_yticklabels(), rotation = 0, fontsize=12)\nax.set_xticklabels(ax.get_xticklabels(), rotation=0, fontsize=12)#fontfamily='serif', \n\nax.set_ylabel('')    \nax.set_xlabel('')\nax.tick_params(axis=u'both', which=u'both',length=0)\n\n# plt.xticks(fontsize=10)\n# plt.yticks(fontsize=10)\n\nplt.tight_layout()\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:43.430910Z","iopub.execute_input":"2022-11-10T14:29:43.432408Z","iopub.status.idle":"2022-11-10T14:29:44.278430Z","shell.execute_reply.started":"2022-11-10T14:29:43.432356Z","shell.execute_reply":"2022-11-10T14:29:44.277349Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n<div style='background-color: teal; color: white; font-family: Helvetica; font-size: 25px; padding: 6px 12px; margin-bottom: 5px;' id=\"3\">3. Who: the jockeys</div>\n\n\n\n[back to top](#toc)\n","metadata":{}},{"cell_type":"markdown","source":"\n<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"3.1\">3.1 Win win win!</div>\n\n\n[back to top](#toc)\n\n\n<div style='color: teal; font-family: Helvetica; font-size: 16px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px; ' >Who won most races in 2019? Who finish in top 3 position in most races? </div>\n\n<div style='font-family: Helvetica; font-size: 14px; font-weight:normal; padding: 6px 12px; margin-bottom: 5px; '>\n\nWhile there were 178 jockeys participated in the 2000 races in 2019, only 43 of them raced in 30 or more races. And the number goes down to 21 (the number of jockeys) who raced in 200 or more races.\n<br><br>\n\nAmong the 2000 races in 2019, Manuel Franco participated in 1274 (63.7%) races, and won 214 of them. This means among all the races took place in 2019, more than one in ten races had the 1st place taken by him! He had a win rate of 17% and place rate around 49%.\n<br><br>\n\nBut was he the one who finished in 1st, 2nd, or 3rd position in most races? The answer is YES!\n<br><br>\n\nManuel Franco finished in 2nd position in 214 races and in 3rd position in 192 races. In total, he finished in the top 3 positions in 620 races, which is 31% of all races!\n<br>\nThe stunning numbers undoubtedly prove Manuel Franco was the best jockey in 2019. Who is the 2nd best?\n<br><br>\n\nThe answer is Jose Lezcano. he raced in 990 races, won 206 races and had win rate of 20.8%. He finished in top 3 positions in 491 races, which is 49.6% out of all races he participated.               \n\n    \n</div>\n\n\n","metadata":{}},{"cell_type":"code","source":"#https://blog.hubspot.com/website/how-to-bold-in-html#:~:text=How%20to%20Italicize%20Text%20in,property%20set%20to%20%E2%80%9Citalic.%E2%80%9D\ncs=pd.pivot_table(start_table[start_table['position_at_finish']<=3], values='race_date', \n               index=['jockey'], columns=['position_at_finish'], aggfunc=np.size)\ncs['Total'] = cs.sum(axis=1)\ncs.sort_values(by='Total', ascending=False, inplace=True)\ncs = cs.head(30)\ntop30jockeys = cs.index.values.tolist()\ncs.columns.name=''\n#cs.sort_values(by='sum', ascending=True, inplace=True)\ncs.columns=['1st Place', '2nd Place', '3rd Place', 'Total']\ncs.index = [f'{i+1}: {val}' for i, val in enumerate(cs.index.values)]\n\n#https://stackoverflow.com/questions/53142921/table-with-and-link-format-for-pandas-style-formatting\ncs.iloc[:30].style.set_table_attributes('style=\"width: 100%;\"')\\\n.set_table_styles(\n    [\n      {\"selector\": \"td, th\", \"props\": [(\"border\", \"2px solid white !important\")]},\n      {'selector': 'tr:hover','props': 'background-color: wheat; font-size: 1em;'},\n      {'selector': 'caption','props': [('text-align', 'left'),  ('color', 'black')]},#('font-size', '18px'),\n    ]\n).set_caption('''\n<h3>Who won most races in 2019? Who finish in top 3 position  in most races? [Top 30]</h3> \n\n<i>Note: Top 30 jockeys are jockeys who ranked in top 30 by number of races finished in 1st, 2nd, or 3rd position.</i>\n\n            ''')\\\n.format(precision=0, na_rep='', thousands=\", \",)\\\n.bar(subset=['1st Place'], color='teal')\\\n.bar(subset=['2nd Place'], color='lightseagreen')\\\n.bar(subset=['3rd Place'], color='powderblue')\\\n.bar(subset=['Total'], color='salmon')","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:44.279595Z","iopub.execute_input":"2022-11-10T14:29:44.281362Z","iopub.status.idle":"2022-11-10T14:29:44.582033Z","shell.execute_reply.started":"2022-11-10T14:29:44.280728Z","shell.execute_reply":"2022-11-10T14:29:44.580578Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data = cs.iloc[:30][::-1]\n\nfig, axs = plt.subplots(1,4, figsize=(18, 16), sharey=True, sharex=False, dpi=100)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\ncolors = ['teal', 'lightseagreen', 'powderblue', 'salmon']\nfor i, col in enumerate(['1st Place', '2nd Place', '3rd Place', 'Total']):\n    ax = axs[i]\n    ax.barh(y = data.index.values, width = data[col].values, height=0.8, color=colors[i], alpha=0.8)\n    ax.bar_label(ax.containers[0],  fmt='%.0f', label_type='edge', color='gray', fontsize=10, fontweight=\"bold\")\n    \n    ax.grid(axis='y', linestyle='-', alpha=0.4)   \n    ax.set_xticks([])\n    #ax.set_title(col)\n\n\n    ax.tick_params(axis='both', which='major', labelsize=12)\n    ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    \n    ax.text(0, 30, f'''{col}''', fontweight='bold', fontfamily='monospace', fontsize=13,color=colors[i], ha='left')  \n    ax.set_facecolor(background_color)\n    \n\nfig.text(.012, 1., '''\nWho won most races in 2019? Who finish in top 3 position  in most races? [Top 30]\n''', fontweight='bold', fontfamily='monospace', fontsize=15,ha='left')  \n\n\nfig.text(.012, .985, '''\nNote: Top 30 jockeys are jockeys who ranked in top 30 by number of races finished in 1st, 2nd, or 3rd position.\n''',fontfamily='monospace',fontweight='light',fontsize=12,style='italic',color='#323232', ha='left')  \n\n  \nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.1, hspace=None) # useful for adjusting space between subplots\nplt.show() ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:44.583589Z","iopub.execute_input":"2022-11-10T14:29:44.583973Z","iopub.status.idle":"2022-11-10T14:29:46.602260Z","shell.execute_reply.started":"2022-11-10T14:29:44.583939Z","shell.execute_reply":"2022-11-10T14:29:46.600965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style='color: teal; font-family: Helvetica; font-size: 16px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px; ' >Win rates and Place rates of top 30 jockeys</div>\n\n<div style='font-family: Helvetica; font-size: 14px; font-weight:normal; padding: 6px 12px; margin-bottom: 5px; '>\n\n\nManuel Franco won 17% of races he ran and had 49% place rate; There were 5 jockeys who had a higher place rate than Franco.\n<br><br>\n\nJavier Castellano had the highest place rate and win rate. Both Javier Castellano and Jose Lezcano had a win rate over 21%.\n\n</div>\n\n\n\n\n\n","metadata":{}},{"cell_type":"code","source":"cs=pd.pivot_table(start_table[start_table['position_at_finish']<=3], values='race_date', \n               index=['jockey'], columns=['position_at_finish'], aggfunc=np.size)\ncs['sum'] = cs.sum(axis=1)\ncs.sort_values(by='sum', ascending=False, inplace=True)\ncs = cs.head(30)\n#cs.sort_values(by='sum', ascending=True, inplace=True)\ncs0=pd.pivot_table(start_table, values='race_date', \n               index=['jockey'],aggfunc=np.size)\ncs0.columns=['total']\ncs0 = cs.merge(cs0, left_index=True, right_index=True, how='inner')\nfor i in [1, 2, 3, 'sum']:\n    cs0[i] = (100*cs0[i]/cs0['total'])\n    \ncs0 = cs0[[1, 2, 3, 'sum']]\ncs0.columns=['1st Place', '2nd Place', '3rd Place', 'Total']\ncs0.index = [f'{i+1}: {val}' for i, val in enumerate(cs0.index.values)]","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:46.604813Z","iopub.execute_input":"2022-11-10T14:29:46.605411Z","iopub.status.idle":"2022-11-10T14:29:46.654043Z","shell.execute_reply.started":"2022-11-10T14:29:46.605309Z","shell.execute_reply":"2022-11-10T14:29:46.652761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data = cs0.iloc[:30][::-1]\n\nfig, axs = plt.subplots(1,4, figsize=(18, 16), sharey=True, sharex=False, dpi=100)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\ncolors = ['teal', 'lightseagreen', 'powderblue', 'salmon']\nfor i, col in enumerate(['1st Place', '2nd Place', '3rd Place', 'Total']):\n    ax = axs[i]\n    ax.barh(y = data.index.values, width = data[col].values, height=0.8, color=colors[i], alpha=0.8)\n    ax.bar_label(ax.containers[0],  fmt='%.1f%%', label_type='edge', color='gray', fontsize=10, fontweight=\"bold\")\n    \n    ax.grid(axis='y', linestyle='-', alpha=0.4)   \n    ax.set_xticks([])\n    #ax.set_title(col)\n\n\n    ax.tick_params(axis='both', which='major', labelsize=12)\n    ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    \n    ax.text(0, 30, f'''{col}''', fontweight='bold', fontfamily='monospace', fontsize=13,color=colors[i], ha='left')  \n    ax.set_facecolor(background_color)  \n    \n\nfig.text(.012, 1.05, '''\nWin rates and Place rates of top 30 jockeys\n''', fontweight='bold', fontfamily='monospace', fontsize=15,ha='left')  \n\n\nfig.text(.012, .985, '''\nNote: In the following analysis, we define `win rate` as percentage of races a jockey finished in 1st position out of all the races \nhe participated in. And we define `place rate` as percentage of races a jockey finished in 1st, 2nd, or 3rd position out of all the \nraces he perticipated in.\n\n''',fontfamily='monospace',fontweight='light',fontsize=12,style='italic',color='#323232', ha='left')  \n\n  \nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.1, hspace=None) # useful for adjusting space between subplots\nplt.show() ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:46.655342Z","iopub.execute_input":"2022-11-10T14:29:46.655718Z","iopub.status.idle":"2022-11-10T14:29:48.788316Z","shell.execute_reply.started":"2022-11-10T14:29:46.655664Z","shell.execute_reply":"2022-11-10T14:29:48.786788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style='color: teal; font-family: Helvetica; font-size: 16px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px; ' >Did jockeys have better luck on certain tracks? Win rates by track of top 30 jockeys.</div>\n\n<div style='font-family: Helvetica; font-size: 14px; font-weight:normal; padding: 6px 12px; margin-bottom: 5px; '>\n\nManuel Franco had an overall win rate around 17%, but his win rate at Aqueduct was over 22%. His performance on Saratoga dragged the overall rate down.\n<br><br>\n\nJavier Castellano had the highest win rate. But his performances on 3 tracks were almost the same.\n<br><br>\n\nSo it seems, some jockeys had their lucks on one track but not another.\n\n</div>","metadata":{}},{"cell_type":"code","source":"cs=pd.pivot_table(start_table[start_table['position_at_finish']<=1], values='race_date', \n               index=['jockey'], columns=['track_id'], aggfunc=np.size)\ncs['sum'] = cs.sum(axis=1)\ncs.sort_values(by='sum', ascending=False, inplace=True)\ncs = cs.merge(pd.DataFrame(index=top30jockeys), left_index=True, right_index=True, how='right')\n#cs.sort_values(by='sum', ascending=True, inplace=True)\ncs0=pd.pivot_table(start_table, values='race_date', \n               index=['jockey'],columns=['track_id'], aggfunc=np.size)\ncs0['sum'] = cs0.sum(axis=1)\ncols = cs.columns.tolist()\n\ncs0 = cs.merge(cs0, left_index=True, right_index=True, how='inner')\nfor c in cols:\n    cs0[f'{c}_x'] = (100*cs0[f'{c}_x']/cs0[f'{c}_y'])\n    cs0.loc[cs0[f'{c}_y']<30, f'{c}_x']=np.nan\n\n    \ncs0 = cs0.iloc[:, :4]\ncols = cols[:-1] + ['Total']\ncs0.columns=cols\n\ncs0.index = [f'{i+1}: {val}' for i, val in enumerate(cs0.index.values)]\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:48.791157Z","iopub.execute_input":"2022-11-10T14:29:48.791589Z","iopub.status.idle":"2022-11-10T14:29:48.851036Z","shell.execute_reply.started":"2022-11-10T14:29:48.791555Z","shell.execute_reply":"2022-11-10T14:29:48.849371Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data = cs0.iloc[:30][::-1]\n\nfig, axs = plt.subplots(1,4, figsize=(18, 16), sharey=True, sharex=False, dpi=100)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\ncolors = ['teal', 'lightseagreen', 'powderblue', 'salmon']\nfor i, col in enumerate(['Aqueduct', 'Belmont', 'Saratoga', 'Total']):\n    ax = axs[i]\n    ax.barh(y = data.index.values, width = data[col].values, height=0.8, color=colors[i], alpha=0.8)\n    ax.bar_label(ax.containers[0],  fmt='%.1f%%', label_type='edge', color='gray', fontsize=10, fontweight=\"bold\")\n    \n    ax.grid(axis='y', linestyle='-', alpha=0.4)   \n    ax.set_xticks([])\n    #ax.set_title(col)\n\n\n    ax.tick_params(axis='both', which='major', labelsize=12)\n    ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    \n    ax.text(0, 30, f'''{col}''', fontweight='bold', fontfamily='monospace', fontsize=13,color=colors[i], ha='left')   \n    ax.set_facecolor(background_color) \n    \n\nfig.text(.012, 1., '''\nDid jockeys have better luck on certain tracks? Win rates by track of top 30 jockeys\n''', fontweight='bold', fontfamily='monospace', fontsize=15,ha='left')  \n\n\nfig.text(.012, .965, '''\nthe win rate is set as 0 if a jockey's total number of races on the corresponding track is less than 30\n\n''',fontfamily='monospace',fontweight='light',fontsize=12,style='italic',color='#323232', ha='left')  \n\n  \nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.1, hspace=None) # useful for adjusting space between subplots\nplt.show() ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:48.853146Z","iopub.execute_input":"2022-11-10T14:29:48.853521Z","iopub.status.idle":"2022-11-10T14:29:51.122658Z","shell.execute_reply.started":"2022-11-10T14:29:48.853488Z","shell.execute_reply":"2022-11-10T14:29:51.121289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cs=pd.pivot_table(start_table[start_table['position_at_finish']<=3], values='race_date', \n               index=['jockey'], columns=['track_id'], aggfunc=np.size)\ncs['sum'] = cs.sum(axis=1)\ncs = cs.merge(pd.DataFrame(index=top30jockeys), left_index=True, right_index=True, how='right')\n#cs.sort_values(by='sum', ascending=True, inplace=True)\ncs0=pd.pivot_table(start_table, values='race_date', \n               index=['jockey'],columns=['track_id'], aggfunc=np.size)\ncs0['sum'] = cs0.sum(axis=1)\ncols = cs.columns.tolist()\n\ncs0 = cs.merge(cs0, left_index=True, right_index=True, how='inner')\nfor c in cols:\n    cs0[f'{c}_x'] = (100*cs0[f'{c}_x']/cs0[f'{c}_y'])\n    cs0.loc[cs0[f'{c}_y']<30, f'{c}_x']=np.nan\n\n    \ncs0 = cs0.iloc[:, :4]\ncols = cols[:-1] + ['Total']\ncs0.columns=cols\n\ncs0.index = [f'{i+1}: {val}' for i, val in enumerate(cs0.index.values)]\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:51.130147Z","iopub.execute_input":"2022-11-10T14:29:51.130572Z","iopub.status.idle":"2022-11-10T14:29:51.184550Z","shell.execute_reply.started":"2022-11-10T14:29:51.130531Z","shell.execute_reply":"2022-11-10T14:29:51.183546Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data = cs0.iloc[:30][::-1]\n\nfig, axs = plt.subplots(1,4, figsize=(18, 16), sharey=True, sharex=False, dpi=100)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\n\ncolors = ['teal', 'lightseagreen', 'powderblue', 'salmon']\nfor i, col in enumerate(['Aqueduct', 'Belmont', 'Saratoga', 'Total']):\n    ax = axs[i]\n    ax.barh(y = data.index.values, width = data[col].values, height=0.8, color=colors[i], alpha=0.8)\n    ax.bar_label(ax.containers[0],  fmt='%.1f%%', label_type='edge', color='gray', fontsize=10, fontweight=\"bold\")\n    \n    ax.grid(axis='y', linestyle='-', alpha=0.4)   \n    ax.set_xticks([])\n    #ax.set_title(col)\n\n\n    ax.tick_params(axis='both', which='major', labelsize=12)\n    ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    \n    ax.text(0, 30, f'''{col}''', fontweight='bold', fontfamily='monospace', fontsize=13,color=colors[i], ha='left')   \n    ax.set_facecolor(background_color) \n    \n\nfig.text(.012, 1., '''\nDid jockeys have better luck on certain tracks? Place rates by track of top 30 jockeys\n''', fontweight='bold', fontfamily='monospace', fontsize=15,ha='left')  \n\n\nfig.text(.012, .965, '''\nthe place rate is set as 0 if a jockey's total number of races on the corresponding track is less than 30 \n\n''',fontfamily='monospace',fontweight='light',fontsize=12,style='italic',color='#323232', ha='left')  \n\n  \nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.1, hspace=None) # useful for adjusting space between subplots\nplt.show() ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:51.185746Z","iopub.execute_input":"2022-11-10T14:29:51.186395Z","iopub.status.idle":"2022-11-10T14:29:53.300553Z","shell.execute_reply.started":"2022-11-10T14:29:51.186358Z","shell.execute_reply":"2022-11-10T14:29:53.299084Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style='color: teal; font-family: Helvetica; font-size: 16px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px; ' >Did jockeys do better with certain distances? (top 20 jockeys)</div>\n\n<div style='font-family: Helvetica; font-size: 14px; font-weight:normal; padding: 6px 12px; margin-bottom: 5px; '>\n\n\n\n</div>\n","metadata":{}},{"cell_type":"code","source":"start_table['win'] = (start_table['position_at_finish']<2).astype(int)\nstart_table['place'] = (start_table['position_at_finish']<4).astype(int)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:53.302147Z","iopub.execute_input":"2022-11-10T14:29:53.303076Z","iopub.status.idle":"2022-11-10T14:29:53.311296Z","shell.execute_reply.started":"2022-11-10T14:29:53.303038Z","shell.execute_reply":"2022-11-10T14:29:53.310050Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cs0 = pd.pivot_table(start_table, index = ['jockey'], columns = [ 'distance_id'], values=['win'], aggfunc = np.mean)\ncs0.columns=[b for _, b in cs0.columns]\nfor cc in cs0.columns:\n    cs0[cc] = cs0[cc].values*100\n\ncs0 = cs0.merge(pd.DataFrame(index=top30jockeys), left_index=True, right_index=True, how='right')\ncs0 = cs0[[550, 600, 650, 700, 800, 850, 900]]\ncs0[cs<30]=np.nan\n\ncs1 = pd.pivot_table(start_table, index = ['jockey'], columns = [ 'distance_id'], values=['place'], aggfunc = np.mean)\ncs1.columns=[b for _, b in cs1.columns]\nfor cc in cs1.columns:\n    cs1[cc] = cs1[cc].values*100\n\ncs1 = cs1.merge(pd.DataFrame(index=top30jockeys), left_index=True, right_index=True, how='right')\ncs1 = cs1[[550, 600, 650, 700, 800, 850, 900]]\ncs1[cs<30]=np.nan","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:53.312875Z","iopub.execute_input":"2022-11-10T14:29:53.313965Z","iopub.status.idle":"2022-11-10T14:29:53.381838Z","shell.execute_reply.started":"2022-11-10T14:29:53.313791Z","shell.execute_reply":"2022-11-10T14:29:53.380729Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"datas = [cs0.head(20), cs1.head(20)]\nlabels=['win rate (%) by distance', 'place rate (%) by distance']\n\nfig, ax = plt.subplots(1, 2, figsize=(18, 12), sharey=True, dpi=100)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\n\ni=0\nfor data in datas:\n    mask = np.zeros_like(data, dtype=bool)\n    #mask = np.triu(np.ones_like(cs, dtype=bool)) #uncomment if only show under the diagnoal line\n\n    vmax = np.round(np.nanmax(data.where(~mask)) - 0.05, 2)\n    vmin = np.round(np.nanmin(data.where(~mask)) + 0.05, 2)\n\n    # Specify kwargs for the heatmap\n    kwargs = {\n        \"mask\": mask,\n        \"cmap\": \"BrBG\",\n        \"annot\": True,\n        \"vmax\": vmax,\n        \"vmin\": vmin,\n        \"linewidths\": 0.5,\n        \"annot_kws\": {\"size\": 10},\n        \"cbar\":False, \n        #\"cbar_kws\": {\"shrink\": 0.95, \"aspect\": 30},\n    }\n\n    # Draw heatmap with mask and default settings\n    sns.heatmap(data, center=0, fmt=\".0f\", **kwargs, ax=ax[i])\n    #ax[i].set_title(f\"{labels[i]}\", fontdict={\"fontsize\": 15,'fontfamily':'monospace','fontweight':'bold','color':'#323232'}, loc='left')\n    ax[i].text(0, -0.8, f\"{labels[i]}\", fontsize=15, fontweight='bold', fontfamily='monospace', color=\"#323232\")\n    ax[i].set_ylabel('')\n    ax[i].tick_params(axis='both', which='major', labelsize=12, labelbottom = False, bottom=False, top = False, labeltop=True)\n    ax[i].set_facecolor(background_color)\n    i=i+1\n\n    \nfig.text(.012, 1.0, '''\nDid jockeys do better with certain distances? [top 20 jockeys]\n''', fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\n\nfig.text(.012, .97, '''\nTop 20 jockeys are jockeys who ranked in top 30 by number of races finished in 1st, 2nd, or 3rd position.\nthe win rate and place rate are set as 0 if a jockey's total number of races on the corresponding distance is less than 30 \n''',fontfamily='monospace',fontweight='light',fontsize=10,style='italic',color='#323232', ha='left')  \n\nfig.text(0.012, .92, '''\n\nJockey Irad Ortiz Jr.'s place rate at 67% in 6.5-furlong races stands out. \n\n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\n    \nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.1, hspace=0.2) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:53.384061Z","iopub.execute_input":"2022-11-10T14:29:53.384432Z","iopub.status.idle":"2022-11-10T14:29:55.546144Z","shell.execute_reply.started":"2022-11-10T14:29:53.384398Z","shell.execute_reply":"2022-11-10T14:29:55.545021Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style='color: teal; font-family: Helvetica; font-size: 16px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px; ' >Who has the highest win rate and place rate? (Top 30 by place rate)</div>\n\n<div style='font-family: Helvetica; font-size: 14px; font-weight:normal; padding: 6px 12px; margin-bottom: 5px; '>\n\nJavier Castellano and Jose Lezcano had a win rate around 21%. Jose Lezcano raced in 990 races, which is nearly half of the 2000 races in 2019. He was also in 2nd place in terms of number of races won by jockeys and number of races finished in 1st, 2nd, and 3rd places.\n<br><br>\n\nFour jockeys had place rate over 50%, and they were Javier Castellano, Irad Ortiz Jr. Joel Rosario, and Jose L. Ortiz. Although Manuel Franco won the highest number of races and had the highest number races in the top 3 positions, his place rate was slightly below 50%.\n<br><br>\n\nJavier Castellano raced in 541 races (i.e. 27% out of 2000 races) and had 55% place rate. Irad Ortiz Jr. raced in over 800 races (i.e. over 40% races) and had a place rate of 54%.\n\n</div>\n\n\n\n\n","metadata":{}},{"cell_type":"code","source":"cs=pd.pivot_table(start_table[start_table['position_at_finish']<=3], values='race_date', \n               index=['jockey'], columns=['position_at_finish'], aggfunc=np.size, fill_value=0)\ncs['sum'] = cs.sum(axis=1)\n\ncs0=pd.pivot_table(start_table, values='race_number', \n               index=['jockey'],aggfunc=np.size)\ncs0.columns=['total']\ncs0 = cs.merge(cs0, left_index=True, right_index=True, how='inner')\nfor i in [1, 2, 3, 'sum']:\n    cs0[i] = (100*cs0[i]/cs0['total']).round(0)\n    \ncs0 = cs0[cs0['total']>=30].sort_values(by='sum', ascending=False)[[1, 2, 3, 'sum']]\ncs0.columns=['1st Place', '2nd Place', '3rd Place', 'Total']   \ncs0.index = [f'{i+1}: {val}' for i, val in enumerate(cs0.index.values)]\n\n#--------------\n\ndata = cs0.iloc[:30][::-1]\n\nfig, axs = plt.subplots(1,4, figsize=(18, 16), sharey=True, sharex=False, dpi=100)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\ncolors = ['teal', 'lightseagreen', 'powderblue', 'salmon']\nfor i, col in enumerate(['1st Place', '2nd Place', '3rd Place', 'Total']  ):\n    ax = axs[i]\n    ax.barh(y = data.index.values, width = data[col].values, height=0.8, color=colors[i], alpha=0.8)\n    ax.bar_label(ax.containers[0],  fmt='%.1f%%', label_type='edge', color='gray', fontsize=10, fontweight=\"bold\")\n    \n    ax.grid(axis='y', linestyle='-', alpha=0.4)   \n    ax.set_xticks([])\n    #ax.set_title(col)\n\n\n    ax.tick_params(axis='both', which='major', labelsize=12)\n    ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    \n    ax.text(0, 30, f'''{col}''', fontweight='bold', fontfamily='monospace', fontsize=13,color=colors[i], ha='left')    \n    ax.set_facecolor(background_color)\n    \n\nfig.text(.012, 1., '''\nWho has the highest win rate and place rate?[Top 30 by place rate]?\n''', fontweight='bold', fontfamily='monospace', fontsize=15,ha='left')  \n\n\nfig.text(.012, .965, '''\nNote: this part of analysis excludes jockeys who ran less than 30 races to make the results statistical meaningful.\n\n''',fontfamily='monospace',fontweight='light',fontsize=12,style='italic',color='#323232', ha='left')  \n\n  \nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.1, hspace=None) # useful for adjusting space between subplots\nplt.show() \n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:55.547736Z","iopub.execute_input":"2022-11-10T14:29:55.548894Z","iopub.status.idle":"2022-11-10T14:29:57.718354Z","shell.execute_reply.started":"2022-11-10T14:29:55.548827Z","shell.execute_reply":"2022-11-10T14:29:57.716500Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"3.2\">3.2 How did jockeys' performance progress over time?</div>\n\n\n\n[back to top](#toc)","metadata":{}},{"cell_type":"code","source":"top10winrates = {}\n\nfor jk in top30jockeys[:10]:\n    cs = start_table[start_table['jockey']==jk].sort_values(by=['race_date', 'race_number'])\n    cs.reset_index(drop=True, inplace=True)\n    cs['win'] = (cs['position_at_finish']<2).astype(int)\n    cs['place'] = (cs['position_at_finish']<4).astype(int)\n    cs['win_cumsum'] = cs['win'].cumsum()\n    cs['place_cumsum'] = cs['place'].cumsum()\n    top10winrates[jk]=cs","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:57.720840Z","iopub.execute_input":"2022-11-10T14:29:57.721308Z","iopub.status.idle":"2022-11-10T14:29:57.796852Z","shell.execute_reply.started":"2022-11-10T14:29:57.721269Z","shell.execute_reply":"2022-11-10T14:29:57.795419Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axs = plt.subplots(5, 2, figsize=(18, 4*5), dpi=130)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\nlabels = ['cumulative wins', 'cumulative places']\ni=0\nfor jk, data in top10winrates.items():\n    data = data[['win_cumsum', 'place_cumsum']]\n    #caption=f\"{jk}'s journey: Num of wins and places over time\" \n    caption=f\"{jk}\"\n    ax = axs[i//2, i%2]\n    \n    ax2 = ax.twinx()\n    ax.set_title(caption, fontsize=13, loc='left')\n    #ax.set_xlabel('time')\n\n    ax.plot(data.index, data.iloc[:, 0], marker='', markerfacecolor='teal', markersize=2, color='lightseagreen', linewidth=2)\n    ax2.plot(data.index, data.iloc[:, 1], marker='', markerfacecolor='tomato', color='salmon', linewidth=2, linestyle='--')\n\n    ax.set_ylabel(labels[0])\n    ax2.set_ylabel(labels[1])\n    ax.legend([labels[0]], loc='upper left')\n    ax2.legend([labels[1]], loc='upper center')\n    ax.yaxis.grid(color='lightgray', linestyle='dashed')\n    \n    i = i + 1\n    \n\n\nfig.text(.012, 1.035, '''\nHow did a jockey's performance progress over time? The journeys of top 10 jockeys.\n''', fontweight='bold', fontfamily='monospace', fontsize=15,ha='left')  \n\nfig.text(0.012, 1., '''\n\nwin: means finish in the 1st position. place: means finish in 1st, 2nd, or 3rd position.\n\n''',ha='left', fontsize=13,) \n\n    \nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.3, hspace=None) # useful for adjusting space between subplots\nplt.show() ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:29:57.798266Z","iopub.execute_input":"2022-11-10T14:29:57.798622Z","iopub.status.idle":"2022-11-10T14:30:01.011493Z","shell.execute_reply.started":"2022-11-10T14:29:57.798592Z","shell.execute_reply":"2022-11-10T14:30:01.009877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"jockeys = ['Manuel Franco', 'Jose Lezcano', 'Javier Castellano', 'Irad Ortiz Jr.']\n\ncs_ = start_table[['race_date', 'race_number']].drop_duplicates()\n\n\nfor jk in jockeys:\n    cs = start_table[start_table['jockey']==jk].sort_values(by=['race_date', 'race_number'])\n    cs.reset_index(drop=True, inplace=True)\n    cs['win'] = (cs['position_at_finish']<2).astype(int)\n    #cs['place'] = (cs['position_at_finish']<4).astype(int)\n    cs_ = cs_.merge(cs[['race_date', 'race_number', 'win']], on=['race_date', 'race_number'], how='left')\n    cs_.sort_values(by=['race_date', 'race_number'], inplace=True)\n    cs_.rename(columns={'win':jk}, inplace=True)\n    cs_[jk].fillna(0, inplace=True)\n    cs_[jk] = cs_[jk].cumsum()\n    \n    \ncs_.sort_values(by=['race_date', 'race_number'], inplace=True)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:30:01.013388Z","iopub.execute_input":"2022-11-10T14:30:01.013831Z","iopub.status.idle":"2022-11-10T14:30:01.083675Z","shell.execute_reply.started":"2022-11-10T14:30:01.013793Z","shell.execute_reply":"2022-11-10T14:30:01.082409Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cs2=race_table.sort_values(by=['race_date', 'race_number'])[['track_id']]\ncs2.reset_index(drop=True, inplace=True)\ncs2['seq']=cs2.index.values\ncs2['val']=1\ncs2.loc[cs2['track_id']=='Aqueduct', 'val']=1\ncs2.loc[cs2['track_id']=='Belmont', 'val']=2\ncs2.loc[cs2['track_id']=='Saratoga', 'val']=3\n\ncs2 = cs2.pivot(columns='track_id', index='seq', values='val')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:30:01.085530Z","iopub.execute_input":"2022-11-10T14:30:01.086034Z","iopub.status.idle":"2022-11-10T14:30:01.106661Z","shell.execute_reply.started":"2022-11-10T14:30:01.085973Z","shell.execute_reply":"2022-11-10T14:30:01.104898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data = cs_.iloc[:, 2:]\nlabels = cs_.columns[2:]\n\ncolors = ['lightseagreen', 'salmon', 'lightskyblue', 'mediumseagreen', 'sandybrown', 'lightslategray', 'wheat', 'crimson']\nmcolors = ['teal', 'tomato', 'skyblue', 'mediumseagreen', 'peru', 'slategray', 'tan',  'firebrick']\n\n\nfig, axs = plt.subplots(2, 1, figsize=(15, 9), sharex=True, gridspec_kw={'height_ratios': [8, 1]}, dpi=100)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\nax = axs[0]\nfor i in range(data.shape[1]):\n    ax.plot(data.index, data.iloc[:, i], marker='', markerfacecolor=mcolors[i], markersize=2, color=colors[i], linewidth=2, label=labels[i])\n    ax.text(data.iloc[:, i].dropna().size + 1, data.iloc[:, i].dropna().values[-1], labels[i], fontsize=11, color=mcolors[i])\n    ax.yaxis.grid(color='lightgray', linestyle='dashed')\n    #ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    ax.set_ylabel('')\n    ax.set_facecolor(background_color)\n    #ax.set_xticks([])\n    \ndata = cs2\nax = axs[1]\nlabels = data.columns.tolist()\nfor i in range(data.shape[1]):\n    ax.plot(data.index, data.iloc[:, i], marker='', markerfacecolor=mcolors[i], markersize=2, color=colors[i], linewidth=2, label=labels[i])\n    #ax.text(data.iloc[:, i].dropna().size + 1, data.iloc[:, i].dropna().values[-1], labels[i], fontsize=11, color=mcolors[i])\n    ax.yaxis.grid(color='lightgray', linestyle='dashed')\n    ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    \n    ax.set_ylabel('')\n    ax.set_xlabel('race number', fontsize=13,)\n    ax.set_yticks([])\n    ax.set_title('track', fontsize=10, loc='left')\n    ax.legend(loc='upper right')\n    ax.set_facecolor(background_color)\n\n\nfig.text(.012, 1.28, '''\nThe cumulative wins of Manuel Franco, Jose Lezcano, Javier Castellano, Irad Ortiz Jr.\n''', fontweight='bold', fontfamily='monospace', fontsize=15,ha='left')  \n\nfig.text(0.012, 1.0, '''\n Manuel Franco, Jose Lezcano were the top 2 by total number of races finished in top 3 positions.\n Javier Castellano, Irad Ortiz Jr. were the top 2 by place race. \n\n Manuel was unstoppable in the first 500 races. But once Javier and Irad joined the game, Manuel's performance hit a plateau. \n \n Irad and Javier joined the game around the 500th races in the year, and their winnings kept climbing linearly until around the 1500th race.\n \n It seemed that before the 500th and after the 1500th races, when races were mostly on track Aqueduct, Manuel and Jose had their advantages,\n and between the 500th and 1250th race when races were on Belmont track, Irad and Javier had their advantages.  \n\n''',ha='left', fontsize=13,) \n\n    \nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.3, hspace=None) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:55:07.488500Z","iopub.execute_input":"2022-11-10T14:55:07.488889Z","iopub.status.idle":"2022-11-10T14:55:08.075994Z","shell.execute_reply.started":"2022-11-10T14:55:07.488857Z","shell.execute_reply":"2022-11-10T14:55:08.074447Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"start_table['month'] = start_table['race_date'].apply(lambda x: int(x[5:7]))\n\ncs = pd.pivot_table(start_table[(start_table['jockey'].isin(jockeys))], \n               index=['month', 'jockey'], \n               columns=['position_at_finish'], \n               values=['race_number'], aggfunc=np.size)\ncs['runs'] = cs.sum(axis=1)\ncs['wins'] = cs[('race_number',  1)]\ncs['places'] = cs.iloc[:, :3].sum(axis=1)\n\ncs['win_rate'] = 100*cs['wins'] /cs['runs']\ncs['place_rate'] = 100*cs['places']/cs['runs']\ncs = cs[['runs', 'wins', 'places', 'win_rate', 'place_rate']]\ncs = cs.unstack()\n\nfig, axs = plt.subplots(3, 4, figsize=(18, 10), sharey=False, sharex=True, dpi=120)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\ndata = cs[[('win_rate','', a) for a in jockeys]]\ndata.columns=jockeys\nfor i, jk in enumerate(jockeys):\n    ax = axs[0, i]\n    ax.plot(data.index, data[jk], marker='o', markerfacecolor='teal', markersize=10, color='teal', linewidth=2,)\n    ax.text(-0.5, 65, jk, fontsize=15, fontweight='bold', fontfamily='monospace', color=\"teal\")\n    ax.yaxis.set_major_formatter(mtick.PercentFormatter())\n    ax.yaxis.set_major_locator(mtick.MultipleLocator(10))\n \n    ax.yaxis.grid(color='lightgray', linestyle='dashed')\n    #ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    ax.set_ylabel('')\n    ax.set_facecolor(background_color)\n    ax.set_ylim(0, 50)\n    #ax.set_xticks([])\n    ax.fill_between(data.index, 0, [0]*4+[40]*5+[0]*3, color='lightgray', alpha=0.4)\n\ndata = cs[[('place_rate','', a) for a in jockeys]]\ndata.columns=jockeys\nfor i, jk in enumerate(jockeys):\n    ax = axs[1, i]\n    ax.plot(data.index, data[jk], marker='o', markerfacecolor='lightseagreen', markersize=10, color='lightseagreen', linewidth=2,)\n    #ax.text(-0.5, 68.5, jk, fontsize=14, fontweight='bold', fontfamily='monospace', color=\"#323232\")\n    ax.yaxis.set_major_formatter(mtick.PercentFormatter())\n    ax.yaxis.set_major_locator(mtick.MultipleLocator(10))\n \n    ax.yaxis.grid(color='lightgray', linestyle='dashed')\n    #ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    ax.set_ylabel('')\n    ax.set_facecolor(background_color)\n    ax.set_yticks(range(0, 81, 20))   \n    ax.set_ylim(0, 80)\n    #ax.set_xticks([])    \n    ax.fill_between(data.index, 0, [0]*4+[70]*5+[0]*3, color='lightgray', alpha=0.4)\n\ndata = cs[[('runs','', a) for a in jockeys]].fillna(0)\ndata.columns=jockeys\nfor i, jk in enumerate(jockeys):\n    ax = axs[2, i]\n    ax.plot(data.index, data[jk], marker='o', markerfacecolor='peru', markersize=10, color='peru', linewidth=2,)\n    #ax.text(-0.5, 68.5, jk, fontsize=14, fontweight='bold', fontfamily='monospace', color=\"#323232\")\n    #ax.yaxis.set_major_formatter(mtick.PercentFormatter())\n    #ax.yaxis.set_major_locator(mtick.MultipleLocator(10))\n \n    ax.yaxis.grid(color='lightgray', linestyle='dashed')\n    #ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    ax.set_ylabel('')\n    ax.set_facecolor(background_color)\n    ax.set_yticks(range(0, 201, 40))   \n    ax.set_ylim(0, 200)\n    ax.set_xticks(range(0, 13, 1))   \n    ax.set_xlim(0, 13)\n    ax.set_xlabel('Month')\n    ax.fill_between(data.index, 0, [0]*4+[180]*5+[0]*3, color='lightgray', alpha=0.4)\n    \naxs[0, 0].text(-0.5, 55, 'Win rate', fontsize=14, fontweight='bold', fontfamily='monospace', color=\"#323232\")\naxs[1, 0].text(-0.5, 90, 'Place rate', fontsize=14, fontweight='bold', fontfamily='monospace', color=\"#323232\")\naxs[2, 0].text(-0.5, 225, 'Num. of races', fontsize=14, fontweight='bold', fontfamily='monospace', color=\"#323232\")\n\nfig.text(.012, 1.02, '''\nThe win rate, place rate, num. of races of Manuel Franco, Jose Lezcano, Javier Castellano, Irad Ortiz Jr. by month\n''', fontweight='bold', fontfamily='monospace', fontsize=15,ha='left')  \n\nfig.text(.012, .985, '''\nShaded area are months when races were mostly on track Belmont and Saratoga\n''', fontweight='light', fontfamily='monospace', fontsize=13,ha='left')\n\nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.1, hspace=0.4) # useful for adjusting space between subplots\nplt.show() ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:30:01.866273Z","iopub.execute_input":"2022-11-10T14:30:01.866736Z","iopub.status.idle":"2022-11-10T14:30:04.071630Z","shell.execute_reply.started":"2022-11-10T14:30:01.866668Z","shell.execute_reply":"2022-11-10T14:30:04.070777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"3.3\">3.3 Zero-sum game </div>\n\n\n\n[back to top](#toc)","metadata":{}},{"cell_type":"code","source":"cs = start_table[['track_id', 'race_date', 'race_number', 'jockey', 'program_number']]\n#cs.set_index(keys=['track_id', 'race_date', 'jockey'], inplace=True)\npcs = cs.pivot(index=['track_id', 'race_date',  'race_number',], columns='jockey', values='program_number')\n\npcs[pcs>'0']=1\npcs.fillna(0, inplace=True)\ncoocc = pcs.T.dot(pcs)\nnp.fill_diagonal(coocc.values, 0)\n\ncoocc_s = coocc.unstack().sort_values()\ncoocc_s.index.names = ['jockey1', 'jockey2']\ncoocc_s = coocc_s.reset_index()\ncoocc_s.columns = ['jockey1', 'jockey2', 'race_cnt']","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:30:04.073218Z","iopub.execute_input":"2022-11-10T14:30:04.073841Z","iopub.status.idle":"2022-11-10T14:30:04.315414Z","shell.execute_reply.started":"2022-11-10T14:30:04.073803Z","shell.execute_reply":"2022-11-10T14:30:04.314135Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#-----data-------------------------------------\ncs = coocc.loc[top30jockeys[:20], top30jockeys[:20]]\n\n#------plot-----------------------------------------------------\nfig, ax = plt.subplots(1, 1, figsize=(15, 12), dpi=90\n                      )\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\nax.set_facecolor(background_color)\n\nmask = np.zeros_like(cs, dtype=bool)\nmask = np.triu(np.ones_like(cs, dtype=bool)) #uncomment if only show under the diagnoal line\n\nvmax = np.round(np.nanmax(cs.where(~mask)) - 0.05, 2)\nvmin = np.round(np.nanmin(cs.where(~mask)) + 0.05, 2)\n\n\n# Specify kwargs for the heatmap\nkwargs = {\n    \"mask\": mask,\n    \"cmap\": \"BrBG\",\n    \"annot\": True,\n    \"vmax\": vmax,\n    \"vmin\": vmin,\n    \"square\": False,\n    \"linewidths\": 1.5,\n    \"annot_kws\": {\"fontsize\": 12},\n    \"cbar\":False, \n    #\"cbar_kws\": {\"shrink\": 0.95, \"aspect\": 30},\n}\n\n# Draw heatmap with mask and default settings\nsns.heatmap(cs, center=0, fmt=\".0f\",ax=ax, **kwargs)\n# sns.heatmap(cs, xticklabels=cs.columns, yticklabels=cs.index, cmap='RdYlGn', square=True, linewidth=2.5,cbar=False,\n#             center=0, annot=True,  fmt='.0f', \n#             ax=ax,annot_kws={\"fontsize\":12})#YlGnBu#RdYlGn\n\n\nax.spines['top'].set_visible(True)\n\nfig.text(.99, 1.005, 'Who frequently raced in the same races?', \n         fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='right') \n\nfig.text(0.99, 0.75, '''\n\nThis part focuses on the top 20 jockeys by the total number of races finished in the top 3 positions.\n\nManuel Franco and Dylan Davis competed against each in the highest number of races.  \nThey ran together in 726 races, which accounted for over 36% of all races in 2019.\n\nJose Lezcano and Manuel Franco competed in 659 (33% out of 2000) races. \nJose Lezcano and Dylan Davis competed in 575 (28.8%) races.\n\n\n\n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='right')\n\n\n\nax.set_yticklabels(ax.get_yticklabels(), rotation = 0, fontsize=12)\nax.set_xticklabels(ax.get_xticklabels(), rotation = 80, fontsize=12)#fontfamily='serif', \n\nax.set_ylabel('')    \nax.set_xlabel('')\nax.tick_params(axis=u'both', which=u'both',length=0)\n\n# plt.xticks(fontsize=10)\n# plt.yticks(fontsize=10)\n\nplt.tight_layout()\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:30:04.317086Z","iopub.execute_input":"2022-11-10T14:30:04.317520Z","iopub.status.idle":"2022-11-10T14:30:05.858212Z","shell.execute_reply.started":"2022-11-10T14:30:04.317444Z","shell.execute_reply":"2022-11-10T14:30:05.856724Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pair_perfs = {'win_rate': [], 'score': []}\npairs = [['Manuel Franco', 'Dylan Davis'], ['Jose Lezcano', 'Manuel Franco'], ['Jose Lezcano', 'Dylan Davis']]\nfor pair in pairs:\n    cs = pcs[pcs[pair].sum(axis=1)==2][pair].reset_index()[['track_id', 'race_date', 'race_number']]\n    cs.columns.name=''\n    # print(cs.shape)\n    cs = cs.merge(start_table, on = ['track_id', 'race_date', 'race_number'], how='inner')\n    cs = cs[cs['jockey'].isin(pair)]\n    # print(cs.shape)\n    cs.sort_values(by=['race_date', 'race_number'], ascending=[True, True], inplace=True)\n    cs_ = pd.pivot_table(cs[cs['position_at_finish']<=1], values='position_at_finish', \n                   index=['race_date', 'race_number'], columns=['jockey'], aggfunc=np.size, fill_value=0)\n    cs_.reset_index(drop=True, inplace=True)\n    for jk in pair:\n        cs_[jk] = (cs_[jk].cumsum())/(cs_.index+1)\n        \n    pair_perfs['win_rate'].append(cs_)\n    \n\n\n    cs0 = cs.pivot(index=['race_date', 'race_number'], columns=['jockey'], values=['position_at_finish'])\n    cs0.columns = [b for _, b in cs0.columns]\n    cs_ = cs0.copy()\n    cs_[pair[0]]=(cs0[pair[0]]>cs0[pair[1]]).astype(int)\n    cs_[pair[1]]=(cs0[pair[0]]<cs0[pair[1]]).astype(int)\n    cs_.reset_index(drop=True, inplace=True)\n    \n    for jk in pair:\n        cs_[jk] = (cs_[jk].cumsum())/(cs_.index+1)  \n        \n    pair_perfs['score'].append(cs_)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:30:05.859790Z","iopub.execute_input":"2022-11-10T14:30:05.861051Z","iopub.status.idle":"2022-11-10T14:30:06.019570Z","shell.execute_reply.started":"2022-11-10T14:30:05.861009Z","shell.execute_reply":"2022-11-10T14:30:06.017773Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axs = plt.subplots(3, 2, figsize=(18, 16), dpi=120)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\n\nfor j in range(3):\n    \n    for n, k in enumerate(list(pair_perfs.keys())):\n    \n        data = pair_perfs[k][j]\n        ax = axs[j, n]\n        labels = data.columns.tolist()\n        if n<1:\n            caption=f'Races {labels[0]} and {labels[1]} ran together: win rate over time for each jockey'\n        else:\n            caption=f'Races {labels[0]} and {labels[1]} ran together: scores over time time for each jockey'\n\n        for i in range(data.shape[1]):\n            ax.plot(data.index, data.iloc[:, i], marker='', markerfacecolor=mcolors[i], markersize=2, color=colors[i], linewidth=2, label=labels[i])\n            ax.text(data.iloc[:, i].dropna().size + 1, data.iloc[:, i].dropna().values[-1], labels[i], fontsize=11, color=mcolors[i])\n            ax.yaxis.grid(color='lightgray', linestyle='dashed')\n            #ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n            ax.spines[['top', 'right']].set_visible(False)\n            ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n            ax.set_ylabel('')\n            ax.set_title(caption)\n            #ax.set_xticks([])\n\n\n\nfig.text(.012, 1.2, '''\nCan one jockey maintain his advantage over another jockey throughout all races?\n''', fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\n\nfig.text(.012, 1.15, '''\nWe look at 3 pairs of jockeys (Manuel Franco and Dylan Davis, Jose Lezcano and Manuel Franco,\nJose Lezcano and Dylan Davis) and see how they outperformed each other over time. \n\n''',fontfamily='monospace',fontweight='bold',fontsize=14,color='#323232', ha='left')  \n\nfig.text(0.012, .985, '''\n\nFirst, we only look at the races either one in a pair won, and examine how the win rates change over time.\nThen, we look at all the races each pair ran together and see how each one outperformed each other over time. \nFor example, in a race, if one finished in 3rd position and the other finished in 5th position, \nthen the one at 3rd position gets a point. \n\nManuel Franco and Dylan Davis: after the initial fluctuations in the first 100ish races, these two gained certain equilibrium.\n\nJose Lezcano and Manuel Franco: Jose gradually lost more and more to Manuel even though Manuel did not \ncath up with Jose - in terms of points got - in the end.\n\nJose Lezcano and Dylan Davis: Dylan quickly outperformed Jose in the first 50 races they two ran together. \nThe pace slowed down after 250 races together, but Dylan maintained outperforming Jose to the end.\n\n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\n    \nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.2, hspace=0.2) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:30:06.021771Z","iopub.execute_input":"2022-11-10T14:30:06.022359Z","iopub.status.idle":"2022-11-10T14:30:07.674232Z","shell.execute_reply.started":"2022-11-10T14:30:06.022308Z","shell.execute_reply":"2022-11-10T14:30:07.672813Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"3.4\">3.4 Speed analysis and Jockey's decisions </div>\n\n\n\n[back to top](#toc)","metadata":{}},{"cell_type":"code","source":"#https://stackoverflow.com/questions/19412462/getting-distance-between-two-points-based-on-latitude-longitude\nfrom math import sin, cos, sqrt, atan2\n#returns the distance in meters\ndef cal_distance(data):\n    \"\"\"\n    data is a pd.Series, must have 'latitude', 'longitude', 'latitude2', 'longitude2'\n    \"\"\"\n    if (data is None)|(data is np.nan):\n        return 0\n\n    R = 6373.0 ## approximate radius of earth in km\n\n    lat1, lon1, lat2, lon2 = data[['latitude', 'longitude', 'latitude2', 'longitude2']].values\n  \n\n    dlon = lon2 - lon1\n    dlat = lat2 - lat1\n    a = (sin(dlat/2))**2 + cos(lat1) * cos(lat2) * (sin(dlon/2))**2\n    c = 2 * atan2(sqrt(a), sqrt(1-a))\n    distance = R * c*1000\n    return distance","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:30:07.675599Z","iopub.execute_input":"2022-11-10T14:30:07.676022Z","iopub.status.idle":"2022-11-10T14:30:07.686286Z","shell.execute_reply.started":"2022-11-10T14:30:07.675981Z","shell.execute_reply":"2022-11-10T14:30:07.684516Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#https://geopy.readthedocs.io/en/stable/#module-geopy.distance\nfrom geopy.distance import distance as GO_DIS\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:30:07.688499Z","iopub.execute_input":"2022-11-10T14:30:07.689024Z","iopub.status.idle":"2022-11-10T14:30:07.865337Z","shell.execute_reply.started":"2022-11-10T14:30:07.688986Z","shell.execute_reply":"2022-11-10T14:30:07.863915Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"jockeys = ['Manuel Franco', 'Jose Lezcano', 'Javier Castellano', 'Irad Ortiz Jr.']\nrh_ids = tracking_table[tracking_table['jockey'].isin(jockeys)]['race_horse_id'].unique().tolist()\n\nspeed_data = []\nfor race_horse_id in rh_ids:\n    \n    data = tracking_table[(tracking_table['race_horse_id']==race_horse_id)][['race_horse_id','trakus_index','latitude','longitude']].copy(deep=True)\n    data.sort_values(by=['race_horse_id', 'trakus_index'], ascending=[True]*2, inplace=True)\n    data_next = data[['race_horse_id','trakus_index','latitude','longitude']].shift(-1)\n    data_next.columns = [f'{c}2' for c in data_next.columns]\n    data = pd.concat([data, data_next], axis=1)\n    data.dropna(how='any', inplace=True)\n    data['distance'] = data.apply(lambda x: GO_DIS(x[['latitude', 'longitude']].values,x[['latitude2', 'longitude2']].values).meters, axis=1)\n    data['speed'] = data['distance']/0.25\n    \n    speed_data.append([race_horse_id, data['distance'].sum(), data['speed'].mean(), data['speed'].median(), \\\n                       data['speed'].min(), data['speed'].max(), \\\n                       data['speed'].quantile(q=0.25), data['speed'].quantile(q=0.75),\\\n                       data[data['trakus_index']<=100]['speed'].mean(), data[data['trakus_index']<=150]['speed'].mean(), \\\n                       data[data['trakus_index']>150]['speed'].mean(),\n                      ]\n                     )\n    ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:30:07.867880Z","iopub.execute_input":"2022-11-10T14:30:07.868504Z","iopub.status.idle":"2022-11-10T14:54:42.593121Z","shell.execute_reply.started":"2022-11-10T14:30:07.868468Z","shell.execute_reply":"2022-11-10T14:54:42.591848Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"speed_data_=[]\nfor ss_ in speed_data:\n    ii=[]\n    for s_ in ss_:\n        if isinstance(s_, pd.Series):\n            ii.append(s_['speed'])\n        else:\n            ii.append(s_)\n    \n    speed_data_.append(ii)        \n    \ndf_speed = pd.DataFrame(data=speed_data_, columns=['race_horse_id', 'total_distance', 'mean_speed', 'median_speed', \n                                               'min_speed', 'max_speed', 'q25_speed', 'q75_speed', \n                                                  'mean100', 'mean150', 'mean150_2'\n                                              ])","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:42.595983Z","iopub.execute_input":"2022-11-10T14:54:42.598051Z","iopub.status.idle":"2022-11-10T14:54:42.634290Z","shell.execute_reply.started":"2022-11-10T14:54:42.598002Z","shell.execute_reply":"2022-11-10T14:54:42.633001Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_speed = pd.DataFrame(data=speed_data, columns=['race_horse_id', 'total_distance', 'mean_speed', 'median_speed', \n                                               'min_speed', 'max_speed', 'q25_speed', 'q75_speed', \n                                                  'mean100', 'mean150', 'mean150_2'\n                                              ])","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:42.635831Z","iopub.execute_input":"2022-11-10T14:54:42.636231Z","iopub.status.idle":"2022-11-10T14:54:42.660616Z","shell.execute_reply.started":"2022-11-10T14:54:42.636201Z","shell.execute_reply":"2022-11-10T14:54:42.659433Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cs = start_table[start_table['jockey'].isin(jockeys)].groupby(['race_date', 'race_number'])['program_number'].count()\ncs = cs[(cs>3)].reset_index()[['race_date', 'race_number']]\ncs = cs.merge(start_table, on=['race_date', 'race_number'], how='inner')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:42.662119Z","iopub.execute_input":"2022-11-10T14:54:42.662719Z","iopub.status.idle":"2022-11-10T14:54:42.697716Z","shell.execute_reply.started":"2022-11-10T14:54:42.662672Z","shell.execute_reply":"2022-11-10T14:54:42.696655Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data0 = tracking_table[(tracking_table['race_date']=='2019-04-19') & (tracking_table['race_number']==8)].copy(deep=True)\ndata0.sort_values(by=['race_horse_id', 'trakus_index'], ascending=[True]*2, inplace=True)\n\ndata_next0 = data0[['race_horse_id','trakus_index','latitude','longitude']].groupby('race_horse_id').shift(-1)\ndata_next0.columns = [f'{c}2' for c in data_next0.columns]\ndata0 = pd.concat([data0, data_next0], axis=1)\n# data0['distance'] = data0.apply(lambda x: cal_distance(x), axis=1)\n# data0['speed'] = data0['distance']/0.25\ndata0.dropna(how='any', inplace=True)\ndata0['distance'] = data0.apply(lambda x: GO_DIS(x[['latitude', 'longitude']].values,x[['latitude2', 'longitude2']].values).meters, axis=1)\ndata0['speed'] = data0['distance']/0.25\n    \ncs0 = data0.iloc[:-1, ].pivot(index='trakus_index', columns=['program_number', 'jockey', 'position_at_finish'], values='speed')\ncs0.columns = [f'{b} (pn:{a},plc:{c})' for a,b,c in cs0.columns]","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:42.699283Z","iopub.execute_input":"2022-11-10T14:54:42.699916Z","iopub.status.idle":"2022-11-10T14:54:45.372985Z","shell.execute_reply.started":"2022-11-10T14:54:42.699879Z","shell.execute_reply":"2022-11-10T14:54:45.371718Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cs0 = cs0[['Jose Lezcano (pn:2  ,plc:4)', 'Manuel Franco (pn:3  ,plc:3)',\n       'Irad Ortiz Jr. (pn:4  ,plc:7)', 'Benjamin Hernandez (pn:5  ,plc:1)',\n       'Javier Castellano (pn:6  ,plc:2)',]]","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:45.374509Z","iopub.execute_input":"2022-11-10T14:54:45.374989Z","iopub.status.idle":"2022-11-10T14:54:45.382487Z","shell.execute_reply.started":"2022-11-10T14:54:45.374940Z","shell.execute_reply":"2022-11-10T14:54:45.380850Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axs = plt.subplots(1, 2, figsize=(16, 6),gridspec_kw={'width_ratios': [6, 10]}, dpi=130) \nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\ngroupby='program_number'\ncolors = ['lightseagreen', 'salmon', 'lightskyblue', 'mediumseagreen', 'sandybrown', 'lightslategray', 'wheat', 'crimson',\n         'rosybrown', 'bisque', 'lightsteelblue', 'cornflowerblue', 'beige', 'plum' , 'orchid', 'olivedrab']\nmcolors = ['teal', 'tomato', 'skyblue', 'mediumseagreen', 'peru', 'slategray', 'tan',  'firebrick']\n\ncaption =f'''race type: {race_type_dict[data0.iloc[0]['race_type']]} - \\\ntrack: {track_id_dict[data0.iloc[0]['track_id']]} - \\\nrace date: {data0.iloc[0]['race_date']} ({data0.iloc[0]['race_number']})\\\n- distance: {data0.iloc[0]['distance_id']} - course: {data0.iloc[0]['course_type']}\n'''\n\n\nax = axs[0]\n\nsns.scatterplot(data=data0, x='longitude', y='latitude', hue=data0['program_number'],palette=colors[:7], \n                alpha=0.9, linewidth=1.3,size=200, legend=False, #size=odds_pre['odds'],ec='black',\n                ax = ax,\n               )\n\nax.yaxis.grid(color='lightgray', linestyle='dashed')\nax.grid(visible=True, which='major', axis='y', color='lightgray', zorder=0, linestyle=':', linewidth=0.2)\nax.spines[['top', 'right']].set_visible(False)\nax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\nax.set_ylabel('Odds')\nax.set_facecolor(background_color)\n#     ax.set_yticks(range(0, 201, 40))   \n#     ax.set_ylim(0, 200)\n#     ax.set_xticks(range(0, 13, 1))   \n# ax.set_xlim(0, 4000)\n#ax.set_xlabel(labels[i])\n#ax.set_title('', loc='left')\nax.set_title('Track')\nax.set_facecolor(background_color) \n\nlabels=cs0.columns.tolist()\nax = axs[1]   \nfor i in range(cs0.shape[1]):\n    ax.plot(cs0.index, cs0.iloc[:, i], marker='', markerfacecolor=mcolors[i], markersize=2, color=colors[i], linewidth=2, label=labels[i])\n    #ax.text(cs0.iloc[:, i].dropna().size + 1, cs0.iloc[:, i].dropna().values[-1], labels[i], fontsize=11, color=mcolors[i])\n    ax.yaxis.grid(color='lightgray', linestyle='dashed')\n    #ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    ax.set_ylabel('speed (meters/second)')\n    ax.set_xlabel('trakus_index')\n    #ax.set_xticks([])\nax.set_title('Speed')\nax.legend(loc='upper right')\nax.set_facecolor(background_color) \n\n\nfig.text(.012, 1.32, '''\nJockey's speed progression in a race (1)\n''', fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(.012, 1.24, f'''\n{caption}\n''', fontfamily='monospace',fontweight='bold',fontsize=13,color='#323232', style='italic',ha='left')\n\nfig.text(.012, 1.22, '''\n(pn: program_number, plc: position_at_finish)\n''',fontfamily='monospace',fontweight='light',fontsize=12,style='italic',color='#323232', ha='left')  \n\n\nfig.text(0.012, .94, '''\n\nIn this part of analysis, we focus on jockeys Manuel Franco, Jose Lezcano, Javier Castellano, Irad Ortiz Jr.\n\nIn the 2000 races in 2019, there were 108 races in which all four jockeys participated. We select 2 races out of the 108 races \nand examine the shape of the course and the progression of speed of each jockey in the race.\n\nFirst, we look at the 8th race on 2019-04-19 at Aqueduct track. \n\n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\n    \nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.2, hspace=0.2) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:45.384576Z","iopub.execute_input":"2022-11-10T14:54:45.385380Z","iopub.status.idle":"2022-11-10T14:54:46.520363Z","shell.execute_reply.started":"2022-11-10T14:54:45.385331Z","shell.execute_reply":"2022-11-10T14:54:46.519381Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data0 = tracking_table[(tracking_table['race_date']=='2019-11-29') & (tracking_table['race_number']==2)].copy(deep=True)\ndata0.sort_values(by=['race_horse_id', 'trakus_index'], ascending=[True]*2, inplace=True)\n\ndata_next0 = data0[['race_horse_id','trakus_index','latitude','longitude']].groupby('race_horse_id').shift(-1)\ndata_next0.columns = [f'{c}2' for c in data_next0.columns]\ndata0 = pd.concat([data0, data_next0], axis=1)\n# data0['distance'] = data0.apply(lambda x: cal_distance(x), axis=1)\n# data0['speed'] = data0['distance']/0.25\ndata0.dropna(how='any', inplace=True)\ndata0['distance'] = data0.apply(lambda x: GO_DIS(x[['latitude', 'longitude']].values,x[['latitude2', 'longitude2']].values).meters, axis=1)\ndata0['speed'] = data0['distance']/0.25\n\ncs0 = data0.iloc[:-1, ].pivot(index='trakus_index', columns=['program_number', 'jockey', 'position_at_finish'], values='speed')\ncs0.columns = [f'{b} (pn:{a},plc:{c})' for a,b,c in cs0.columns]","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:46.521463Z","iopub.execute_input":"2022-11-10T14:54:46.522429Z","iopub.status.idle":"2022-11-10T14:54:50.855565Z","shell.execute_reply.started":"2022-11-10T14:54:46.522394Z","shell.execute_reply":"2022-11-10T14:54:50.854303Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cs0 = cs0[['Irad Ortiz Jr. (pn:1  ,plc:2)', 'Kendrick Carmouche (pn:2  ,plc:1)', 'Manuel Franco (pn:3  ,plc:5)',\n       'John R. Velazquez (pn:5  ,plc:4)', 'Javier Castellano (pn:6  ,plc:3)', 'Jose Lezcano (pn:8  ,plc:8)',\n         ]]\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:50.856951Z","iopub.execute_input":"2022-11-10T14:54:50.857284Z","iopub.status.idle":"2022-11-10T14:54:50.864016Z","shell.execute_reply.started":"2022-11-10T14:54:50.857254Z","shell.execute_reply":"2022-11-10T14:54:50.862613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axs = plt.subplots(1, 2, figsize=(18, 6), dpi=100)\nbackground_color = \"#fbfbfb\"\nfig.patch.set_facecolor(background_color) # figure background color\n\ngroupby='program_number'\ncolors = ['lightseagreen', 'salmon', 'lightskyblue', 'mediumseagreen', 'sandybrown', 'lightslategray', 'wheat', 'crimson',\n         'rosybrown', 'bisque', 'lightsteelblue', 'cornflowerblue', 'beige', 'plum' , 'orchid', 'olivedrab']\nmcolors = ['teal', 'tomato', 'skyblue', 'mediumseagreen', 'peru', 'slategray', 'tan',  'firebrick']\n\ncaption =f'''race type: {race_type_dict[data0.iloc[0]['race_type']]} - \\\ntrack: {track_id_dict[data0.iloc[0]['track_id']]} - \\\nrace date: {data0.iloc[0]['race_date']} ({data0.iloc[0]['race_number']})\\\n- distance: {data0.iloc[0]['distance_id']} - course: {data0.iloc[0]['course_type']}\n'''\n\n\nax = axs[0]\n\nsns.scatterplot(data=data0, x='longitude', y='latitude', hue=data0['program_number'],palette=colors[:9], \n                alpha=0.9, linewidth=1.3,size=200, legend=False, #size=odds_pre['odds'],ec='black',\n                ax = ax,\n               )\n\nax.yaxis.grid(color='lightgray', linestyle='dashed')\nax.grid(visible=True, which='major', axis='y', color='lightgray', zorder=0, linestyle=':', linewidth=0.2)\nax.spines[['top', 'right']].set_visible(False)\nax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\nax.set_ylabel('Odds')\nax.set_facecolor(background_color)\n#     ax.set_yticks(range(0, 201, 40))   \n#     ax.set_ylim(0, 200)\n#     ax.set_xticks(range(0, 13, 1))   \n# ax.set_xlim(0, 4000)\n#ax.set_xlabel(labels[i])\n#ax.set_title('', loc='left')\nax.set_title('Track')\nax.set_facecolor(background_color) \n\n\nlabels=cs0.columns.tolist()\nax = axs[1]   \nfor i in range(cs0.shape[1]):\n    ax.plot(cs0.index, cs0.iloc[:, i], marker='', markerfacecolor=mcolors[i], markersize=2, color=colors[i], linewidth=2, label=labels[i])\n    #ax.text(cs0.iloc[:, i].dropna().size + 1, cs0.iloc[:, i].dropna().values[-1], labels[i], fontsize=11, color=mcolors[i])\n    ax.yaxis.grid(color='lightgray', linestyle='dashed')\n    #ax.grid(visible=True, which='major', axis='both', color='lightgray', linestyle='-', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    ax.set_ylabel('speed (meters/second)')\n    ax.set_xlabel('trakus_index')\n    #ax.set_xticks([])\nax.set_title('Speed')\nax.legend(loc='lower right')\nax.set_facecolor(background_color) \n\nfig.text(.012, 1.14, '''\nJockey's speed progression in a race (2)\n''', fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(.012, 1.06, f'''\n{caption}\n''', fontfamily='monospace',fontweight='bold',fontsize=13,color='#323232', style='italic',ha='left')\n\nfig.text(.012, 1.05, '''\n(pn: program_number, plc: position_at_finish)\n''',fontfamily='monospace',fontweight='light',fontsize=12,style='italic',color='#323232', ha='left')  \n\n\nfig.text(0.012, .98, '''\nSecond, we look at the 2nd race on 2019-11-29 at Aqueduct track. \n\n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\n    \nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.2, hspace=0.2) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:50.865448Z","iopub.execute_input":"2022-11-10T14:54:50.866436Z","iopub.status.idle":"2022-11-10T14:54:51.666246Z","shell.execute_reply.started":"2022-11-10T14:54:50.866390Z","shell.execute_reply":"2022-11-10T14:54:51.664994Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_racehorseid = tracking_table[['race_date', 'race_number','race_id', 'program_number', 'race_horse_id', ]].drop_duplicates(keep='first')\ndf_speed = df_speed.merge(df_racehorseid, on=['race_horse_id'], how='inner')\ndf_speed = df_speed.merge(start_table, on=['race_date', 'race_number', 'program_number'], how='inner')\ndf_speed['course_type2']='Turf'\ndf_speed.loc[df_speed['course_type']=='Dirt', 'course_type2']='Dirt'","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:51.667699Z","iopub.execute_input":"2022-11-10T14:54:51.668126Z","iopub.status.idle":"2022-11-10T14:54:53.695379Z","shell.execute_reply.started":"2022-11-10T14:54:51.668094Z","shell.execute_reply":"2022-11-10T14:54:53.693820Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"background_color = \"#fbfbfb\"\nfig, axs = plt.subplots(1, 3, figsize=(15, 5), sharex=True, sharey=False, dpi=100,facecolor=background_color)\n\ncolors = ['lightseagreen', 'salmon', 'lightskyblue', 'royalblue', 'sandybrown', 'lightslategray', 'wheat', 'crimson',]\n\n\nfor i, col in enumerate(df_speed['track_id'].unique()):\n    ax = axs[i]\n    \n    sns.boxplot(y='mean_speed',x='jockey',hue='course_type2',data=df_speed[df_speed['track_id']==col],\n                order = jockeys, \n                palette=colors[:2], \n                boxprops=dict(alpha=.9),\n                ax=ax, \n               )\n    \n\n    ax.yaxis.grid(color='lightgray', linestyle='dashed')\n    ax.grid(visible=True, which='major', axis='y', color='lightgray', zorder=0, linestyle='-', linewidth=0.5)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    ax.set_yticks(range(5, 26, 5))   \n    ax.set_ylim(5, 25)\n    #     ax.set_xticks(range(0, 13, 1))   \n    # ax.set_xlim(0, 4000)\n    ax.set_xlabel('')\n    ax.set_ylabel('')\n    ax.set_title(col, loc='center')\n#     ax.set_yticklabels(ax.get_yticklabels(), rotation = 0, fontsize=12)\n    ax.set_xticklabels(ax.get_xticklabels(), rotation = 60, fontfamily='monospace', fontsize=10)#\n    \n    ax.legend_.remove() \n    ax.set_facecolor(background_color)\n    \n\nfig.text(.012, 1.26, '''\nDistribution of average speed in a race -  Manuel Franco, Jose Lezcano, Javier Castellano, Irad Ortiz Jr.\n''', fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(0.012, .98, '''\n\nFor all four jockeys - Manuel Franco, Jose Lezcano, Javier Castellano, Irad Ortiz Jr., the average speed in a race in general\nwas faster on Turf course than Dirt course. (Note in previous analysis there were more longer distance races on Turf course).\n\nDespite that these jockeys' performance (win rate/place rate) on different tracks very based on previous analysis - for example,\nManuel Franco win rate/place rate on Belmont/Saratoga was lower than that on Aqueduct, the average speed did not differ much.\n\n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\n\nfig.text(.95, 1, 'Dirt', color=\"lightseagreen\",fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \nfig.text(.96, 1, '|',fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \nfig.text(.99, 1, 'Turf', color=\"salmon\",fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \n\nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.2, hspace=0.2) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:53.697087Z","iopub.execute_input":"2022-11-10T14:54:53.697565Z","iopub.status.idle":"2022-11-10T14:54:54.724379Z","shell.execute_reply.started":"2022-11-10T14:54:53.697521Z","shell.execute_reply":"2022-11-10T14:54:54.722861Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"background_color = \"#fbfbfb\"\nfig, axs = plt.subplots(2, 3, figsize=(15, 8), sharex=False, sharey=True, dpi=100,facecolor=background_color)\n\ncolors = ['lightseagreen', 'salmon', 'lightskyblue', 'royalblue', 'sandybrown', 'lightslategray', 'wheat', 'crimson',]\n\n\nfor j, hue in enumerate(['win', 'place',]):\n    for i, col in enumerate(['mean_speed', 'mean150', 'mean150_2']):\n        ax = axs[j, i]\n\n        sns.boxplot(y=col,x='jockey',hue=hue,data=df_speed,\n                    order = jockeys, \n                    palette=colors[:2], \n                    boxprops=dict(alpha=.8),\n                    ax=ax, \n                   )\n\n\n        ax.yaxis.grid(color='lightgray', linestyle='dashed')\n        ax.grid(visible=True, which='major', axis='y', color='lightgray', zorder=0, linestyle='-', linewidth=0.5)\n        ax.spines[['top', 'right']].set_visible(False)\n        ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n        ax.set_yticks(range(5, 26, 5))   \n        ax.set_ylim(5, 25)\n        #     ax.set_xticks(range(0, 13, 1))   \n        # ax.set_xlim(0, 4000)\n        ax.set_xlabel('')\n        ax.set_ylabel('')\n        #ax.set_title('', loc='left')\n    #     ax.set_yticklabels(ax.get_yticklabels(), rotation = 0, fontsize=12)\n        ax.set_xticklabels(ax.get_xticklabels(), rotation = 20, fontfamily='monospace', fontsize=8)#\n\n        ax.legend_.remove() \n        ax.set_facecolor(background_color)\n\n\n\naxs[0, 0].text(-.45,29, '''\nAverage speed during the whole race\n''', fontfamily='monospace',fontweight='bold',fontsize=12,color='teal', ha='left')   \n\naxs[0, 1].text(-.45,29, '''\nAverage speed for trakus_index<150\n''', fontfamily='monospace',fontweight='bold',fontsize=12,color='teal', ha='left')    \n\naxs[0, 2].text(-.45,29, '''\nAverage speed for trakus_index>150\n''', fontfamily='monospace',fontweight='bold',fontsize=12,color='teal', ha='left')    \n\naxs[0, -1].text(2.8, 27, 'Not Win', color=\"lightseagreen\",fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \naxs[0, -1].text(3, 27, '|',fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \naxs[0, -1].text(3.5, 27, 'Win', color=\"salmon\",fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \n\naxs[-1, -1].text(2.8, 27, 'Not Place', color=\"lightseagreen\",fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \naxs[-1, -1].text(2.95, 27, '|',fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \naxs[-1, -1].text(3.5, 27, 'Place', color=\"salmon\",fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \n    \nfig.text(.012, 1.2, '''\nJockey's decisions - speed and wins\n''', fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(0.012, .95, '''\n\nDo full horsepower in the begining phase of the race lead to win?  \n    Manuel Franco: there's no obvious difference in speed between the races that he won and those he did not won.  \n    Jose Lezcano:  the speed of races that he won was slightly faster than those he did not won\n    Javier Castellano:  the speed of races that he won was obviously faster than those he did not won, the difference was \n        more apparent in later half (or after trakus_index 150) of the race. It seemed that his such decisions helped him\n        gaining good results in races.\n    Irad Ortiz Jr.: Similar to Jose Lezcano.\n\n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\n\n\nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.2, hspace=0.5) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:54.726359Z","iopub.execute_input":"2022-11-10T14:54:54.726817Z","iopub.status.idle":"2022-11-10T14:54:56.354421Z","shell.execute_reply.started":"2022-11-10T14:54:54.726773Z","shell.execute_reply":"2022-11-10T14:54:56.352979Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n<div style='background-color: teal; color: white; font-family: Helvetica; font-size: 25px; padding: 6px 12px; margin-bottom: 5px;' id=\"4\">4. Bets: odds of winning</div>\n\n\n[back to top](#toc)","metadata":{}},{"cell_type":"markdown","source":"<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"4.1\">4.1 Odd by finishing position</div>\n\n\n\n[back to top](#toc)","metadata":{}},{"cell_type":"code","source":"background_color = \"#fbfbfb\"\nfig, ax = plt.subplots(1, 1, figsize=(15, 5), sharex=True, sharey=True, dpi=100,facecolor=background_color)\n\ncolors = ['lightseagreen', 'salmon', 'lightskyblue', 'royalblue', 'sandybrown', 'lightslategray', 'wheat', 'crimson',]\n\ndata = start_table.loc[start_table['position_at_finish']<9, ['odds', 'position_at_finish']]\n\nsns.kdeplot(data['odds'], hue=data['position_at_finish'], ax=ax, palette=colors,\n            shade=True, linewidth=.5, alpha=0.6, legend=True)#ec='black', \n    \nax.yaxis.grid(color='lightgray', linestyle='dashed')\nax.grid(visible=True, which='major', axis='y', color='lightgray', zorder=0, linestyle=':', linewidth=0.2)\nax.spines[['top', 'right']].set_visible(False)\nax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\nax.set_ylabel('')\nax.set_facecolor(background_color)\n#     ax.set_yticks(range(0, 201, 40))   \n#     ax.set_ylim(0, 200)\n#     ax.set_xticks(range(0, 13, 1))   \nax.set_xlim(0, 4000)\nax.set_xlabel('Odds')\n#ax.set_title('', loc='left')\nax.set_facecolor(background_color)\n\n        \n\nfig.text(.012, 1.16, '''\nOdds by finishing position\n''', fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(0.012, .94, '''\nThe density plot of Odds shows that \"the market expectations\" (i.e. speculations on winning chances) had a high correlatioin \nto the actual wins:\n    the odds concentrated on the very left for jockeys/horses finished in 1st place; \n    the distribution shifted a bit right for jockeys/horses finished in 2nd or 3rd places. \n \n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\n\n\nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.2, hspace=0.2) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:56.356098Z","iopub.execute_input":"2022-11-10T14:54:56.356524Z","iopub.status.idle":"2022-11-10T14:54:56.982149Z","shell.execute_reply.started":"2022-11-10T14:54:56.356485Z","shell.execute_reply":"2022-11-10T14:54:56.981106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"4.2\">4.2 Odds of top 15 jockeys by track </div>\n\n\n\n[back to top](#toc)","metadata":{}},{"cell_type":"code","source":"background_color = \"#fbfbfb\"\nfig, axs = plt.subplots(5, 3, figsize=(15, 15), sharex=True, sharey=True, dpi=110,facecolor=background_color)\n\n\ni = 0\nfor jk in top30jockeys[:15]:\n    ax = axs[i//3, i%3]\n    data = start_table[start_table['jockey']==jk][['track_id', 'odds']]\n    #sns.kdeplot(data['odds'], hue=data['track_id'], ec='black', shade=True, linewidth=1.5, alpha=0.9, zorder=3, legend=False, ax=ax)\n    sns.kdeplot(data.loc[data['track_id']=='Aqueduct', 'odds'], ax=ax,color=\"lightseagreen\", shade=True, label=\"Aqueduct\",alpha=0.6,)\n    sns.kdeplot(data.loc[data['track_id']=='Belmont', 'odds'], ax=ax,color=\"salmon\", shade=True, label=\"Belmont\", alpha=0.4, )\n    sns.kdeplot(data.loc[data['track_id']=='Saratoga', 'odds'], ax=ax,color=\"wheat\", shade=True, label=\"Saratoga\",alpha=0.3, )\n    ax.yaxis.grid(color='lightgray', linestyle='dashed')\n    ax.grid(visible=True, which='major', axis='y', color='lightgray', zorder=0, linestyle=':', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    ax.set_ylabel('')\n    ax.set_facecolor(background_color)\n#     ax.set_yticks(range(0, 201, 40))   \n#     ax.set_ylim(0, 200)\n#     ax.set_xticks(range(0, 13, 1))   \n    ax.set_xlim(0, 4000)\n    ax.set_xlabel('Odds')\n    ax.set_title(jk, loc='left')\n    ax.set_facecolor(background_color)\n    i = i + 1\n        \n\n\nfig.text(.012, 1.12, '''\nOdds of top 15 jockeys by track \n''', fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\n\nfig.text(.012, 1.095, '''\nTop 15 jockeys are jockeys who ranked in top 15 by number of races finished in 1st, 2nd, or 3rd position.\n\n''',fontfamily='monospace',fontweight='light',fontsize=12,style='italic',color='#323232', ha='left')  \n\nfig.text(0.012, .985, '''\n\nFrom previous analysis we know that Manuel Franco's performance hit a plateau when the racing track switched from Aqueduct to Belmont. \nThis was also reflected in the odds (i.e. the expectations of jockey/horse's chances of wining):the odds for races at Aqueduct track \nconcentrated in left tail, and the distribution of odds of races at the other two tracks shifted to right.\n\nOn the contrary, Jose L. Ortiz and Javier Castellano both did better on Belmont and Saratoga tracks, and the odds on Belmont were \nconcentrated on the left. \n\n\n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\nfig.text(.84, 1, 'Aqueduct', color=\"lightseagreen\",fontweight='bold', fontfamily='monospace', fontsize=15,ha='right')  \nfig.text(.85, 1, '|',fontweight='bold', fontfamily='monospace', fontsize=15,ha='right')  \nfig.text(.91, 1, 'Belmont', color=\"salmon\",fontweight='bold', fontfamily='monospace', fontsize=15,ha='right')  \nfig.text(.92, 1, '|',fontweight='bold', fontfamily='monospace', fontsize=15,ha='right')  \nfig.text(.99, 1, 'Saratoga', color=\"wheat\",fontweight='bold', fontfamily='monospace', fontsize=15,ha='right')  \n\nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.2, hspace=0.2) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:54:56.983818Z","iopub.execute_input":"2022-11-10T14:54:56.984608Z","iopub.status.idle":"2022-11-10T14:55:00.365024Z","shell.execute_reply.started":"2022-11-10T14:54:56.984570Z","shell.execute_reply":"2022-11-10T14:55:00.363733Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"4.3\">4.3 Odds and Win/Place rate in previous 30 race days </div>\n\n\n[back to top](#toc)","metadata":{}},{"cell_type":"code","source":"#While there were 178 jockeys participated in the 2000 races in 2019, \n#only 43 of them raced in 30 or more races. \n#And the number goes down to 21 (the number of jockeys) who raced in 200 or more races.\n\n#calculate each jockey's previous 30 race days performance for the 43 jockeys who raced in 30 or more races. \n\njockeys43 = start_table['jockey'].value_counts()[start_table['jockey'].value_counts()>=30].index.values.tolist()\nrace_days = race_table['race_date'].unique().tolist()\nrace_days.sort()\n\n\ndata = pd.pivot_table(start_table, index=['race_date'], columns=['jockey'], \n               values=['win', 'place'], \n               aggfunc={'win': [np.sum, np.size], 'place': np.sum} )\ndata.sort_index(ascending=True, inplace=True)\n\ndfs_pre = []\nfor jk in jockeys43:\n\n    data_i = data[[('place', 'sum',            jk), \n                   (  'win', 'size',            jk), \n                   (  'win', 'sum',            jk)]].fillna(0)\n    data_i.columns=['place', 'run', 'win']\n\n    data_i['plc_sum']=data_i['place'].rolling(31).apply(lambda x: x[:-1].sum())\n    data_i['win_sum']=data_i['win'].rolling(31).apply(lambda x: x[:-1].sum())\n    data_i['run_sum']=data_i['run'].rolling(31).apply(lambda x: x[:-1].sum())\n\n    data_i['plc_rate'] = data_i['plc_sum']/data_i['run_sum']\n    data_i['win_rate'] = data_i['win_sum']/data_i['run_sum']\n    data_i['jockey']=jk\n    dfs_pre.append(data_i.reset_index()[['jockey', 'race_date', 'plc_rate', 'win_rate']])\n    \n\ndf_pre = pd.concat(dfs_pre)\n\nodds_sum = pd.pivot_table(start_table, index=['jockey', 'race_date','track_id'], \n               values=['odds'], \n               aggfunc=[np.min, np.max, np.mean]).reset_index()\nodds_sum = odds_sum[odds_sum['jockey'].isin(jockeys43)]\nodds_sum.columns = ['jockey', 'race_date','track_id', 'min_odds', 'max_odds', 'mean_odds']\n\nodds_pre = df_pre.merge(start_table[['jockey', 'race_date', 'odds', 'track_id']], on=['jockey', 'race_date'], how='left')\nodds_pre_sum = df_pre.merge(odds_sum, on=['jockey', 'race_date'], how='left')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:55:00.367247Z","iopub.execute_input":"2022-11-10T14:55:00.368197Z","iopub.status.idle":"2022-11-10T14:55:05.059599Z","shell.execute_reply.started":"2022-11-10T14:55:00.367899Z","shell.execute_reply":"2022-11-10T14:55:05.058363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"background_color = \"#fbfbfb\"\nfig, axs = plt.subplots(1, 2, figsize=(15, 4.5), sharex=True, sharey=True, dpi=100,facecolor=background_color)\n\ncolors = ['lightseagreen', 'salmon', 'lightskyblue', 'royalblue', 'sandybrown', 'lightslategray', 'wheat', 'crimson',]\n\nlabels = ['Win rate in previous 30 race days', 'Place rate in previous 30 race days']\nfor i, col in enumerate(['win_rate', 'plc_rate']):\n    ax = axs[i]\n\n    sns.scatterplot(data=odds_pre, x=col, y='odds', color='teal',hue=odds_pre['track_id'],palette=colors[:3], \n                    alpha=0.9, linewidth=1.3,size=10, legend=False, #size=odds_pre['odds'],ec='black',\n                    ax = ax,\n                   )\n\n    ax.yaxis.grid(color='lightgray', linestyle='dashed')\n    ax.grid(visible=True, which='major', axis='y', color='lightgray', zorder=0, linestyle=':', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    ax.set_ylabel('Odds')\n    ax.set_facecolor(background_color)\n    #     ax.set_yticks(range(0, 201, 40))   \n    #     ax.set_ylim(0, 200)\n    #     ax.set_xticks(range(0, 13, 1))   \n    # ax.set_xlim(0, 4000)\n    ax.set_xlabel(labels[i])\n    #ax.set_title('', loc='left')\n    ax.set_facecolor(background_color)\n    \naxs[0].add_patch(Rectangle((0.01, 0.), 0.2, 6000,alpha=0.3, edgecolor='gray',facecolor='gray'))\naxs[1].add_patch(Rectangle((0.05, 0.), 0.5, 8000,alpha=0.3, edgecolor='gray',facecolor='gray'))        \n\nfig.text(.012, 1.4, '''\nOdds and Win/Place rate in previous 30 race days \n''', fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(0.012, .9, '''\n\nHere we are trying to explore the relationship between odds and the corresponding jockey’s win rate/place rate in previous 30 race days.\n\nWhen a jockey’s win rate in the previous 30 race days was below 0.2 (i.e. win rate less than 20%), there was no obvious pattern on odds; \nwhen the rate was above 0.2, the odds were low in comparison.\n\nThe similar pattern holds for place rate: when a jockey’s place rate in previous 30 race days was below 0.6 (i.e. less than 60% place rate),  \nthere was no obvious pattern on odds; when the rate was above 0.6, the odds were low in comparison.\n\nThere was no apparent difference between different tracks.\n \n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\nfig.text(.84, 1, 'Aqueduct', color=\"lightseagreen\",fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \nfig.text(.85, 1, '|',fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \nfig.text(.91, 1, 'Belmont', color=\"salmon\",fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \nfig.text(.92, 1, '|',fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \nfig.text(.99, 1, 'Saratoga', color=\"wheat\",fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \n\n\nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.2, hspace=0.2) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:55:05.061286Z","iopub.execute_input":"2022-11-10T14:55:05.061822Z","iopub.status.idle":"2022-11-10T14:55:06.412881Z","shell.execute_reply.started":"2022-11-10T14:55:05.061718Z","shell.execute_reply":"2022-11-10T14:55:06.411572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"background_color = \"#fbfbfb\"\nfig, axs = plt.subplots(1, 3, figsize=(15, 3.5), sharex=True, sharey=False, dpi=100,facecolor=background_color)\n\ncolors = ['lightseagreen', 'salmon', 'lightskyblue', 'royalblue', 'sandybrown', 'lightslategray', 'wheat', 'crimson',]\n\n\nfor i, col in enumerate(['min_odds', 'max_odds', 'mean_odds']):\n    ax = axs[i]\n\n    sns.scatterplot(data=odds_pre_sum, x='win_rate', y=col, color='teal',hue=odds_pre_sum['track_id'],palette=colors[:3], \n                    alpha=0.9, linewidth=1.3,size=10, legend=False, #size=odds_pre['odds'],ec='black', \n                    ax=ax)\n\n    ax.yaxis.grid(color='lightgray', linestyle='dashed')\n    ax.grid(visible=True, which='major', axis='y', color='lightgray', zorder=0, linestyle=':', linewidth=0.2)\n    ax.spines[['top', 'right']].set_visible(False)\n    ax.spines[['bottom', 'left']].set_edgecolor('whitesmoke')\n    #     ax.set_yticks(range(0, 201, 40))   \n    #     ax.set_ylim(0, 200)\n    #     ax.set_xticks(range(0, 13, 1))   \n    # ax.set_xlim(0, 4000)\n    ax.set_xlabel('Win rate in previous 30 race days')\n    ax.set_ylabel(col)\n    #ax.set_title('', loc='left')\n    ax.set_facecolor(background_color)\n    ax.add_patch(Rectangle((0.01, 0.), 0.2, 6000,alpha=0.3, edgecolor='gray',facecolor='gray'))\n        \n\nfig.text(.012, 1.32, '''\nOdds and Win rate in previous 30 race days  \n''', fontfamily='monospace',fontweight='bold',fontsize=15,color='#323232', ha='left')\n\nfig.text(0.012, .94, '''\nmin_odds/max_odds/mean_odds: the min/max/mean value of odds for all races that a jockey raced in a race day; \nSimilar to previous analysis, when a jockey's win rate in the previous 30 race days was above 0.2, the min/max/mean odds were all low in comparison.\n\nThis pattern can lead to a logical conclusion that when a jockey had an impressive track record, the expectations on the jockey's future wins \nwas high (lower odds mean higher expectations on winning).\n \n''',fontfamily='monospace',fontweight='light',fontsize=13,color='#323232', ha='left')\n\nfig.text(.84, 1, 'Aqueduct', color=\"lightseagreen\",fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \nfig.text(.85, 1, '|',fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \nfig.text(.91, 1, 'Belmont', color=\"salmon\",fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \nfig.text(.92, 1, '|',fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \nfig.text(.99, 1, 'Saratoga', color=\"wheat\",fontweight='light', fontfamily='monospace', fontsize=13,ha='right')  \n\nplt.tight_layout()\nplt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.2, hspace=0.2) # useful for adjusting space between subplots\nplt.show()  ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-10T14:55:06.415040Z","iopub.execute_input":"2022-11-10T14:55:06.415768Z","iopub.status.idle":"2022-11-10T14:55:07.479798Z","shell.execute_reply.started":"2022-11-10T14:55:06.415730Z","shell.execute_reply":"2022-11-10T14:55:07.478605Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n<div style='background-color: teal; color: white; font-family: Helvetica; font-size: 25px; padding: 6px 12px; margin-bottom: 5px;' id=\"5\">5. Final thoughts</div>\n\n\n[back to top](#toc)\n\n\n<div style='color: teal; font-family: Helvetica; font-size: 18px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px; '>How to make races more interesting?</div>\n\n<div style='font-family: Helvetica; font-size: 16px; font-weight:normal; padding: 6px 12px; margin-bottom: 5px; '>\n\nFrom the thorough analysis on racing data above, we know races are mostly competed among around 30 jockeys and there is high correlation between odds and finishing position (i.e. chances of winning). We also know when a jockey’s win rate in the previous 30 race days is less than 20%, there is no apparent pattern in odds. So if we place 2 or 3 jockeys with similarly high win rates - for example, all over 21% - in the same race, or we place jockeys all with similarly low win rates - say all below 15% - in the same race, will the betting process be more exciting because the races become more unpredictable?\n<br>    \n\n\n\n</div>\n\n\n\n<div style='color: teal; font-family: Helvetica; font-size: 18px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px; '>How to place bets for a little harmless fun?</div>\n\n<div style='font-family: Helvetica; font-size: 16px; font-weight:normal; padding: 6px 12px; margin-bottom: 5px; '>\n\nSince there is a high correlation between chances of winning and odds, and the odds are low when jockey’s win rate in the previous 30 race days is above 60%, and a top jockey’s performance can persist throughout the year, so betting on jockeys who did well previously and have low odds should be fun enough by having bigger chances of getting a win.\n<br>    \n\n\n\n</div>","metadata":{}},{"cell_type":"markdown","source":"\n<div style='background-color: teal; color: white; font-family: Helvetica; font-size: 25px; padding: 6px 12px; margin-bottom: 5px;' id=\"8\">Appendix</div>\n\n[back to top](#toc)\n\n\n<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"8.1\">Data Description </div>\n\n\n\n| field name  | field description   |\n| ------------ | ------------ |\n|track_id | 3 character id for the track the race took place at. AQU -Aqueduct, BEL - Belmont, 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|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. Example - 1280 would be 12.8-1.|\n|position_at_finish | An integer of the horse's finishing position. (added to the dataset 9/8/22)|\n|distance_id | Distance of the race in furlongs passed as an integer. Example - 600 would be 6 furlongs.|\n|course_type | The course the race was run over passed as one character. M - Hurdle, D - Dirt, O - Outer turf, I - Inner turf, T - turf.\n|track_condition | The condition of the course the race was run on passed as three characters. YL - Yielding, FM - Firm, SY - Sloppy, GD - Good, FT - Fast, MY - Muddy, 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. STK - Stakes, WCL - Waiver Claiming, WMC - Waiver Maiden Claiming, SST - Starter Stakes, SHP - Starter Handicap, CLM - Claiming, STR - Starter Allowance, AOC - Allowance Optionl Claimer, SOC - Starter Optional Claimer, MCL - Maiden Claiming, ALW - Allowance, 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. Example - 01220 would be 12:20.|\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.|\n|*race_id|unique number for race_date + race_number  combination.|\n|*race_horse_id|unique number for race_date + race_number + program_number combination.|","metadata":{}},{"cell_type":"markdown","source":"\n<div style='background-color: lightseagreen; color: white; font-family: Helvetica; font-size: 20px; font-weight:bold; padding: 6px 12px; margin-bottom: 5px;' id=\"8.2\">References </div>\n\n\n- https://pandas.pydata.org/docs/user_guide/style.html\n- [Take Your Histograms to the Next Level Using Matplotlib](https://towardsdatascience.com/take-your-histograms-to-the-next-level-using-matplotlib-5f093ad7b9d3)\n- https://github.com/arseniyturin/Capstone-Project/blob/master/plotting.py\n- https://github.com/arseniyturin/Capstone-Project/blob/master/Part%203.%20Machine%20Learning.ipynb\n- https://github.com/akanz1/klib/blob/main/src/klib/describe.py\n- https://github.com/WilliamCHW/Python-Visualizations\n- https://www.kaggle.com/code/joshuaswords/awesome-eda-2021-happiness-population\n- https://www.kaggle.com/code/gaetanlopez/how-to-make-clean-visualizations\n- https://www.kaggle.com/code/joshuaswords/netflix-data-visualization\n- https://www.kaggle.com/code/joshuaswords/does-hosting-the-olympics-improve-performance\n- https://www.kaggle.com/code/joshuaswords/predicting-a-stroke-shap-lime-explainer-eli5\n- https://www.kaggle.com/code/joshuaswords/data-visualization-clustering-mall-data\n","metadata":{}}]}