{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os, sys, gc\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true,"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":false},"cell_type":"markdown","source":"### READ FILES"},{"metadata":{"trusted":true},"cell_type":"code","source":"num_files = 0\n#files = {}\n\nlast_folders = []\nfile_list = []\nfile_short = []\n\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    last_folder = str(dirname).split('/')[-1]\n    \n    for filename in filenames:\n        file = str(filename).split('.')[0]\n        \n        last_folders.append(last_folder)\n        \n        file_curr = 'DF_' + last_folder.replace('-', '_') + '_' + file        \n        file_list.append(file_curr)\n        file_short.append(file)\n        \n        df = pd.read_csv(os.path.join(dirname, filename), encoding='Latin5')\n        exec(file_curr + \" = \" + str('df'))\n        num_files += 1        \n        \nprint('Num files read: ', num_files)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DF_LIST = pd.DataFrame(file_list)\nDF_LIST.columns = ['DF_NAME']\n\nDF_LIST['FOLDER'] = last_folders\nDF_LIST['FILE'] = file_short\n\n# Remove trails (-) and replace with underscore (_)\nDF_LIST['FOLDER'] = DF_LIST['FOLDER'].apply(lambda f: f.replace('-', '_'))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Add descriptive file attributes"},{"metadata":{"trusted":true},"cell_type":"code","source":"DF_LIST['FILE_TYPE'] = DF_LIST['FILE'].apply(lambda f: 'Gender specific' if f[0] in ['W', 'M'] else 'Common')\n\nDF_LIST['FILE_COMMON'] = DF_LIST['FILE'].apply(lambda f: f[1:] if f[0] in ['W', 'M'] else f).apply(\n                                               lambda f: 'W' if f.find('Womens')>0 else f).apply(\n                                               lambda f: 'M' if f.find('Mens')>0 else f)\n\nDF_LIST['FOLDER_COMMON'] = DF_LIST['FOLDER'].apply(lambda f: f[1:] if f[0] in ['W', 'M'] else f).apply(\n                                            lambda f: f.replace('_Womens', '')).apply(\n                                            lambda f: f.replace('_Mens', ''))\n\nDF_LIST['GENDER'] = DF_LIST[['FILE', 'FOLDER']].apply(\n                                            lambda f: f.FILE[0] if f.FILE[0] in ['W', 'M'] else f.FOLDER, \n                                            axis=1).apply(\n                                            lambda f: 'M' if f.find('Mens')>0 or f[0] =='M' else f).apply(\n                                            lambda f: 'W' if f.find('Womens')>0 or f[0] == 'W' else f)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Combine men and women's data in order to reduce df number and be able to analyze male and female plays together"},{"metadata":{"trusted":true},"cell_type":"code","source":"def append_men_women_df(df_men=None, df_women=None):\n    \n    if not df_men.empty and not df_women.empty:\n        df_men['GENDER']   = 'M'\n        df_women['GENDER'] = 'W'\n        return(df_men.append(df_women, ignore_index=True, sort=False))\n    \n    elif df_men.empty and not df_women.empty:\n        df_women['GENDER'] = 'W'\n        return(df_women)\n    \n    elif not df_men.empty and df_women.empty:\n        df_men['GENDER']   = 'M'\n        return(df_men)    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"merged_df = []\nmerged_df_counter = 0\ndefault_df = pd.DataFrame() \n\nfile_common = DF_LIST.query('FILE_TYPE==\"Gender specific\"').FILE_COMMON.unique()\n\nfor f in file_common:\n    df_common_1 = DF_LIST.query('FILE_COMMON==\"{}\"'.format(f))\n    folder_common = df_common_1.FOLDER_COMMON.unique()\n    \n    if f.find('Events') >= 0:\n        continue\n    \n    for f2 in folder_common:        \n        df_name_new = 'DF_' + f2 + '_' + f        \n        \n        df_common = df_common_1.query('FOLDER_COMMON==\"{}\"'.format(f2))\n        \n        df_men = df_common.query('GENDER==\"M\"').DF_NAME.values[0] if df_common.query('GENDER==\"M\"').shape[0]>0 else 'default_df'\n        df_women = df_common.query('GENDER==\"W\"').DF_NAME.values[0] if df_common.query('GENDER==\"W\"').shape[0]>0 else 'default_df'\n        \n        df_new = append_men_women_df(eval(df_men), eval(df_women))        \n        exec(df_name_new + \" = \" + str('df_new'))\n        \n        merged_df_counter = merged_df_counter + 1 if df_men != 'default_df' else merged_df_counter\n        merged_df_counter = merged_df_counter + 1 if df_women != 'default_df' else merged_df_counter\n        \n        merged_df.append(df_name_new)\n\nprint('Number of df merged', merged_df_counter)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"merged_df2 = [] \n\nfile_common = DF_LIST.query('FILE_TYPE!=\"Gender specific\"').FILE_COMMON.unique()\n\nfor f in file_common:\n    df_common_1 = DF_LIST.query('FILE_COMMON==\"{}\"'.format(f))\n    folder_common = df_common_1.FOLDER_COMMON.unique()\n    \n    for f2 in folder_common:        \n        df_name_new = 'DF_' + f2 + '_' + f        \n        \n        df_common = df_common_1.query('FOLDER_COMMON==\"{}\"'.format(f2))\n        \n        df_men = df_common.query('GENDER==\"M\"').DF_NAME.values[0] if df_common.query('GENDER==\"M\"').shape[0]>0 else 'default_df'\n        df_women = df_common.query('GENDER==\"W\"').DF_NAME.values[0] if df_common.query('GENDER==\"W\"').shape[0]>0 else 'default_df'\n        \n        df_new = append_men_women_df(eval(df_men), eval(df_women))        \n        exec(df_name_new + \" = \" + str('df_new'))\n        \n        merged_df2.append(df_name_new)\n\nprint('Number of df merged', len(merged_df2))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DF_Cities      = DF_DataFiles_Stage2_Cities.append(DF_DataFiles_Stage1_Cities).drop_duplicates()\nDF_Conferences = DF_DataFiles_Stage2_Conferences.append(DF_DataFiles_Stage1_Conferences).drop_duplicates()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### CONTROL \n\nCheck whether dataframes are correctly merged or not"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def check_sum():\n    \n    total_rows = 0\n    \n    print('Checking merged data with the original...')\n    \n    # exclude df which are not merged\n    df_exc = DF_LIST.query('(DF_NAME.str.contains(\"Cities|Conferences\") and FILE_TYPE ==\"Common\") or \\\n                             DF_NAME.str.contains(\"Events\")', engine='python').DF_NAME.unique()\n    df_ = [d for d in DF_LIST.DF_NAME if d not in df_exc]\n\n    print('Excluding Events, Cities and Conferences which are not gender specific')\n\n    for d in df_:\n        total_rows += eval(d).shape[0]\n\n    print(total_rows, ': Total Rows before dataframes merged')\n\n    total_rows_check = 0\n\n    for d in merged_df:\n        total_rows_check += eval(d).shape[0]\n\n    print(total_rows_check, ': Total Rows after dataframes merged')\n\n    print('\\nTotal rows match: ', total_rows == total_rows_check)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"check_sum()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### ANALYSIS OF EVENTS IN DETAIL"},{"metadata":{},"cell_type":"markdown","source":"Requires internet connection"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def plot_court(version=1):\n    \n    court_image1 = 'https://developer.geniussports.com/warehouse/rest/basketball_coords.png'\n    court_image2 = 'https://developer.geniussports.com/warehouse/rest/basketball_courtmap.png'\n    \n    court_image  = eval('court_image' + str(version))\n    \n    img = plt.imread(court_image)\n    fig, ax = plt.subplots(figsize=(24,8))\n    ax.imshow(img)\n    plt.axis('off');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#plot_court(2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sample_pid = DF_MPlayByPlay_Stage2_MPlayers.PlayerID.sample(1).values[0]\n\nsample1 = DF_MPlayByPlay_Stage2_MPlayers.query('PlayerID=={}'.format(sample_pid))\nsample2 = DF_2020_Mens_Data_MPlayers.query('PlayerID=={}'.format(sample_pid))\n\nsample1.append(sample2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sample_eid = DF_MPlayByPlay_Stage2_MEvents2015.EventID.sample(1).values[0]\n\nsample1 = DF_MPlayByPlay_Stage2_MEvents2015.query('EventID=={}'.format(sample_eid))\nsample2 = DF_2020_Mens_Data_MEvents2015.query('EventID=={}'.format(sample_eid))\n\nsample1.append(sample2)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### FINAL DATAFRAMES TO ANALYZE\nIn order to reduce analysis effort and memory usage, only Stage 2 files are considered and the remaining are deleted"},{"metadata":{"trusted":true},"cell_type":"code","source":"FINAL_DF_LIST = [f for f in merged_df if f.find('Stage1')<0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"FINAL_DF_LIST_EVENTS = DF_LIST.query('DF_NAME.str.contains(\"Stage2\") and FILE_COMMON.str.contains(\"Events\")', engine='python').DF_NAME.unique()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Delete unused dataframes, all df excluding \"Events\""},{"metadata":{"trusted":true},"cell_type":"code","source":"DF_2_DEL = [df for df in DF_LIST.DF_NAME.unique() if df not in FINAL_DF_LIST_EVENTS]\n\nfor df_name in DF_2_DEL:\n    exec('del ' + str(df_name))\n    \ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"### TEAM and PLAYER MODELLING\n\nExplore different player and team profiles based on event performance"},{"metadata":{"trusted":true},"cell_type":"code","source":"def time_period_obsolete(elapsed_seconds):\n    if elapsed_seconds <= 1200:\n        i  = elapsed_seconds // 300\n        tp = 'First Half {}-{} min'.format(str(i*5), str((i+1)*5))\n    elif elapsed_seconds <= 2400:\n        i  = (elapsed_seconds - 1200) // 300\n        tp = 'Second Half {}-{} min'.format(str(i*5), str((i+1)*5))\n    else:\n        # trailing part is added to include 300th or 60th seconds in the previous period not in the next\n        ot = (elapsed_seconds - 2400) // 300.00001\n        i  = (elapsed_seconds - 2400 - ot * 300) // 60.00001   \n        tp = 'Overtime ({}) {}-{} min'.format(str(int(ot) + 1), str(int(i)*1), str((int(i)+1)*1))\n    \n    return(tp)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def time_period(elapsed_seconds):\n    \n    if elapsed_seconds <= 1200:\n        tp = 'FirstHalf'\n    elif elapsed_seconds <= 2400:\n        tp = 'SecondHalf'\n    elif elapsed_seconds <= 2700:\n        tp = 'OverTime1'\n    elif elapsed_seconds <= 3000:\n        tp = 'OverTime2'\n    elif elapsed_seconds <= 3300:\n        tp = 'OverTime3'\n    elif elapsed_seconds <= 3600:\n        tp = 'OverTime4'\n    else:\n        tp = 'OverTime4P'\n    \n    return(tp)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Add time period to all events dataframes"},{"metadata":{"trusted":true},"cell_type":"code","source":"for df_name in FINAL_DF_LIST_EVENTS:\n    df = eval(df_name)\n    \n    df['TimePeriod'] = df['ElapsedSeconds'].apply(time_period)\n    df['WinnerFlag'] = (df['EventTeamID'] == df['WTeamID'])*1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Define unique key to each play "},{"metadata":{"trusted":true},"cell_type":"code","source":"def add_keys(df, cols_key):\n    \n    vals = df[cols_key].values\n    keys = [str(int(a)) + '_' + str(int(b)) + '_' + str(int(c)) + '_' + str(int(d)) for [a,b,c,d] in vals]\n    df['Key'] = keys\n    \n    cols_new = [c for c in df.columns if c not in cols_key]\n    \n    return(df[cols_new])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Prepare team event statistics"},{"metadata":{"trusted":true},"cell_type":"code","source":"group_cols = ['EventTeamID', 'Season', 'DayNum', 'WTeamID', 'LTeamID', 'WinnerFlag', 'EventType']\nkey_cols   = ['Season', 'DayNum', 'WTeamID', 'LTeamID']\nfirst = True\n\nprint('Preparing team event statistics')\n\nfor df_name in FINAL_DF_LIST_EVENTS:\n    df = eval(df_name)\n    stat_temp = df.groupby(group_cols)['EventID'].count().reset_index().rename(columns={'EventID':'EventCount'})\n    stat_det_temp = df.groupby(group_cols + ['TimePeriod'])['EventID'].count().reset_index().rename(columns={'EventID':'EventCount'})\n    \n    team_event_stats1 = stat_temp if first else team_event_stats1.append(stat_temp)\n    team_event_detailed_stats1 = stat_det_temp if first else team_event_detailed_stats1.append(stat_det_temp)\n    \n    if first:\n        first = False\n\n# ADD COACH NAME TO TEAM STATS DATAFRAMES\nprint('Adding coach information to teams')\n\nteam_event_stats = team_event_stats1.merge(DF_DataFiles_Stage2_TeamCoaches, left_on=['Season', 'EventTeamID'],\n                                           right_on=['Season', 'TeamID'], how='left').query(\n                                           'DayNum>=FirstDayNum and DayNum<=LastDayNum').drop(\n                                           ['TeamID', 'FirstDayNum', 'LastDayNum', 'GENDER'], axis=1)\n\nteam_event_detailed_stats = team_event_detailed_stats1.merge(DF_DataFiles_Stage2_TeamCoaches, left_on=['Season', 'EventTeamID'],\n                                           right_on=['Season', 'TeamID'], how='left').query(\n                                           'DayNum>=FirstDayNum and DayNum<=LastDayNum').drop(\n                                           ['TeamID', 'FirstDayNum', 'LastDayNum', 'GENDER'], axis=1)\n\n\nteam_event_stats = add_keys(team_event_stats, key_cols)\nteam_event_detailed_stats = add_keys(team_event_detailed_stats, key_cols)    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Checkpoint - Each team has only one coach on a specific day"},{"metadata":{"trusted":true},"cell_type":"code","source":"team_event_stats.groupby(['EventTeamID', 'Season', 'DayNum'])['CoachName'].nunique().reset_index().sort_values('CoachName').tail(1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Add result type: NCAA, secondary, regular to team stats"},{"metadata":{"trusted":true},"cell_type":"code","source":"DF_DataFiles_Stage2_GameCities = add_keys(DF_DataFiles_Stage2_GameCities, key_cols)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"team_event_stats_final = team_event_stats.merge(DF_DataFiles_Stage2_GameCities, on='Key', how='left')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Drop rows with NULL result types which is very small in percentage"},{"metadata":{"trusted":true},"cell_type":"code","source":"team_event_stats_final.CRType.isna().sum() / team_event_stats_1.shape[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"team_event_stats_final.dropna(axis=0, inplace=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Prepare player event statistics"},{"metadata":{"trusted":true},"cell_type":"code","source":"group_cols = ['EventPlayerID', 'Season', 'DayNum', 'WTeamID', 'LTeamID', 'EventType'] #'WinnerFlag'\nkey_cols   = ['Season', 'DayNum', 'WTeamID', 'LTeamID']\nfirst = True\n\nfor df_name in FINAL_DF_LIST_EVENTS:\n    df = eval(df_name)\n    stat_temp = df.groupby(group_cols)['EventID'].count().reset_index().rename(columns={'EventID':'EventCount'})\n    #stat_det_temp = df.groupby(group_cols + ['TimePeriod'])['EventID'].count().reset_index().rename(columns={'EventID':'EventCount'})\n    \n    player_event_stats = stat_temp if first else player_event_stats.append(stat_temp)\n    player_event_detailed_stats = stat_det_temp if first else player_event_detailed_stats.append(stat_det_temp)\n    \n    if first:\n        first = False\n    \nplayer_event_stats = add_keys(player_event_stats, key_cols)\n#player_event_detailed_stats = add_keys(player_event_detailed_stats, key_cols)    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Add gender field to player stats"},{"metadata":{"trusted":true},"cell_type":"code","source":"team_gender = DF_DataFiles_Stage2_Teams[['TeamID', 'GENDER']].values\n\ngender_dict = {int(t):g for t,g in team_gender}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"teamids = player_event_stats['Key'].apply(lambda k: k.split('_')[3]).apply(int).values\ngender  = [gender_dict[t] for t in teamids]\nplayer_event_stats['Gender'] = gender","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Some players may not be actively playing during the whole match which is a bias towards those who played longer. This bias is ignored due to:\n\n- Each player has the same chance to play longer or shorter time in a match\n- Data is accumulated from 5 years of plays which randomly includes longer/shorter durations of activity\n- Mean of event counts occured among all plays is considered"},{"metadata":{"trusted":true},"cell_type":"code","source":"player_event_mean = player_event_stats.pivot_table(index='EventPlayerID', columns='EventType', values='EventCount', \n                                                   aggfunc=np.mean).reset_index().fillna(0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"player_event_mean_mens = player_event_stats.query('Gender==\"M\"').pivot_table(index='EventPlayerID', columns='EventType', values='EventCount', \n                                                   aggfunc=np.mean).reset_index().fillna(0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"player_event_mean_womens = player_event_stats.query('Gender==\"W\"').pivot_table(index='EventPlayerID', columns='EventType', values='EventCount', \n                                                   aggfunc=np.mean).reset_index().fillna(0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### IDENTIFYING DIFFERENT PLAYER PROFILES\n\nK-Means algorithm is used to explore player weakness/strength and profiles\n2 sub cluster is built based on attribute groups\n\n1. Based on shots, i.e misses and mades\n2. Offensive/defensive/other attributes"},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.cluster import KMeans \n\nimport seaborn as sns\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def cluster_stats(df, cols_cluster, col_profile):\n    \n    count   = df.groupby(col_profile)[cols_cluster[0]].count().reset_index().rename(columns={cols_cluster[0]:'count'})\n    mean    = df.groupby(col_profile)[cols_cluster].mean().reset_index()\n    median  = df.groupby(col_profile)[cols_cluster].mean().reset_index()\n    \n    mean.columns   = [col_profile] + [c + '_mean' for c in cols_cluster]\n    median.columns = [col_profile] + [c + '_median' for c in cols_cluster]\n    \n    stats   = count.merge(mean, on=col_profile, how='inner'\n                         ).merge(median, on=col_profile, how='inner')\n    \n    return(stats)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def make_cluster(df, cols_cluster, col_profile, n_cluster=4):\n\n    data = df[cols_cluster].values\n\n    km = KMeans(n_clusters=n_cluster, random_state=1111)\n    km.fit(data)\n    \n    pred = km.predict(data)\n    \n    df[col_profile] = pred\n    \n    clust_stats = cluster_stats(df, cols_cluster, col_profile)\n    clust_stats_compact = df[[col_profile] + cols_cluster].melt(col_profile)\n    \n    return df, clust_stats, clust_stats_compact","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_counts(data, col_profile):\n    \n    sns.set_palette(\"Paired\")\n\n    fig, ax = plt.subplots(figsize=(6, 3))\n    ax.set_title('Number of records in each cluster - {}'.format(col_profile))\n\n    sns.barplot(x=col_profile, y=\"count\", data=data, ax=ax)    ;","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_cluster(data, cols_cluster, col_profile, title):\n    \n    sns.set_palette(\"Paired\")\n    \n    fig, ax = plt.subplots(figsize=(20, 6))\n    ax.set_title(title)\n\n    # cut off outlier values\n    data_plot = data.query('value<=10')\n\n    sns.boxplot(x=col_profile, y=\"value\", hue=\"EventType\", data=data_plot, ax=ax);","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**1st sub-cluster**"},{"metadata":{},"cell_type":"markdown","source":"Firstly cluster only male players"},{"metadata":{"trusted":true},"cell_type":"code","source":"cols_cluster = ['made1', 'made2', 'made3', 'miss1', 'miss2', 'miss3']\ncol_profile  = 'PROFILE_1'\ntitle        = 'Male Player profiles based on shots made or missed'\n\nplayer_event_mean_mens, clust1_stats, clust1_stats_compact =  make_cluster(player_event_mean_mens, cols_cluster, col_profile, n_cluster=4)\n\nplot_counts(clust1_stats, col_profile)\nplot_cluster(clust1_stats_compact, cols_cluster, col_profile, title)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now cluster only female players"},{"metadata":{"trusted":true},"cell_type":"code","source":"cols_cluster = ['made1', 'made2', 'made3', 'miss1', 'miss2', 'miss3']\ncol_profile  = 'PROFILE_1'\ntitle        = 'Female Player profiles based on shots made or missed'\n\nplayer_event_mean_womens, clust1_stats, clust1_stats_compact =  make_cluster(player_event_mean_womens, cols_cluster, col_profile, n_cluster=4)\n\nplot_counts(clust1_stats, col_profile)\nplot_cluster(clust1_stats_compact, cols_cluster, col_profile, title)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Comparing Male and Female Player profiles:\n- They have simillar groupings in terms of shots made or missed\n    - Female Profile 0 - Men Profile 2 look simliar\n    - Female Profile 3 - Men Profile 1 look simliar\n    - Female Profile 1 - Men Profile 0 look simliar\n    - Female Profile 2 - Men Profile 3 look simliar\n\n- Next step: Cluster male and female players together since they are simillar"},{"metadata":{},"cell_type":"markdown","source":"Finally, male and female players clustered together"},{"metadata":{"trusted":true},"cell_type":"code","source":"cols_cluster = ['made1', 'made2', 'made3', 'miss1', 'miss2', 'miss3']\ncol_profile  = 'PROFILE_1'\ntitle        = 'Player profiles based on shots made or missed'\n\nplayer_event_mean, clust1_stats, clust1_stats_compact =  make_cluster(player_event_mean, cols_cluster, col_profile, n_cluster=4)\n\nplot_counts(clust1_stats, col_profile)\nplot_cluster(clust1_stats_compact, cols_cluster, col_profile, title)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div style='font-family:\"Calibri\"; border: 1px solid gray; padding:8px;'>\n<br/>\n**FROM THE GRAPH ABOVE:**\n\n<br/>\n- There is not any sub group who is totally successful or totally failure, i.e. Scoring high mades and low misses, or scoring low mades and high misses\n\n- Some of the distinguishing attributes of profiles:\n<ul>\n    <li> PROFILE 3 - BEST SHORT DISTANCE SHOOTTERS: They are far better at making 1 or 2 points, however they equally miss 2 points </li>\n    <li> PROFILE 2 - AVERAGE SHOOTTER FAILING LONG DISTANCE: Although they are good at 1-2 point shots, they missed 3 points the most </li>\n    <li> PROFILE 0 - AVERAGE SHOOTTER </li>\n    <li> PROFILE 1 - NOT A SHOOTHER </li>\n</ul>  \n</div>"},{"metadata":{},"cell_type":"markdown","source":"Recode sub-cluster - 1"},{"metadata":{"trusted":true},"cell_type":"code","source":"shooter_dict = {3: 'BEST_SHORT_DISTANCE_SHOOTER', 2: 'AVERAGE_SHOOTER_FAILING_LONG_DISTANCE', 0: 'AVERAGE_SHOOTER', 1: 'NOT_SHOOTER'}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"player_event_mean['SHOOTER_PROFILE'] = player_event_mean['PROFILE_1'].apply(lambda x: shooter_dict[x])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**2nd sub-cluster**"},{"metadata":{"trusted":true},"cell_type":"code","source":"cols_cluster = ['assist', 'block', 'reb', 'steal']\ncol_profile  = 'PROFILE_2'\ntitle        = 'Player profiles based on offensive & defensive traits'\n\nplayer_event_mean, clust1_stats, clust1_stats_compact =  make_cluster(player_event_mean, cols_cluster, col_profile, n_cluster=4)\n\nplot_counts(clust1_stats, col_profile)\nplot_cluster(clust1_stats_compact, cols_cluster, col_profile, title)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**PROFILE 2: PROFILES BASED ON OFFENSIVE & DEFENSIVE CHARACTERISTICS**\n<ul style='font-family:\"Calibri\"; border: 1px solid gray; padding:8px;'>\n    <li> PROFILE 1 - BEST REBOUNDERS : Players who are best at rebounds </li>\n    <li> PROFILE 0 - GOOD REBOUNDERS : Players who are above average at rebounds </li>\n    <li> PROFILE 3 - AVERAGE ASSISTER REBOUNDER      : Players who are best at assisting but also a good rebounder </li>\n    <li> PROFILE 2 - NOT_ASSISTER_REBOUNDER        : Players who do not have distinguishing offensive or defensive trait </li>\n</ul>"},{"metadata":{},"cell_type":"markdown","source":"RECODE PROFILE - 2"},{"metadata":{"trusted":true},"cell_type":"code","source":"off_def_dict = {1: 'BEST_REBOUNDERS', 0: 'GOOD_REBOUNDERS', 3: 'AVERAGE_ASSISTER_REBOUNDER', 2: 'NOT_ASSISTER_REBOUNDER'}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"player_event_mean['OFFENSIVE_DEFENSIVE_PROFILE'] = player_event_mean['PROFILE_2'].apply(lambda x: off_def_dict[x])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's visualize and try to understand different profiles"},{"metadata":{"trusted":true},"cell_type":"code","source":"player_event_mean.groupby(['SHOOTER_PROFILE', 'OFFENSIVE_DEFENSIVE_PROFILE'])['EventPlayerID'].count().reset_index().pivot(\n            'SHOOTER_PROFILE', 'OFFENSIVE_DEFENSIVE_PROFILE', 'EventPlayerID')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"From the matrix above, it can be concluded that:\n    - Best short distance shooters are also best rebounders\n    - Average shooters are also average/good rebounders\n    - Players who are not a good shooter are mostly not very successful at assisting and rebounds"},{"metadata":{},"cell_type":"markdown","source":"#### ADD PLAYER PROFILES TO PLAYS"},{"metadata":{"trusted":true},"cell_type":"code","source":"player_profiles_1 = player_event_stats[['Key', 'EventPlayerID', 'Gender']].drop_duplicates()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"player_profiles_2 = player_event_mean[['EventPlayerID', 'OFFENSIVE_DEFENSIVE_PROFILE', 'SHOOTER_PROFILE']].drop_duplicates()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"player_profiles = player_profiles_1.merge(player_profiles_2, on=['EventPlayerID'], how='inner')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### COACH PROFILES"},{"metadata":{},"cell_type":"markdown","source":"Data is duplicate due to event type column, so firstly make it unique for each key"},{"metadata":{"trusted":true},"cell_type":"code","source":"coach_stats = team_event_stats_final[['Key', 'WinnerFlag', 'CoachName']].pivot_table(\n                index='CoachName', columns='WinnerFlag', values='Key', aggfunc='count').reset_index()\n\ncoach_stats.columns = ['CoachName', 'LoosingPlays', 'WinningPlays']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"coach_stats['TotalPlays'] = coach_stats['WinningPlays'] + coach_stats['LoosingPlays']\ncoach_stats['WinRatio'] = coach_stats['WinningPlays'] * 100 / coach_stats['TotalPlays']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"coach_stats.TotalPlays.hist();","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"coach_stats.WinRatio.hist();","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Total plays clearly indicate experience and winning ratio in total plays is the measure of success. So both information should be used in order to profile coaches correctly\n\nSimple ranking will be used based on quantiles "},{"metadata":{"trusted":true},"cell_type":"code","source":"def experience_rank(totalplays, lower, upper):\n    if totalplays <= lower:\n        return('LeastExperienced')\n    elif totalplays <= upper:\n        return('Experienced')\n    else:\n        return('MostExperienced')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def success_rank(totalplays, lower, upper):\n    if totalplays <= lower:\n        return('LeastSuccessful')\n    elif totalplays <= upper:\n        return('Successful')\n    else:\n        return('MostSuccessful')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"lower = coach_stats.TotalPlays.quantile(.33)\nupper = coach_stats.TotalPlays.quantile(.67)\n\ncoach_stats['ExperienceRank'] = coach_stats['TotalPlays'].apply(lambda x: experience_rank(x, lower, upper))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"lower = coach_stats.WinRatio.quantile(.33)\nupper = coach_stats.WinRatio.quantile(.67)\n\ncoach_stats['SuccessRank'] = coach_stats['WinRatio'].apply(lambda x: success_rank(x, lower, upper))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"coach_stats['CoachProfile'] = coach_stats[['ExperienceRank', 'SuccessRank']].apply(lambda x: x.ExperienceRank + '_' + x.SuccessRank, axis=1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Add coach profile to the team final data"},{"metadata":{"trusted":true},"cell_type":"code","source":"coach_dict = {str(c):str(p) for c,p in coach_stats[['CoachName', 'CoachProfile']].values}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"team_event_stats_final['CoachProfile'] = team_event_stats_final.CoachName.apply(lambda c: coach_dict[c])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Add player profile to the team final data"},{"metadata":{"trusted":true},"cell_type":"code","source":"player_profiles_offdef = player_profiles.pivot_table(index='Key', columns='OFFENSIVE_DEFENSIVE_PROFILE', values='EventPlayerID', \n                                                     aggfunc='count').reset_index().fillna(0)\nplayer_profiles_shooter = player_profiles.pivot_table(index='Key', columns='SHOOTER_PROFILE', values='EventPlayerID', \n                                                     aggfunc='count').reset_index().fillna(0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"player_dict1 = {str(c):str(p) for c,p in player_profiles[['EventPlayerID', 'OFFENSIVE_DEFENSIVE_PROFILE']].values}\nplayer_dict2 = {str(c):str(p) for c,p in player_profiles[['EventPlayerID', 'SHOOTER_PROFILE']].values}","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### FACTORS DETERMINING THE WINNER TEAM\n\nCoach and player profiles along with event statistics can be used to better quantify the factors affecting the result of plays and determining the winning team"},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}