{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<h1 style=\"text-align:center;font-size:220%;\"><a>BIG DATA DERBY 2022</a></h1> \n\n","metadata":{}},{"cell_type":"markdown","source":"**Notebook Run Time: 130sec Thank you for your patient.**","metadata":{}},{"cell_type":"markdown","source":"## About Me","metadata":{}},{"cell_type":"markdown","source":"**Hello everyone, this may be my first contest where I spend my time seriously. I am a graduate of Mechatronics Engineering. I have been dealing with Data Science for about 1 year. I wish everyone success.**","metadata":{}},{"cell_type":"markdown","source":"# Import Libraries\n","metadata":{}},{"cell_type":"code","source":"import numpy as np \nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport plotly.express as px\nfrom plotly.subplots import make_subplots\nimport plotly.figure_factory as ff\nimport plotly.offline as offline\nimport plotly.graph_objs as go\noffline.init_notebook_mode(connected = True)\nfrom plotly.colors import n_colors\ncolors=['#5a6edc','#fc0da1','#fed400','#E60000','#4a00b5','#abd98c','#FF5733','#800080','#00FFFF','#00FF00']","metadata":{"_kg_hide-input":false,"_kg_hide-output":true,"scrolled":true,"execution":{"iopub.status.busy":"2022-11-04T14:21:22.240259Z","iopub.execute_input":"2022-11-04T14:21:22.240801Z","iopub.status.idle":"2022-11-04T14:21:25.219191Z","shell.execute_reply.started":"2022-11-04T14:21:22.240648Z","shell.execute_reply":"2022-11-04T14:21:25.217960Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from IPython.display import HTML as html_print\nfrom IPython.display import display\n\ndef cstr(s, fcolor='red',bgcolor='#232425'):\n    return \"<p style=color:{};font-size:21px;background-color:{};>{}</p>\".format(fcolor,bgcolor, s)\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:21:25.221598Z","iopub.execute_input":"2022-11-04T14:21:25.221973Z","iopub.status.idle":"2022-11-04T14:21:25.227134Z","shell.execute_reply.started":"2022-11-04T14:21:25.221939Z","shell.execute_reply":"2022-11-04T14:21:25.226259Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load Data & First Look\n","metadata":{}},{"cell_type":"code","source":"race_table=pd.read_csv(\"/kaggle/input/big-data-derby-2022/nyra_race_table.csv\")\nstart_table_head=[\"track_id\",\"race_date\",\"race_number\",\"program_number\",\"weight_carried\",\"jockey\",\"odds\",\"position_at_finish\"]\nstart_table=pd.read_csv(\"/kaggle/input/big-data-derby-2022/nyra_start_table.csv\",header=0,names=start_table_head)\ntracking_table=pd.read_csv(\"/kaggle/input/big-data-derby-2022/nyra_tracking_table.csv\")\nmerged_head={\"track_id\":str,\"race_date\":str,\"race_number\":str,\"program_number\":str,\"trakus_index\":int,\n             \"latitude\":float,\"longitude\":float,\"distance_id\":int, \"course_type\":str,\n             \"track_condition\":str,\"run_up_distance\":int,\"race_type\":str,\"post_time\":str,\"weight_carried\":int,\n             \"jockey\":str,\"odds\":int,\"position_at_finish\":int}\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:21:25.228793Z","iopub.execute_input":"2022-11-04T14:21:25.229297Z","iopub.status.idle":"2022-11-04T14:21:33.806241Z","shell.execute_reply.started":"2022-11-04T14:21:25.229265Z","shell.execute_reply":"2022-11-04T14:21:33.805249Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"race_table.head()\n","metadata":{"execution":{"iopub.status.busy":"2022-11-04T14:21:33.809134Z","iopub.execute_input":"2022-11-04T14:21:33.809904Z","iopub.status.idle":"2022-11-04T14:21:33.838107Z","shell.execute_reply.started":"2022-11-04T14:21:33.809860Z","shell.execute_reply":"2022-11-04T14:21:33.836844Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"start_table.head(15)\n","metadata":{"execution":{"iopub.status.busy":"2022-11-04T14:21:33.839637Z","iopub.execute_input":"2022-11-04T14:21:33.840024Z","iopub.status.idle":"2022-11-04T14:21:33.857258Z","shell.execute_reply.started":"2022-11-04T14:21:33.839991Z","shell.execute_reply":"2022-11-04T14:21:33.855834Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tracking_table.head(5)","metadata":{"execution":{"iopub.status.busy":"2022-11-04T14:21:33.858991Z","iopub.execute_input":"2022-11-04T14:21:33.859478Z","iopub.status.idle":"2022-11-04T14:21:33.879607Z","shell.execute_reply.started":"2022-11-04T14:21:33.859429Z","shell.execute_reply":"2022-11-04T14:21:33.878281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Replace & Fix","metadata":{}},{"cell_type":"markdown","source":"**The hour column has been fixed. The content abbreviations of the track condition and course type columns have been fixed.**","metadata":{}},{"cell_type":"code","source":"race_table['post_time']=race_table['post_time'].astype(str).apply(lambda x: str(x[0])+str(x[1])+':'+str(x[2])+str(x[3]) if len(str(x))!=3 else str(0)+str(x[0])+':'+str(x[1])+str(x[2]))\nrace_table['track_condition']=race_table['track_condition'].astype(str).apply(lambda x: str(x[:-1]))\ntrack_condition_head={'YL':'Yielding', 'FM':'Firm', 'SY':'Sloppy', 'GD':'Good', 'FT':'Fast', 'MY':'Muddy', 'SF':'Soft'}\ncourse_type_head={'M':'Hurdle', 'D':'Dirt', 'O':'Outer turf', 'I':'Inner turf', 'T':'turf'}\nrace_table['track_condition'].replace(track_condition_head,inplace=True)\nrace_table['course_type'].replace(course_type_head,inplace=True)\nrace_table.head(5)\n","metadata":{"execution":{"iopub.status.busy":"2022-11-04T14:21:33.881262Z","iopub.execute_input":"2022-11-04T14:21:33.882273Z","iopub.status.idle":"2022-11-04T14:21:33.922973Z","shell.execute_reply.started":"2022-11-04T14:21:33.882208Z","shell.execute_reply":"2022-11-04T14:21:33.922012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"merged_df=start_table.merge(tracking_table,on=['track_id','race_date','race_number','program_number'],how='inner')\\\n                             .merge(race_table,on=['track_id','race_date','race_number'],how='inner')\n\nmerged_df['race_date']=pd.to_datetime(merged_df['race_date'],format='%Y-%m-%d')\nstart_table['race_date']=pd.to_datetime(start_table['race_date'],format='%Y-%m-%d')\nrace_table['race_date']=pd.to_datetime(race_table['race_date'],format='%Y-%m-%d')\nmerged_df.head(5)","metadata":{"execution":{"iopub.status.busy":"2022-11-04T14:21:33.924259Z","iopub.execute_input":"2022-11-04T14:21:33.924987Z","iopub.status.idle":"2022-11-04T14:21:42.853859Z","shell.execute_reply.started":"2022-11-04T14:21:33.924740Z","shell.execute_reply":"2022-11-04T14:21:42.852621Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h1 style=\"text-align:left;font-size:200%;\"><a id='DFuture' > Dedection Future Types </a></h1> \n","metadata":{}},{"cell_type":"markdown","source":"**I had to separate Future Types for both an overview and use in other functions.**","metadata":{}},{"cell_type":"code","source":"def dedect_features(df,nc_th=15,cn_th=20,title='Features Type Summary'):\n    '''\n    Parameters\n    ----------\n    df : DataFrame\n        Main Df\n    nc_th : Integer, \n        Numeric but categorical threshold limit. The default is 15.\n    cn_th : Integer, \n        Categorical but numeric threshold limit. The default is 20.\n\n    Returns\n    -------\n    date_cols : List\n        Date Types Columns List.\n    num_but_cat : List\n        Numeric but Categorical Types Columns List.\n    cat_col : List\n        Categorical Types Columns List.\n    cat_but_num : List\n        Categorical but Numeric Columns List.\n    num_col : List\n        Date Types Columns List.\n\n    '''\n    date_cols=[col for col in df if df[col].dtypes==\"datetime64[ns]\"]\n    \n    num_but_cat=[col for col in df.select_dtypes(['float','integer']).columns if df[col].value_counts().shape[0]<nc_th]\n    cat_col=df.select_dtypes(['object','category']).columns.to_list()+num_but_cat\n    cat_but_num=[col for col in df.select_dtypes(['object','category']).columns if df[col].value_counts().shape[0]>cn_th]\n    cat_col=[col for col in cat_col if col not in cat_but_num]\n    \n    num_col=df.select_dtypes(['integer','float']).columns.to_list()\n    num_col=[col for col in num_col if col not in num_but_cat]\n    \n    fig0=go.Figure()\n    fig0.add_trace(go.Scatter(\n        x=[0.2,1.7,3.4,5.3],\n        y=[1.7, 1.7, 1.7, 1.7],\n        mode=\"text\",\n        text=[\"Date Cols\",\"Cardinal Cols\",\"Categorical Cols\",\"Numeric Columns\", \"Numeric but Cat. Columns\"],\n        textposition=\"bottom center\"\n        ))\n    \n    fig0.add_trace(go.Scatter(\n    x=[0.2,1.7,3.4,5.3],\n    y=[1.1, 1.1, 1.1, 1.1],\n    mode=\"text\", \n    text=[\"<span style='font-size:24px'><b>\"+ str(len(date_cols)) +\"</b></span>\", \n          \"<span style='font-size:24px'><b>\"+ str(len(cat_but_num)) +\"</b></span>\",\n          \"<span style='font-size:24px'><b>\"+ str(len(cat_col)) + \"</b></span>\",\n          \"<span style='font-size:24px'><b>\"+ str(len(num_col)) + \"</b></span>\",\n          \"<span style='font-size:24px'><b>\"+ str(len(num_but_cat)) + \"</b></span>\",\n          \"<span style='font-size:24px'><b>17</b></span>\"],\n    textposition=\"bottom center\"\n        ))\n    fig0.add_hline(y=2.2, line_width=5, line_color='orange')\n    fig0.add_hline(y=0.3, line_width=3, line_color='orange')\n    fig0.add_trace(go.Scatter(\n        x=[3.2],\n        y=[-0.2],\n        mode=\"text\",\n        text=[\"<span style='font-size:18px'><b>Total Columns: \"+str(df.shape[1])+\"</b></span>\"],\n        textposition=\"bottom center\"\n        ))\n    fig0.update_yaxes(visible=False)\n    fig0.update_xaxes(visible=False)\n    fig0.update_layout(showlegend=False, height=300, width=900, \n                  title=title, title_x=0.5, title_y=0.9,\n                  xaxis_range=[-0.5,6.6], yaxis_range=[-1.2,2.2],\n                  plot_bgcolor='#424242', paper_bgcolor='#424242',\n                  font=dict(size=20, color='#fff0f5'),\n                  title_font=dict(size=28, color='#F5F5DC'),\n                  margin=dict(t=90,l=30,b=0,r=30), \n    )\n    fig0.show()\n    \n    return date_cols,num_but_cat,cat_col,cat_but_num,num_col\ndfs_features_type={'race_table':[],'start_table':[],'tracking_table':[],'merged_df':[]}\n\ndate_cols,num_but_cat,cat_col,cat_but_num,num_col=dedect_features(race_table,title='Race Table Features Type Summary')\ndfs_features_type['race_table']={'date_col':date_cols,'num_but_cat':num_but_cat,'cardinal':cat_but_num,'cat_col':cat_col,'numeric':num_col}\n\ndate_cols,num_but_cat,cat_col,cat_but_num,num_col=dedect_features(start_table,title='Start Table Features Type Summary')\ndfs_features_type['start_table']={'date_col':date_cols,'num_but_cat':num_but_cat,'cardinal':cat_but_num,'cat_col':cat_col,'numeric':num_col}\n\ndate_cols,num_but_cat,cat_col,cat_but_num,num_col=dedect_features(tracking_table,title='Tracking Table Features Type Summary')\ndfs_features_type['tracking_table']={'date_col':date_cols,'num_but_cat':num_but_cat,'cardinal':cat_but_num,'cat_col':cat_col,'numeric':num_col}\n\ndate_cols,num_but_cat,cat_col,cat_but_num,num_col=dedect_features(merged_df,title='Merged All Tables Features Type Summary')\ndfs_features_type['merged_df']={'date_col':date_cols,'num_but_cat':num_but_cat,'cardinal':cat_but_num,'cat_col':cat_col,'numeric':num_col}","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:21:42.855501Z","iopub.execute_input":"2022-11-04T14:21:42.856243Z","iopub.status.idle":"2022-11-04T14:21:57.980503Z","shell.execute_reply.started":"2022-11-04T14:21:42.856185Z","shell.execute_reply":"2022-11-04T14:21:57.979116Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# EDA ( Explotory Data Analysis )\n","metadata":{}},{"cell_type":"markdown","source":"***The first thing I can say for EDA is that the Finish line must have clear coordinates. If we had this valuable data, new features such as the effect of the ground condition on the horses and the creation of a ground coefficient could be created. I conducted an in-depth analysis in detail. You can read my findings from time to time.***\n\n***I took a general-to-specific approach as a flow. As you scroll down, you will encounter more in-depth reviews.***","metadata":{}},{"cell_type":"code","source":"start_race=start_table.merge(race_table,on=['track_id','race_date','race_number'],how='inner')\ndef first_and_last(start_race):\n    col=['track_id','race_date','race_number','jockey','position_at_finish']\n    \n    first_placement=start_race[start_race['position_at_finish']==min(start_race['position_at_finish'])][['track_id','race_date','race_number','track_condition','course_type' ,'jockey']]\n    #win_index=start_race[start_race['position_at_finish']==min(start_race['position_at_finish'])].index\n    #start_race.loc[win_index,'winner']=int(1)\n    #start_race.fillna(0,inplace=True)\n    \n    last_placement=start_race[~(start_race['position_at_finish']==min(start_race['position_at_finish']))][['track_id','race_date','race_number','track_condition','course_type' ,'jockey']]\n    j=start_race[col]              \n    #last_placement=start_race.groupby(['race_date','race_number'],as_index=False)['position_at_finish'].max()\n    #last_placement=last_placement.merge(start_race,on=['race_date','race_number','position_at_finish'],how='inner')\n    count_first_placement=first_placement[['track_id','track_condition','course_type','jockey']].value_counts().sort_index(level=['track_id'],ascending=True).sort_values(ascending=False)\n    count_first_placement=count_first_placement.reset_index(name='win_counts')\n    count_last_placement=last_placement[['track_id','track_condition','course_type','jockey']].value_counts().sort_index(level=['track_id'],ascending=True).sort_values(ascending=False)\n    count_last_placement=count_last_placement.reset_index(name='lose_counts')\n    return start_race,first_placement,last_placement,count_first_placement,count_last_placement\nstart_race,first_placement,last_placement,count_first_placement,count_last_placement=first_and_last(start_race)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**In general, it has been observed that the races are spread over 2 location.**","metadata":{}},{"cell_type":"code","source":"track_idcount=race_table['track_id'].value_counts()\nfig=px.bar(x=track_idcount.index,y=track_idcount,color=track_idcount.index,text_auto=True)\nfig.update_layout(title_text='<b>'+'Race Count For Per Track Id '+'</b>',\n                                      title_x=0.5,\n                                      xaxis_title=\"Track Name\", \n                                      yaxis_title=\"Race Count\",\n                                      paper_bgcolor='#232425',\n                                      plot_bgcolor='#232425',\n                                      font_color=\"white\",\n                                      title_font_color=\"#00FFFF\",\n                                      legend_title_font_color=\"white\",\n                                      font=dict(\n                                          family=\"Courier New, monospace\",\n                                          size=18\n                                          ),\n                                         )\nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:21:58.055028Z","iopub.execute_input":"2022-11-04T14:21:58.055378Z","iopub.status.idle":"2022-11-04T14:21:58.965824Z","shell.execute_reply.started":"2022-11-04T14:21:58.055348Z","shell.execute_reply":"2022-11-04T14:21:58.964582Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### ***Number of races by date.***","metadata":{}},{"cell_type":"code","source":"#Source: https://www.kaggle.com/code/alejopaullier/big-data-derby-2022-eda?scriptVersionId=103214099&cellId=21\n\nDAYS = ['Sun.', 'Mon.', 'Tues.', 'Wed.', 'Thurs.', 'Fri.', 'Sat.']\nMONTHS = ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'June', 'July', 'Aug.', 'Sept.', 'Oct.', 'Nov.', 'Dec.']\n\n\ndef date_heatmap(series, start=None, end=None, mean=False, ax=None, **kwargs):\n    '''Plot a calendar heatmap given a datetime series.\n\n    Arguments:\n        series (pd.Series):\n            A series of numeric values with a datetime index. Values occurring\n            on the same day are combined by sum.\n        start (Any):\n            The first day to be considered in the plot. The value can be\n            anything accepted by :func:`pandas.to_datetime`. The default is the\n            earliest date in the data.\n        end (Any):\n            The last day to be considered in the plot. The value can be\n            anything accepted by :func:`pandas.to_datetime`. The default is the\n            latest date in the data.\n        mean (bool):\n            Combine values occurring on the same day by mean instead of sum.\n        ax (matplotlib.Axes or None):\n            The axes on which to draw the heatmap. The default is the current\n            axes in the :module:`~matplotlib.pyplot` API.\n        **kwargs:\n            Forwarded to :meth:`~matplotlib.Axes.pcolormesh` for drawing the\n            heatmap.\n\n    Returns:\n        matplotlib.collections.Axes:\n            The axes on which the heatmap was drawn. This is set as the current\n            axes in the `~matplotlib.pyplot` API.\n    '''\n    # Combine values occurring on the same day.\n    dates = series.index.floor('D')\n    group = series.groupby(dates)\n    series = group.mean() if mean else group.sum()\n\n    # Parse start/end, defaulting to the min/max of the index.\n    start = pd.to_datetime(start or series.index.min())\n    end = pd.to_datetime(end or series.index.max())\n\n    # We use [start, end) as a half-open interval below.\n    end += np.timedelta64(1, 'D')\n\n    # Get the previous/following Sunday to start/end.\n    # Pandas and numpy day-of-week conventions are Monday=0 and Sunday=6.\n    start_sun = start - np.timedelta64((start.dayofweek + 1) % 7, 'D')\n    end_sun = end + np.timedelta64(7 - end.dayofweek - 1, 'D')\n\n    # Create the heatmap and track ticks.\n    num_weeks = (end_sun - start_sun).days // 7\n    heatmap = np.zeros((7, num_weeks))\n    ticks = {}  # week number -> month name\n    for week in range(num_weeks):\n        for day in range(7):\n            date = start_sun + np.timedelta64(7 * week + day, 'D')\n            if date.day == 1:\n                ticks[week] = MONTHS[date.month - 1]\n            if date.dayofyear == 1:\n                ticks[week] += f'\\n{date.year}'\n            if start <= date < end:\n                heatmap[day, week] = series.get(date, 0)\n\n    # Get the coordinates, offset by 0.5 to align the ticks.\n    y = np.arange(8) - 0.5\n    x = np.arange(num_weeks + 1) - 0.5\n\n    # Plot the heatmap. Prefer pcolormesh over imshow so that the figure can be\n    # vectorized when saved to a compatible format. We must invert the axis for\n    # pcolormesh, but not for imshow, so that it reads top-bottom, left-right.\n    ax = ax or plt.gca()\n    mesh = ax.pcolormesh(x, y, heatmap, **kwargs)\n    ax.invert_yaxis()\n\n    # Set the ticks.\n    ax.set_xticks(list(ticks.keys()))\n    ax.set_xticklabels(list(ticks.values()))\n    plt.setp(ax.get_xticklabels(), color=\"white\")\n    ax.set_yticks(np.arange(7))\n    ax.set_yticklabels(DAYS)\n    plt.setp(ax.get_yticklabels(), color=\"white\")\n    plt.setp(ax.get_yticklabels(), color=\"white\")\n\n    # Set the current image and axes in the pyplot API.\n    plt.sca(ax)\n    plt.sci(mesh)\n\n    return ax\n\n\n# # Get some data, a series of values with datetime index.\n# data = np.random.randint(5, size=365)\n# data = pd.Series(data)\n# data.index = pd.date_range(start='2017-01-01', end='2017-12-31', freq='1D')\n\nrace_table[\"race_date\"] =  pd.to_datetime(race_table[\"race_date\"], format='%Y-%m-%d')\ndata = race_table[\"race_date\"].value_counts()\n\n# Create the figure. For the aspect ratio, one year is 7 days by 53 weeks.\n# We widen it further to account for the tick labels and color bar.\nfigsize = plt.figaspect(8 / 50)\nfig = plt.figure(figsize=(figsize),facecolor='#232425')\n\n# Plot the heatmap with a color bar.\nax = date_heatmap(data, edgecolor='white')\ncb=plt.colorbar(ticks=range(max(data.values)), pad=0.02)\ncb.ax.yaxis.set_tick_params(color='white')\ncmap = plt.cm.get_cmap('turbo', 6)\nplt.setp(plt.getp(cb.ax.axes, 'yticklabels'), color='white')\nplt.set_cmap(cmap)\n# Force the cells to be square. If this is set, the size of the color bar\n# may look weird compared to the size of the heatmap. That can be corrected\n# by the aspect ratio of the figure or scale of the color bar.\nax.set_aspect('auto')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:21:58.967554Z","iopub.execute_input":"2022-11-04T14:21:58.967940Z","iopub.status.idle":"2022-11-04T14:21:59.338172Z","shell.execute_reply.started":"2022-11-04T14:21:58.967908Z","shell.execute_reply":"2022-11-04T14:21:59.336509Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"***Let's dig a little deeper. Race distributions according to Track condition / Course Type on the tracks are as in the figure. Most of the races are Course Type Dirt for all tracks.***","metadata":{}},{"cell_type":"code","source":"track_idcount=race_table[['track_id','course_type','track_condition']].value_counts().sort_index(level=0)\ntypes_condition=race_table.groupby(['track_id','course_type','track_condition'],as_index=False)['race_number'].count()\nfig=px.bar(types_condition,x='track_condition',y='race_number',facet_col='course_type',color='track_id',barmode='group')\nfig.update_layout(title_text='<b>'+'Course Type / Track Condition Race Count On Track Id '+'</b>',\n                                      title_x=0.5,\n                                      paper_bgcolor='#232425',\n                                      plot_bgcolor='#232425',\n                                      font_color=\"white\",\n                                      title_font_color=\"#00FFFF\",\n                                      legend_title_font_color=\"white\",\n                                      font=dict(\n                                          family=\"Courier New, monospace\",\n                                          size=18\n                                          ),\n                                         )\nfig.for_each_annotation(lambda a: a.update(text=a['text'].split('=')[1]))\nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:21:59.341435Z","iopub.execute_input":"2022-11-04T14:21:59.342710Z","iopub.status.idle":"2022-11-04T14:21:59.569246Z","shell.execute_reply.started":"2022-11-04T14:21:59.342638Z","shell.execute_reply":"2022-11-04T14:21:59.567892Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"***Let's take a look at how many races jockeys run. Here, we can say that the jockeys who competed over 100 races statistically obtained a general statistics. As the number of races is low, the race they win has a great effect on the win rate. ***","metadata":{}},{"cell_type":"code","source":"jockey_racecount=start_race['jockey'].value_counts()\nfig=px.bar(x=jockey_racecount.index,y=jockey_racecount)\nfig.update_layout(title_text='<b>'+'Race Count For Per Jockey'+'</b>',\n                                      title_x=0.5,\n                                      height=800,\n                                      xaxis_title=\"Jockey Name\", \n                                      yaxis_title=\"Race Count\",\n                                      paper_bgcolor='#232425',\n                                      plot_bgcolor='#232425',\n                                      font_color=\"white\",\n                                      title_font_color=\"#00FFFF\",\n                                      legend_title_font_color=\"white\",\n                                      font=dict(\n                                          family=\"Courier New, monospace\",\n                                          size=18\n                                          ),\n                                         )\nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:21:59.570699Z","iopub.execute_input":"2022-11-04T14:21:59.571109Z","iopub.status.idle":"2022-11-04T14:21:59.652317Z","shell.execute_reply.started":"2022-11-04T14:21:59.571076Z","shell.execute_reply":"2022-11-04T14:21:59.651123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"def jockey_stat(count_first_placement,count_last_placement,j_name,th):\n    first_j_name_stat=count_first_placement[count_first_placement['jockey']==j_name]\n    last_j_name_stat=count_last_placement[count_last_placement['jockey']==j_name]\n    \n    if (int(first_j_name_stat['win_counts'].sum())+int(last_j_name_stat['lose_counts'].sum()))<th:\n        return print('Not enough race count <'+str(th)+' for ---> '+j_name + '\\n'  )\n    else:\n        fig=px.bar(first_j_name_stat,x='track_condition',y='win_counts',facet_col='course_type',color='track_id',barmode='group',text='win_counts')\n        fig.update_traces(textposition='outside', textfont_size=11,textangle=90)\n        fig.update_yaxes(showgrid=True, gridwidth=0.75, gridcolor='LightPink')\n        \n        fig1=px.bar(last_j_name_stat,x='track_condition',y='lose_counts',facet_col='course_type',color='track_id',barmode='group',text='lose_counts')\n        fig1.update_traces(textposition='outside', textfont_size=13,textangle=90)\n        fig1.update_yaxes(showgrid=True, gridwidth=0.75, gridcolor='LightPink')\n        \n        fig.update_layout(title_text='<b>'+j_name+' Winner Stats '+'</b>',\n                                      title_x=0.5,\n                                      paper_bgcolor='#232425',\n                                      plot_bgcolor='#232425',\n                                      font_color=\"white\",\n                                        width=800,\n                                      title_font_color=\"#00FFFF\",\n                                      legend_title_font_color=\"white\",\n                                      font=dict(\n                                          family=\"Courier New, monospace\",\n                                          size=18\n                                          ),\n                                         )\n        fig1.update_layout(title_text='<b>'+j_name+' Loser Stats '+'</b>',\n                                      title_x=0.5,\n                                      paper_bgcolor='#232425',\n                                       width=800,\n                                      plot_bgcolor='#232425',\n                                      font_color=\"white\",\n                                      title_font_color=\"#D70040\",\n                                      legend_title_font_color=\"white\",\n                                      font=dict(\n                                          family=\"Courier New, monospace\",\n                                          size=18),\n                                         )\n        fig.for_each_annotation(lambda a: a.update(text=a['text'].split('=')[1]))\n        fig.show()\n        \n        fig1.for_each_annotation(lambda a: a.update(text=a['text'].split('=')[1]))\n        fig1.show()\n        print('\\n')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T18:14:18.393969Z","iopub.execute_input":"2022-11-04T18:14:18.394365Z","iopub.status.idle":"2022-11-04T18:14:18.413494Z","shell.execute_reply.started":"2022-11-04T18:14:18.394334Z","shell.execute_reply":"2022-11-04T18:14:18.411297Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"***And a little deeper..\nWe talked about the win rate. Let's take a look at the winrates of each jockey according to the Course Type / Track condition. Here, circle size represents the total number of races attended. We can see that there is no data in some types. When we look in general, we can see that Manuel Franco raced with a winrate of 0.227 in 317 races, for example, in Dirt type and Fast track condition on the Aquduct track. And we can say that it is in the leading position as winrate in Sloppy / Dirt.***\n\n***Individual names can be selected from the Jockey Name list.***","metadata":{}},{"cell_type":"code","source":"start_race,first_placement,last_placement,count_first_placement,count_last_placement=first_and_last(start_race)\nwfirst_placement=count_first_placement.sort_values(['track_id','course_type']).set_index(['track_id','course_type','track_condition','jockey'])\nwlast_placement=count_last_placement.sort_values(['track_id','course_type']).set_index(['track_id','course_type','track_condition','jockey'])\nfor index in wlast_placement.index:\n    try:\n        wlast_placement.loc[index,'win_rate']=wfirst_placement.loc[index]['win_counts']/(wfirst_placement.loc[index]['win_counts']+wlast_placement.loc[index]['lose_counts'])\n        wlast_placement.loc[index,'race_count']=wfirst_placement.loc[index]['win_counts']+wlast_placement.loc[index]['lose_counts']\n    except KeyError:\n        try:\n            wlast_placement.loc[index]['lose_counts']\n            wlast_placement.loc[index,'win_rate']=0\n        except KeyError:\n            wlast_placement.loc[index,'win_rate']=1\n        \nwlast_placement.fillna(0,inplace=True)\nwlast_placement.reset_index(inplace=True)\n\nabove_150=wlast_placement[wlast_placement['race_count']>30]\n\nfig=px.scatter(above_150,y='win_rate',x='track_id',color='jockey',facet_col='track_condition',facet_row='course_type',size='race_count')\nfig.update_layout(title_text='<b>'+' Win Rate Charts for Track Condition / Course Type Per Jockey '+'</b>',\n                                  title_font=dict(color='#AD2B10'),\n                                  height=1000,\n                                  width=1000,\n                                  title_x=0.5,\n                                  showlegend=False,\n                                  \n                                  paper_bgcolor='#232425',\n                                  plot_bgcolor='#232425',\n                                  font=dict(\n                                      family=\"Courier New, monospace\",\n                                      size=18,\n                                      color='white'),\n                                  \n                  updatemenus=[\n                                {\n                                    \"buttons\": [\n                                        {\n                                            \"label\": m,\n                                            \"method\": \"update\",\n                                            \"args\": [\n                                                {\n                                                    \"visible\": [\n                                                        True if m == \"All\" else t.name == m for t in fig.data\n                                                    ]\n                                                }\n                                                \n                                            ],\n                                            \n                                        }\n                                        for m in [\"All\"] + above_150[\"jockey\"].unique().tolist()\n                                    ],\n                                    'font' : dict(color='LightPink'),\n                                    'pad':{\"l\": 0, \"r\": 20, \"t\":25 , \"b\": 0}\n                                }\n                            ],\n                  \n                  \n                                     )\n\n\nfig['data'][0]\nfig['layout']\nfig.update_yaxes(showgrid=True,gridwidth=0.75, gridcolor='LightPink')\nfig.update_xaxes(showgrid=False)\nfig.for_each_annotation(lambda a: a.update(text=a['text'].split('=')[1]))\nfig.add_annotation(dict(text='Select Jockey Name: ', x=-0.46, y=1.005, xref='paper',yref='paper', align='left', showarrow=False,font=dict(size=18)))\nfig.update_xaxes(showticklabels=True)\nfig.show()\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:21:59.673959Z","iopub.execute_input":"2022-11-04T14:21:59.674436Z","iopub.status.idle":"2022-11-04T14:22:01.974993Z","shell.execute_reply.started":"2022-11-04T14:21:59.674398Z","shell.execute_reply":"2022-11-04T14:22:01.973650Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"***Here, we have discussed the winning stats and losing stats of the horses competing the most, which can be examined in more detail here. The number of races was taken as 350 and above. You can see in the output that jockeys with less than 350 races are not plotted.***","metadata":{}},{"cell_type":"code","source":"for j in count_first_placement['jockey'].unique():\n    jockey_stat(count_first_placement,count_last_placement,j,350)","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2022-11-04T14:22:01.976589Z","iopub.execute_input":"2022-11-04T14:22:01.978029Z","iopub.status.idle":"2022-11-04T14:22:08.003509Z","shell.execute_reply.started":"2022-11-04T14:22:01.977729Z","shell.execute_reply":"2022-11-04T14:22:08.002151Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def select_race(df,race_date,track_id,race_number):  \n    '''\n    Filters the desired race from the merged DataFrame. Returns the filtered DataFrame and Jockey coordinates.\n\n    Parameters\n    ----------\n    df : TYPE DataFrame.\n        Merged Dataframe.\n    race_date : TYPE String.\n    track_id : TYPE String.\n    race_number : TYPE Int.\n        \n    Returns\n    -------\n    first : TYPE DataFrame\n    jockey_cordinants : TYPE Dict\n      \n    '''\n    first=merged_df[(merged_df['race_date']==race_date) & (merged_df['track_id']==track_id) & (merged_df['race_number']==race_number)]\n    a=first['jockey'].value_counts()\n    jockey_cordinants=[]\n\n    first.set_index('trakus_index',drop=True,inplace=True)\n    first=first.sort_index()\n    first.reset_index(drop=True,inplace=True)\n    for i in a.index:\n        jockey_cordinants.append(first[first['jockey']==i][['latitude','longitude']].reset_index(drop=True))\n\n    first.head()\n    return first,jockey_cordinants\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:22:08.005310Z","iopub.execute_input":"2022-11-04T14:22:08.005764Z","iopub.status.idle":"2022-11-04T14:22:08.018649Z","shell.execute_reply.started":"2022-11-04T14:22:08.005722Z","shell.execute_reply":"2022-11-04T14:22:08.016944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"***Let's see how a race is played as a simulation.***","metadata":{}},{"cell_type":"code","source":"first,jockey_cordinants=select_race(merged_df,'2019-01-04','AQU',4)\ndef sim_chart(jockey_cordinants,df):\n    j_0_y=jockey_cordinants[0]['longitude']\n    j_0_x=jockey_cordinants[0]['latitude']\n    \n    a=first['jockey'].value_counts()\n    \n    j_0_y_min=np.min(j_0_y)-0.00050\n    j_0_y_max=np.max(j_0_y)+0.00050\n    j_0_x_min=np.min(j_0_x)-0.00020\n    j_0_x_max=np.max(j_0_x)+0.00020\n    \n    fig = go.Figure(\n    data=[\n        go.Scatter(x=jockey_cordinants[i]['latitude'],y=jockey_cordinants[i]['longitude'],\n                     mode=\"lines\",\n                     name=a.index[i],\n                     line=dict(width=0.1, color=colors[i])) for i in range(len(jockey_cordinants))]+[go.Scatter(x=df[df['jockey']==df[df['latitude']==min(df['latitude'])]['jockey'].iloc[0]]['latitude'],\n                         y=df[df['jockey']==df[df['latitude']==min(df['latitude'])]['jockey'].iloc[0]]['longitude'],\n                         mode=\"lines\",\n                         name='Track',\n                         line=dict(width=1.4, color=\"black\"))],\n    \n    layout=go.Layout(\n        xaxis=dict(range=[j_0_x_max, j_0_x_min], autorange=False, zeroline=False),\n        yaxis=dict(range=[j_0_y_min, j_0_y_max], autorange=False, zeroline=False),\n        title_text=\"Race type : {} - Track : {} - Race Date : {} - Distance : {} - Course : {}\".format(df['race_type'][0],\n                                    df['track_id'][0],df['race_date'][0],df['distance_id'][0],df['course_type'][0]), hovermode=\"closest\",\n        updatemenus=[dict(type=\"buttons\",\n                          buttons=[dict(label=\"Play\",\n                                        method=\"animate\",\n                                        args=[None,{\"frame\": {\"duration\": 10,},\n                                                   }])\n\n                                  ])],\n\n        ),\n    frames=[\n        go.Frame(\n            data=[\n                go.Scatter(\n                    x=[jockey_cordinants[i]['latitude'][k]],\n                    y=[jockey_cordinants[i]['longitude'][k]],\n                    mode=\"markers\",\n                    marker=dict(size=7,color=colors[i])) for i in range(len(jockey_cordinants))],\n               )\n\n        for k in range(int(jockey_cordinants[0].index.max()))]\n\n    )\n\n    fig.show()\n%time sim_chart(jockey_cordinants,first)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:22:08.020616Z","iopub.execute_input":"2022-11-04T14:22:08.021112Z","iopub.status.idle":"2022-11-04T14:22:10.928405Z","shell.execute_reply.started":"2022-11-04T14:22:08.021068Z","shell.execute_reply":"2022-11-04T14:22:10.926989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"first,jockey_cordinants=select_race(merged_df,'2019-01-04','AQU',1)\n%time sim_chart(jockey_cordinants,first)","metadata":{"execution":{"iopub.status.busy":"2022-11-04T14:22:10.930457Z","iopub.execute_input":"2022-11-04T14:22:10.930916Z","iopub.status.idle":"2022-11-04T14:22:13.442350Z","shell.execute_reply.started":"2022-11-04T14:22:10.930873Z","shell.execute_reply":"2022-11-04T14:22:13.441240Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Jockey Ranking in Furlongs\n","metadata":{}},{"cell_type":"code","source":"def cordinants_per_furlong(df,jockey_cordinants):\n    '''\n    Parameters\n    ----------\n    df : Selected race dataframe returning from select_race function\n    jockey_cordinants : TYPE\n        DESCRIPTION.\n\n    Returns\n    -------\n    position_cordinants_per_furlong : TYPE dict.\n        Coordinates of jockeys at furlong points.\n\n    furlongs_split : TYPE List.\n        Furlong name list.\n\n    per_furlong_pos_index : TYPE List.\n        Furlong position indexes.\n\n    '''\n    #furlongs_interval list\n    furlong=int((first['distance_id'].value_counts().index/100)[0])+1\n    furlongs_split=[i for i in range(1,furlong+1)]\n    furlongs_split.insert(0,'Start')\n    if furlong % round(furlong,0)!=0:\n        furlongs_split.insert(len(furlongs_split),'Finish')\n    else:\n        furlongs_split.insert(-1,'Finish')\n        furlongs_split.pop(-1)\n    fur=first['distance_id'][0]/100 #How many furlongs \n    fur_meters=201.1684 # furlong meters\n    \n    pist_size=fur_meters*(fur) # pist long length\n    index_size=jockey_cordinants[0].shape[0] # trakus index length\n    per_furlong=pist_size/index_size # Calculating how many meters data is received\n    \n    per_index_one_furlongs=int(np.round(fur_meters/per_furlong,0)) #Furlong is reached in which index\n    \n    #Furlong index list\n    per_furlong_pos_index=[i*per_index_one_furlongs for i in range(int(fur)+1)]\n    per_furlong_pos_index.insert(len(per_furlong_pos_index),per_furlong_pos_index[-1]+(index_size-per_furlong_pos_index[-1]-1))\n    per_furlong_pos_index.pop(-2)\n    position_cordinants_per_furlong={str(i): [] for i in df.jockey.value_counts().index}\n    \n    \n    for num,val in enumerate(position_cordinants_per_furlong.keys()):\n        l=[]\n        for n,i in enumerate(per_furlong_pos_index):\n            if int(jockey_cordinants[num].index[-1])!=per_furlong_pos_index[-1]:\n                miss=[i for i in per_furlong_pos_index if i>int(jockey_cordinants[num].index[-1])]\n                a=pd.concat([pd.DataFrame([np.nan], columns=['latitude'],index=[i]) for i in range(int(jockey_cordinants[num].index[-1])+1,miss[-1]+1)])\n                b=pd.concat([pd.DataFrame([np.nan], columns=['longitude'],index=[i]) for i in range(int(jockey_cordinants[num].index[-1])+1,miss[-1]+1)])\n                ab=pd.concat([a,b],axis=1)\n                jockey_cordinants[num]=pd.concat([jockey_cordinants[num],ab],axis=0)\n                jockey_cordinants[num].fillna(method='ffill',inplace=True)\n            l.append(jockey_cordinants[num].loc[i])   \n        position_cordinants_per_furlong[val]=l\n        \n    return position_cordinants_per_furlong,furlongs_split,per_furlong_pos_index\n\ndef get_origin(df):\n    '''\n    Parameters\n    ----------\n    df : TYPE DataFrame.\n       Selected race dataframe returning from select_race function.\n\n    Returns\n    -------\n    xmax_y : TYPE float.\n       Y coordinate corresponding to the max value of the X coordinate of the runway..\n    xmin_y : TYPE float.\n        Y coordinate corresponding to the min value of the X coordinate of the runway..\n    origin_x : TYPE float.\n        X coordinate of the center point of the runway.\n    origin_y : TYPE float.\n        Y coordinate of the center point of the runway.\n\n    '''\n    pist_cord=first[first['jockey']==first[first['latitude']==min(first['latitude'])]['jockey'].iloc[0]]\n    x_max=pist_cord['latitude'].max()\n    x_min=pist_cord['latitude'].min()\n    y_max=pist_cord['longitude'].max()\n    y_min=pist_cord['longitude'].min()\n    origin_x= (x_max+x_min)/2\n    xmax_y=pist_cord[pist_cord['latitude']==x_max]['longitude'].iloc[0]\n    xmin_y=pist_cord[pist_cord['latitude']==x_min]['longitude'].iloc[0]\n    origin_y=(y_max+y_min)/2\n    return xmax_y,xmin_y,origin_x,origin_y\n\ndef checkpoints_location(df,jockey_cordinants,per_furlong_pos_index,type=0):\n    '''\n    Parameters\n    ----------\n    df : TYPE DataFrame.\n       Selected race dataframe returning from select_race function.\n    jockey_cordinants : TYPE Dict.\n        Selected race  jockey coordinates ,dictionary returning from select_race function.\n    per_furlong_pos_index : TYPE List.\n        Furlong's index returning from cordinants_per_furlong functions.\n    type : TYPE Int, optional\n        No graphics. The default is 0.\n\n    Returns\n    -------\n    checkpoints_cordinant : TYPE\n        DESCRIPTION.\n\n    '''\n    checkpoints_cordinant={str(i): [] for i in first.jockey.value_counts().index}\n    for n,i in enumerate(checkpoints_cordinant.keys()):\n        checkpoints_cordinant[i]=jockey_cordinants[n].loc[per_furlong_pos_index]\n    #checkpoints_cordinant=rework(checkpoints_cordinant)\n    colors=['#5a6edc','#fc0da1','#fed400','#E60000','#4a00b5','#abd98c','#FF5733','#800080','#00FFFF','#00FF00']\n    if type!=1:\n        fig = go.Figure(\n            data=[\n                go.Scatter(x=df[df['jockey']==df[df['latitude']==min(df['latitude'])]['jockey'].iloc[0]]['latitude'],\n                             y=df[df['jockey']==df[df['latitude']==min(df['latitude'])]['jockey'].iloc[0]]['longitude'],\n                             mode=\"lines\",\n                             name='Track',\n                             line=dict(width=1.4, color=\"white\"))])\n        for num,val in enumerate(checkpoints_cordinant.keys()):\n            fig.add_trace(go.Scatter(x=checkpoints_cordinant[val]['latitude'],\n                                     y=checkpoints_cordinant[val]['longitude'],\n                                    mode=\"markers\",\n                                    name=val,\n                                    marker=dict(size=7,color=colors[num])))\n        fig.add_trace(go.Scatter(x=[origin_x],\n                                    y=[origin_y],\n                                    mode=\"markers\",\n                                    name=\"Origin\",\n                                    marker=dict(size=7,color='pink')))\n        fig.update_layout(title_text='<b>'+str(len(per_furlong_pos_index)-1)+' Furlong Checkpoint Jockey Position '+'</b>',\n                                  title_x=0.5,\n                                  paper_bgcolor='#232425',\n                                  plot_bgcolor='#232425',\n                                  font=dict(\n                                      family=\"Courier New, monospace\",\n                                      size=18,\n                                      color='white'),\n                                     )\n        fig.add_annotation(dict(font=dict(color='yellow',size=15),\n                                        x=-0.085,\n                                        y=1.15,\n                                        showarrow=False,\n                                        text='Track: '+first['track_id'][0]+' | '+'Race Date: '+str(first['race_date'][0].date())+' | '+'Race Number:'+str(first['race_number'][0]),\n                                        textangle=0,\n                                        xanchor='left',\n                                        xref=\"paper\",\n                                        yref=\"paper\"))\n        fig.update_xaxes(showgrid=False, gridwidth=0.75, gridcolor='LightPink')\n        fig.update_yaxes(showgrid=False, gridwidth=0.75, gridcolor='LightPink')\n        fig.show()\n    return checkpoints_cordinant\n    ","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:22:13.444336Z","iopub.execute_input":"2022-11-04T14:22:13.444692Z","iopub.status.idle":"2022-11-04T14:22:13.480144Z","shell.execute_reply.started":"2022-11-04T14:22:13.444661Z","shell.execute_reply":"2022-11-04T14:22:13.478864Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"xmax_y,xmin_y,origin_x,origin_y=get_origin(first)\nposition_cordinants_per_furlong,furlongs_split,per_furlong_pos_index=cordinants_per_furlong(first,jockey_cordinants)\ncheckpoints_cordinant=checkpoints_location(first,jockey_cordinants,per_furlong_pos_index)","metadata":{"execution":{"iopub.status.busy":"2022-11-04T14:22:13.482149Z","iopub.execute_input":"2022-11-04T14:22:13.482654Z","iopub.status.idle":"2022-11-04T14:22:13.546078Z","shell.execute_reply.started":"2022-11-04T14:22:13.482590Z","shell.execute_reply":"2022-11-04T14:22:13.544689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"first,jockey_cordinants=select_race(merged_df,'2019-01-01','AQU',1)\nposition_cordinants_per_furlong,furlongs_split,per_furlong_pos_index=cordinants_per_furlong(first,jockey_cordinants)\nxmax_y,xmin_y,origin_x,origin_y=get_origin(first)\ncheckpoints_cordinant=checkpoints_location(first,jockey_cordinants,per_furlong_pos_index)","metadata":{"execution":{"iopub.status.busy":"2022-11-04T14:22:13.547609Z","iopub.execute_input":"2022-11-04T14:22:13.548162Z","iopub.status.idle":"2022-11-04T14:22:13.975026Z","shell.execute_reply.started":"2022-11-04T14:22:13.548128Z","shell.execute_reply":"2022-11-04T14:22:13.973858Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# How the Calculate Furlong Positions ? \n\n* ***To find the order of the jockeys in the furlongs, I got each of the coordinate values ​​with a function that calculates the stance angles relative to each other.I would like to give a brief information about it.***\n\n* ***First, a function calculates the angle for each jockey relative to the other jockeys. Each jockey has his own coordinate system. I divided this coordinate system into 2 parts angularly. (270,0] & [0,90] Area-2 , (90,180] & [180,270] Area-1 is as in the figure. What happens in Area-2 is the competitors who stay in front of the Jockey. Area-1 is the competitors who stay behind. it adds up the angles of a jockey and defines the zones and performs the sequencing in another function.***\n\n![download.png](attachment:08fab928-b448-4d17-a8cd-457436096c0d.png)","metadata":{},"attachments":{"08fab928-b448-4d17-a8cd-457436096c0d.png":{"image/png":"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"}}},{"cell_type":"code","source":"def road_taken(df,jockey_cordinants,per_furlong_pos_index):\n    '''\n    Calculates the distance each jockey takes between furlongs and returns a dict that calculates the angle of each jockey relative to the other jockeys.\n\n    Parameters\n    ----------\n    df : Type DataFrame\n        Selected race dataframe returning from select_race function.\n    jockey_cordinants : TYPE dict\n        Selected race  jockey coordinates ,dictionary returning from select_race function.\n    per_furlong_pos_index : TYPE List\n        urlong's index returning from cordinants_per_furlong functions.\n\n    Returns\n    -------\n    jockey_dist_furlong: TYPE Dict.\n        Distance traveled between furlongs.\n        \n    jockey_angle_furlong: TYPE Dict.\n        The angle of each jockey relative to the other jockeys on furlongs.\n\n    '''\n    from math import radians, cos, sin, asin, sqrt,atan2,degrees\n    import itertools\n    \n    def haversine(lon1, lat1, lon2, lat2):\n        \"\"\"\n        Calculate the great circle distance in kilometers between two points \n        on the earth (specified in decimal degrees)\n        \"\"\"\n        from math import radians, cos, sin, asin, sqrt\n\n        # convert decimal degrees to radians \n        lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])\n\n        # haversine formula \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 * asin(sqrt(a)) \n        r = 6371 # Radius of earth in kilometers. Use 3956 for miles. Determines return value units.\n        return c * r\n    def initial_bearing(pointA, pointB):\n        \"\"\"\n        Parameters\n        ----------\n        pointA : TYPE Tuple.\n            X,Y Cordinants.\n        pointB : TYPE Tuple.\n            X,Y Cordinants.\n\n        Raises\n        ------\n        TypeError\n            Parameters if not tuple.\n\n        Returns\n        -------\n        compass_bearing : TYPE Float\n            Returns the angle.\n\n\n        \"\"\"\n        if (type(pointA) != tuple) or (type(pointB) != tuple):\n            raise TypeError(\"Only tuples are supported as arguments\")\n\n        lat1 = radians(pointA[0])\n        lat2 = radians(pointB[0])\n\n        diffLong = radians(pointB[1] - pointA[1])\n\n        x = sin(diffLong) * cos(lat2)\n        y = cos(lat1) * sin(lat2) - (sin(lat1)\n                * cos(lat2) * cos(diffLong))\n\n        initial_bearing = atan2(x, y)\n\n        # Now we have the initial bearing but math.atan2 return values\n        # from -180° to + 180° which is not what we want for a compass bearing\n        # The solution is to normalize the initial bearing as shown below\n        initial_bearing = degrees(initial_bearing)\n        compass_bearing = (initial_bearing + 360) % 360\n        \n        return compass_bearing\n    \n    jockey_dist_furlong={str(i): [] for i in per_furlong_pos_index}\n    jockey_angle_furlong={str(i): {} for i in per_furlong_pos_index}\n    \n    for index in per_furlong_pos_index:\n        ls=[]\n        a_s=[]\n        jockey_div=first.jockey.value_counts().index.to_list()\n        for n,jockey_n in enumerate(df.jockey.value_counts().index):\n            sum_dis=0\n            \n            \n            for i in range(0,index):\n                    x_f=jockey_cordinants[n]['latitude'].reset_index(drop=True).loc[i]\n                    y_f=jockey_cordinants[n]['longitude'].reset_index(drop=True).loc[i]\n                    x_s=jockey_cordinants[n]['latitude'].reset_index(drop=True).loc[i+1]\n                    y_s=jockey_cordinants[n]['longitude'].reset_index(drop=True).loc[i+1]\n                    #x_diff=x_f-x_s\n                    #y_diff=y_f-y_s\n                    sum_dis+=haversine(y_f,x_f,y_s,x_s)\n            ls.append(sum_dis)\n            x_f=jockey_cordinants[n]['latitude'].reset_index(drop=True).loc[index]\n            y_f=jockey_cordinants[n]['longitude'].reset_index(drop=True).loc[index]\n            \n            \n            for t,jockey_name in enumerate(jockey_div):\n                x_s=jockey_cordinants[t]['latitude'].reset_index(drop=True).loc[index]\n                y_s=jockey_cordinants[t]['longitude'].reset_index(drop=True).loc[index]\n                pA=(x_f,y_f)\n                pB=(x_s,y_s)\n                angle=initial_bearing(pA,pB)\n                a_s.append(angle)\n            jockey_angle_furlong[str(index)][jockey_n]=a_s\n            a_s=[]\n        jockey_dist_furlong[str(index)]=ls\n        \n    return jockey_dist_furlong,jockey_angle_furlong\n\ndef placement(xmax_y,xmin_y,origin_x,origin_y,checkpoints_cordinant,per_furlong_pos_index,angle_dict):\n    \"\"\"\n    Calculates the jockey rank in the furlongs.\n\n    Parameters\n    ----------\n    xmax_y : TYPE float.\n    xmin_y : TYPE float.\n    origin_x : TYPE float.\n    origin_y : TYPE float.\n    checkpoints_cordinant : TYPE dict.\n    per_furlong_pos_index : TYPE list.\n    angle_dict : TYPE dict.\n\n    Returns\n    -------\n    placement_val : TYPE dict.\n        Jockey rank in the furlongs.\n\n    \"\"\"\n    track=first[first['jockey']==first[first['latitude']==min(first['latitude'])]['jockey'].iloc[0]]['jockey'].iloc[0]\n    track_index=list(checkpoints_cordinant.keys()).index(track)\n    distance_dict={str(i) :[] for i in per_furlong_pos_index}\n    for num,index in enumerate(checkpoints_cordinant[list(checkpoints_cordinant.keys())[0]].index):\n        ls=[]\n        \n        for key in checkpoints_cordinant.keys():\n            x=checkpoints_cordinant[key]['latitude'][index]\n            y=checkpoints_cordinant[key]['longitude'][index]\n            ls.append([x,y,key])\n        distance_dict[str(per_furlong_pos_index[num])]=ls\n        \n    placement_val={str(i):['' for k in range(len(checkpoints_cordinant.keys()))] for i in distance_dict.keys()}\n    value_name_area_ls={str(i):[] for i in distance_dict.keys()}    \n    for key,value in distance_dict.items():\n        for j in range(len(value)):\n            if((origin_x>=value[j][0]) & (xmin_y<=value[j][1])): # 1 sector \n                value_name_area_ls[key].append([value[j][2],0])\n            else:\n                if((origin_x<value[j][0])&(xmax_y<value[j][1])):\n                    value_name_area_ls[key].append([value[j][2],1])\n                else:\n                    if((origin_x<=value[j][0]) & (xmax_y>=value[j][1])):\n                        value_name_area_ls[key].append([value[j][2],2])\n                    else:\n                        if((origin_x>value[j][0]) & (xmin_y>value[j][1])):\n                            value_name_area_ls[key].append([value[j][2],3])\n    area_1=list(set([key for key in value_name_area_ls.keys() if (value_name_area_ls[key][track_index][1]==0) | (value_name_area_ls[key][track_index][1]==1)]))\n    area_1.sort()\n    area_2=list(set([key for key in value_name_area_ls.keys() if (value_name_area_ls[key][track_index][1]==2) | (value_name_area_ls[key][track_index][1]==3)]))\n    area_2.sort()\n    for key,value in value_name_area_ls.items():\n        dis_ls=[i[0] for i in value_name_area_ls[key]] # jockey name döndürüyor\n        for area in area_1:\n            ls=[]    \n            for z in dis_ls:\n                right=0\n                left=0\n                for i in jockey_angle_furlong[area][z]:\n                    if ((i>0) & (i<=90)) | ((i>=270) & (i<360)):\n                        right+=1\n                    if ((i<=180) & (i>=90)) | ((i>=180) & (i<270)):\n                        left+=1\n                \n                placement_val[area][right]=z\n        for area in area_2:\n            for z in dis_ls:\n                right=0\n                left=0\n                for i in jockey_angle_furlong[area][z]:\n                    if ((i>0) & (i<=92)) | ((i>=272) & (i<360)):\n                        right+=1\n                    if ((i<=180) & (i>92)) | ((i>=180) & (i<272)):\n                        left+=1  \n                placement_val[area][left]=z\n    return placement_val\n\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:22:13.976917Z","iopub.execute_input":"2022-11-04T14:22:13.977286Z","iopub.status.idle":"2022-11-04T14:22:14.305124Z","shell.execute_reply.started":"2022-11-04T14:22:13.977254Z","shell.execute_reply":"2022-11-04T14:22:14.303842Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"***In this section, you can see how each jockey is ranked relative to the other jockeys and how their angles are stored as a dictionary.***","metadata":{}},{"cell_type":"code","source":"first,jockey_cordinants=select_race(merged_df,'2019-01-01','AQU',1)\nposition_cordinants_per_furlong,furlongs_split,per_furlong_pos_index=cordinants_per_furlong(first,jockey_cordinants)\nxmax_y,xmin_y,origin_x,origin_y=get_origin(first)\ncheckpoints_cordinant=checkpoints_location(first,jockey_cordinants,per_furlong_pos_index,type=1)\n\njockey_dist_furlong,jockey_angle_furlong=%time road_taken(first,jockey_cordinants,per_furlong_pos_index) \njockey_angle_furlong","metadata":{"_kg_hide-input":false,"scrolled":true,"execution":{"iopub.status.busy":"2022-11-04T14:22:14.306554Z","iopub.execute_input":"2022-11-04T14:22:14.307187Z","iopub.status.idle":"2022-11-04T14:22:16.313548Z","shell.execute_reply.started":"2022-11-04T14:22:14.307146Z","shell.execute_reply":"2022-11-04T14:22:16.312315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plc=%time placement(xmax_y,xmin_y,origin_x,origin_y,checkpoints_cordinant,per_furlong_pos_index,jockey_angle_furlong) \nplc","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2022-11-04T14:22:16.315107Z","iopub.execute_input":"2022-11-04T14:22:16.315716Z","iopub.status.idle":"2022-11-04T14:22:16.331848Z","shell.execute_reply.started":"2022-11-04T14:22:16.315649Z","shell.execute_reply":"2022-11-04T14:22:16.330833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Furlong Charts ","metadata":{}},{"cell_type":"code","source":"def make_sub(df,checkpoints_cordinant,jockey_dist_furlong,per_furlong_pos_index):\n    fig = make_subplots(\n        rows=4, cols=1,\n        specs=[[{\"type\": \"scatter\"}],\n               [{\"type\": \"scatter\"}],\n               [{\"rowspan\": 2,\"type\": \"table\"}],\n               [None]],\n        subplot_titles=(\"Acceleration\",\"Snapshot on Furlongs \",\"Jockey Position on Furlong \"),)\n    #Track plot\n    fig.add_trace(go.Scatter(x=df[df['jockey']==df[df['latitude']==min(df['latitude'])]['jockey'].iloc[0]]['latitude'],\n                             y=df[df['jockey']==df[df['latitude']==min(df['latitude'])]['jockey'].iloc[0]]['longitude'],\n                             mode=\"lines\",\n                             showlegend = False,\n                             name='Track',\n                             line=dict(width=1.4, color=\"white\")),\n                 row=2,col=1)\n    annotation_head=[i for i in range(1,len(per_furlong_pos_index))]\n    annotation_head.insert(0,'Start')\n    for num,val in enumerate(checkpoints_cordinant.keys()):\n        fig.add_trace(go.Scatter(x=checkpoints_cordinant[val]['latitude'],\n                                 y=checkpoints_cordinant[val]['longitude'],\n                                mode=\"markers\",\n\n                                name=val,\n                                marker=dict(size=7,color=colors[num])),row=2,col=1)\n    for num,val in enumerate(per_furlong_pos_index):\n        fig.add_annotation(x=checkpoints_cordinant[df[df['jockey']==df[df['latitude']==min(df['latitude'])]['jockey'].iloc[0]]['jockey'].iloc[0]].iloc[:,0].reset_index(drop=True)[num], \n                           y=checkpoints_cordinant[df[df['jockey']==df[df['latitude']==min(df['latitude'])]['jockey'].iloc[0]]['jockey'].iloc[0]].iloc[:,1].reset_index(drop=True)[num],\n                text=str(annotation_head[num]),\n                showarrow=False,\n                yshift=25,row=2,col=1)\n    fig.update_xaxes(showgrid=False, gridwidth=0.75, gridcolor='LightPink')\n    fig.update_yaxes(showgrid=False, gridwidth=0.75, gridcolor='LightPink')\n    #Acceleration plot\n    acce_dict={str(i):[] for i in checkpoints_cordinant.keys()}\n\n    next=0\n    for num,val in enumerate(list(jockey_dist_furlong.keys())[1:],start=1):\n        for n,name in enumerate(acce_dict.keys()):\n            if num==1: \n                next=0\n            else: \n                next=jockey_dist_furlong[list(jockey_dist_furlong.keys())[num-1]][n] \n            delta_x=jockey_dist_furlong[val][n]-next\n            acce_dict[list(checkpoints_cordinant.keys())[n]].append(delta_x)\n\n    acce_furlong=[i for i in range(len(list(checkpoints_cordinant.values())[0].index))]\n    for n,key in enumerate(acce_dict.keys()):\n        fig.add_trace(go.Scatter(x=acce_furlong,\n                                     y=acce_dict[key],\n                                    mode=\"lines\",\n                                    showlegend = False,\n\n                                    name=key,\n                                    line=dict(width=1.2, color=colors[n])),\n                                    row=1,col=1)\n    #Jockey Position for Furlongs Table \n    annotation_head.insert(0,'Rank')\n    cells=list(plc.values())\n    cells.insert(0,[i for i in range(1,len(plc.values())+1)])\n    cells_v=[k[i] for i in range(len(cells[1])) for k in cells ]\n    fig.add_trace(go.Table(\n        header=dict(values=annotation_head,\n                    fill_color='#232425',\n                    font=dict(size=15,color='red'),\n                    align='center'),\n        cells=dict(values=cells,\n                   fill_color='#232425',\n                   font=dict(size=13,color='white'),\n                   align='left')),row=3,col=1)\n    fig['layout']['xaxis']['title']= 'Furlongs'\n    fig['layout']['yaxis']['title']= 'Acceleration'\n    fig['layout']['xaxis2']['title']='Latitude'\n    fig['layout']['yaxis2']['title']='Longitude'\n    fig['layout']['xaxis'].update(showgrid=True)\n    \n    fig.update_layout(title_text='<b>'+str(len(per_furlong_pos_index)-1)+' Furlong Checkpoint Jockey Position '+'</b>',\n                                  height=1250,\n                                  width=800,\n                                  title_x=0.5,\n                                  paper_bgcolor='#232425',\n                                  plot_bgcolor='#232425',\n                                  font=dict(\n                                      family=\"Courier New, monospace\",\n                                      size=18,\n                                      color='white'),\n                                  legend=dict(yanchor=\"bottom\",\n                                                y=0.45,\n                                                xanchor=\"right\",\n                                                x=1.5\n                                            )\n                                     )\n    for i in fig['layout']['annotations']:\n        i['font'] = dict(size=20,color='red')\n    fig.add_annotation(dict(font=dict(color='yellow',size=12),\n                                        x=-0.15,\n                                        y=1.25,\n                                        showarrow=False,\n                                        text='Track: '+df['track_id'][0]+' | '+'Race Date: '+str(df['race_date'][0].date())+' | '+'Race Number:'+str(df['race_number'][0]),\n                                        textangle=0,\n                                        xanchor='left',\n                                        xref=\"x domain\",\n                                        yref=\"y domain\"\n                                        ),row=1,col=1)    \n    fig.show()\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T14:22:16.333450Z","iopub.execute_input":"2022-11-04T14:22:16.334378Z","iopub.status.idle":"2022-11-04T14:22:16.368252Z","shell.execute_reply.started":"2022-11-04T14:22:16.334339Z","shell.execute_reply":"2022-11-04T14:22:16.366899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"***During the race, acceleration and position ranking information graphics were drawn between the furlongs.***","metadata":{}},{"cell_type":"code","source":"first,jockey_cordinants=select_race(merged_df,'2019-01-01','AQU',1)\nposition_cordinants_per_furlong,furlongs_split,per_furlong_pos_index=cordinants_per_furlong(first,jockey_cordinants)\nxmax_y,xmin_y,origin_x,origin_y=get_origin(first)\ncheckpoints_cordinant=checkpoints_location(first,jockey_cordinants,per_furlong_pos_index,type=1)\n\njockey_dist_furlong,jockey_angle_furlong=%time road_taken(first,jockey_cordinants,per_furlong_pos_index) \nplc=%time placement(xmax_y,xmin_y,origin_x,origin_y,checkpoints_cordinant,per_furlong_pos_index,jockey_angle_furlong) \nmake_sub(first,checkpoints_cordinant,jockey_dist_furlong,per_furlong_pos_index)","metadata":{"execution":{"iopub.status.busy":"2022-11-04T14:22:16.373890Z","iopub.execute_input":"2022-11-04T14:22:16.376295Z","iopub.status.idle":"2022-11-04T14:22:18.640262Z","shell.execute_reply.started":"2022-11-04T14:22:16.376235Z","shell.execute_reply":"2022-11-04T14:22:18.638975Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"first,jockey_cordinants=select_race(merged_df,'2019-01-04','AQU',4)\nposition_cordinants_per_furlong,furlongs_split,per_furlong_pos_index=cordinants_per_furlong(first,jockey_cordinants)\nxmax_y,xmin_y,origin_x,origin_y=get_origin(first)\ncheckpoints_cordinant=checkpoints_location(first,jockey_cordinants,per_furlong_pos_index,type=1)\n\njockey_dist_furlong,jockey_angle_furlong=%time road_taken(first,jockey_cordinants,per_furlong_pos_index) \nplc=%time placement(xmax_y,xmin_y,origin_x,origin_y,checkpoints_cordinant,per_furlong_pos_index,jockey_angle_furlong) \nmake_sub(first,checkpoints_cordinant,jockey_dist_furlong,per_furlong_pos_index)","metadata":{"execution":{"iopub.status.busy":"2022-11-04T14:22:18.641689Z","iopub.execute_input":"2022-11-04T14:22:18.642073Z","iopub.status.idle":"2022-11-04T14:22:23.296615Z","shell.execute_reply.started":"2022-11-04T14:22:18.642040Z","shell.execute_reply":"2022-11-04T14:22:23.295119Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# All Jokey Furlong Rank Heatmap","metadata":{}},{"cell_type":"markdown","source":"* ***The sequences in the furlongs were converted into a DataFrame and output as .csv. This output was then displayed as a furlong heatmap for each jockey.***","metadata":{}},{"cell_type":"code","source":"\"\"\"above_350=start_race['jockey'].value_counts()[start_race['jockey'].value_counts()>350].index.to_list()\nselected_df=pd.DataFrame()\nfor i in above_350:\n    a=start_race[start_race['jockey']==i]\n    selected_df=selected_df.append(a,ignore_index=True)\nunique_race=selected_df.sort_values(['track_id','race_date']).set_index(['race_date','track_id','race_number']).index.unique()\nfurlong_df=pd.DataFrame()\nfor race in unique_race:\n    print(race)\n    first,jockey_cordinants=select_race(merged_df,str(race[0]),race[1],race[2])\n    position_cordinants_per_furlong,furlongs_split,per_furlong_pos_index=cordinants_per_furlong(first,jockey_cordinants)\n    xmax_y,xmin_y,origin_x,origin_y=get_origin(first)\n    checkpoints_cordinant=checkpoints_location(first,jockey_cordinants,per_furlong_pos_index,1)\n    jockey_dist_furlong,jockey_angle_furlong=%time road_taken(first,jockey_cordinants,per_furlong_pos_index) \n    plc=%time placement(xmax_y,xmin_y,origin_x,origin_y,checkpoints_cordinant,per_furlong_pos_index,jockey_angle_furlong)\n    dta=[]\n    column=[['race_date','track_id','race_number','furlong']+['pos_'+str(i) for i in range(1,max_jockey_count+1)]]\n    for n,i in enumerate(plc.keys()):\n        dta.append([race[0],race[1],race[2],furlongs_split[n]]+list(plc[i]))\n    r_df=pd.DataFrame(data=dta)\n    furlong_df=pd.concat([furlong_df,r_df],axis=0,ignore_index=True)\n    furlong_df.to_csv('furlong_df.csv', index=False)\"\"\"","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"scrolled":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"***Import Output Data Furlong***","metadata":{}},{"cell_type":"code","source":"furlong_df=pd.read_csv('../input/furlongdf/furlong_df (1).csv')\nfurlong_df['3'].replace('Start','0',inplace=True)\nfurlong_df['3']=furlong_df['3'].astype(int)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T18:02:45.513175Z","iopub.execute_input":"2022-11-04T18:02:45.513606Z","iopub.status.idle":"2022-11-04T18:02:45.602660Z","shell.execute_reply.started":"2022-11-04T18:02:45.513570Z","shell.execute_reply":"2022-11-04T18:02:45.601657Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nmax_jockey_count=start_race.groupby(['race_date','track_id','race_number'])['jockey'].count().max()\ncol_name=['race_date','track_id','race_number','Furlongs']+['pos_'+str(i) for i in range(1,max_jockey_count+1)]\nfurlong_df.columns=col_name\nfurlong_df.head(10)\n","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2022-11-04T18:02:48.957981Z","iopub.execute_input":"2022-11-04T18:02:48.958400Z","iopub.status.idle":"2022-11-04T18:02:48.991265Z","shell.execute_reply.started":"2022-11-04T18:02:48.958366Z","shell.execute_reply":"2022-11-04T18:02:48.990169Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def jockey_df_list(furlongs,start_race):\n    \"\"\"\n    Position information of each jockey is transferred as heatmap.\n    \n    Parameters\n    ----------\n    furlongs : TYPE DataFrame\n        Furlong position each jockey.\n    start_race : TYPE DataFrame\n\n    Returns\n    -------\n    fig : TYPE Object\n        Heatmap Listed each jockey on the Plotly API.\n\n    \"\"\"\n    fig=go.Figure()\n    buttons=[]\n    furlongs.set_index('Furlongs',inplace=True)\n    unique_jockey_list=start_race['jockey'].unique()\n    max_jockey_count=start_race.groupby(['race_date','track_id','race_number'])['jockey'].count().max()\n    for n,k in enumerate(unique_jockey_list):\n        df=furlongs[furlongs[['pos_'+str(i) for i in range(1,max_jockey_count+1)]]==k][['pos_'+str(i) for i in range(1,max_jockey_count+1)]]\n        df=df.groupby('Furlongs').count()\n        fig.add_trace(go.Heatmap(y=df.index,x=df.columns,z=df[['pos_'+str(i) for i in range(1,max_jockey_count+1)]],name=k,\n                    hovertemplate ='<i>Rank</i>: %{x}'+'<br><b>Furlong</b>: %{y}<br>'+'<i>Count</i>: %{z}',text=df[['pos_'+str(i) for i in range(1,max_jockey_count+1)]],\n                    texttemplate=\"%{text}\",textfont={\"size\":14}))\n    return fig\nfig=jockey_df_list(furlong_df,start_race)\nfig['data']\nfig.update_layout(title_text='<b>'+' What is the rank of the jockey in the furlongs at all Race?'+'</b>',\n                                  title_font=dict(color='#AD2B10'),\n                                  xaxis_title=\"Ranking of jockeys in Furlong\",\n                                  yaxis_title=\"Furlongs\",\n                                  legend_title=\"Count\",\n                                  height=1000,\n                                  title_x=0.5,\n                                  showlegend=False,\n                                  paper_bgcolor='#232425',\n                                  plot_bgcolor='#232425',\n                                  font=dict(\n                                      family=\"Courier New, monospace\",\n                                      size=15,\n                                      color='white'),\n                                  \n                  updatemenus=[\n                                {\n                                    \"buttons\": [\n                                        {\n                                            \"label\": m,\n                                            \"method\": \"update\",\n                                            \"args\": [\n                                                {\n                                                    \"visible\": [\n                                                        \n                                                        True if t.name==m else False for t in fig.data\n                                                    ]\n                                                }\n                                                \n                                            ],\n                                            \n                                        }\n                                        for m in start_race['jockey'].unique().tolist()\n                                    ],\n                                    'font' : dict(color='LightPink'),\n                                    'pad':{\"l\": 0, \"r\": 20, \"t\":25 , \"b\": 0}\n                                }\n                            ],\n                  \n                  \n                                     )\n\nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-11-04T18:03:05.525754Z","iopub.execute_input":"2022-11-04T18:03:05.526236Z","iopub.status.idle":"2022-11-04T18:03:14.312918Z","shell.execute_reply.started":"2022-11-04T18:03:05.526199Z","shell.execute_reply":"2022-11-04T18:03:14.311174Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Conculusion\n\n* Having horse IDs can give much better analysis results.\n* With deeper features, the angle taken by the horse in the tracus indices, the pulse information of the horse in the furlongs, injury analysis can be made, especially in the turning parts.\n* With the finish line being the coordinate information, it will be possible to know the acceleration of the horse and the exact time the horse has finished the track. In this way, it can be determined whether the characteristic features of the track are in a causal relationship with respect to the horses.\n* For example, it is a fact that not every horse can run in very long races. These are made in rare races and with highly experienced horses.\n\n***It was a very enjoyable dataset. Thanks for your time...***","metadata":{}}]}