{"cells":[{"metadata":{},"cell_type":"markdown","source":"# NFL Injury Analytics\n### Investigation the relationship between the playing surface and the injury and performance of NFL athletes."},{"metadata":{},"cell_type":"markdown","source":"**The aim of this data analysis is what are the causes of the injuries of NFL players. It is said that synthetic turf make higher injury rates than natural turf. Is it truth? Let's see the data! **"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport math\nimport statistics\nimport random\n\n%matplotlib inline\nimport matplotlib.pyplot as plt\nplt.style.use('ggplot')\nimport seaborn as sns\n\n# Convert to float32 or int16 to save memory usage\nplay_dtype = {'PlayDay': 'int16', 'PlayGame': 'int16', 'Temperature': 'float32'}\n\ntrk_dtype = {'time': 'float32', 'x': 'float32', 'y': 'float32', \n        'dis': 'float32', 's': 'float32', 'o': 'float32', 'dir': 'float32'}\n\ninj = pd.read_csv(\"../input/nfl-playing-surface-analytics/InjuryRecord.csv\")\nplay = pd.read_csv(\"../input/nfl-playing-surface-analytics/PlayList.csv\", dtype=play_dtype)\ntrk = pd.read_csv(\"../input/nfl-playing-surface-analytics/PlayerTrackData.csv\", dtype=trk_dtype)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data"},{"metadata":{},"cell_type":"markdown","source":"## Injury Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"inj.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('inj null')\nprint(inj.isnull().sum())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Injury record has missing values in PlayKey column. This indicates when the injuries occured is unknown.**"},{"metadata":{"trusted":true},"cell_type":"code","source":"inj[inj['GameID'].duplicated(keep=False)]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**One of injured had 2 body parts broken in a same play. **"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Convert the period of injuries into 4-grade.(M1: 0.25, M7: 0.5, M28: 0.75, M42: 1)\ndef GetInjuryGrade(x):\n    if x['DM_M42'] == 1:\n        return 1\n    elif x['DM_M42'] == 0 and x['DM_M28'] == 1:\n        return 0.75\n    elif x['DM_M28'] == 0 and x['DM_M7'] == 1:\n        return 0.5\n    elif x['DM_M7'] == 0 and x['DM_M1'] == 1:\n        return 0.25    \ninj['GetInjuryGrade'] = inj.apply(GetInjuryGrade, axis=1)\nprint('InjuryGrade Mean: {0:.3f}'.format(inj['GetInjuryGrade'].mean()))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Play List"},{"metadata":{"trusted":true},"cell_type":"code","source":"play.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('play null')\nprint(play.isnull().sum())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"InjPlayers = inj['PlayerKey'].unique()\nNoInjPlayers = play.loc[~play['PlayerKey'].isin(InjPlayers)]['PlayerKey'].unique()\nprint('InjPlayers: ', len(InjPlayers))\nprint('NoInjPlayers: ', len(NoInjPlayers))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**There are a lot of kinds of values in StadiumType, Weather and PlayType columns. So they should be converted into simple categorical values.**"},{"metadata":{"trusted":true},"cell_type":"code","source":"StadiumType_dict = {\n    'Outdoor': 'outdoor', 'Outdoors': 'outdoor', 'Indoors': 'indoor', 'Dome': 'indoor', \n    'Retractable Roof': 'indoor', 'Indoor': 'indoor', 'Open': 'outdoor', \n    'Domed, closed': 'indoor', 'Retr. Roof - Closed': 'indoor', \n    'Retr. Roof-Closed': 'indoor', 'Domed, open': 'outdoor', \n    'Dome, closed': 'indoor', 'Closed Dome': 'indoor', \n    'Domed': 'indoor', 'Oudoor': 'outdoor', 'Domed, Open': 'outdoor', \n    'Ourdoor': 'outdoor', 'Outdoor Retr Roof-Open': 'outdoor', 'Outddors': 'outdoor', \n    'Indoor, Roof Closed': 'indoor', 'Retr. Roof-Open': 'outdoor', \n    'Retr. Roof - Open': 'outdoor', 'Indoor, Open Roof': 'outdoor', 'Bowl': 'outdoor', \n    'Retr. Roof Closed': 'indoor', 'Heinz Field': 'outdoor', 'Outdor': 'outdoor', \n    'Outside': 'outdoor', 'Cloudy': 'outdoor', np.nan: np.nan\n}\n\nplay['StadiumType'] = play['StadiumType'].apply(lambda x: StadiumType_dict[x])\n\n\nWeather_dict = {\n    'Cloudy': 'overcast', 'Sunny': 'clear', 'Partly Cloudy': 'overcast', 'Clear': 'clear', \n    'Mostly Cloudy': 'overcast', 'Rain': 'rain', 'Controlled Climate': np.nan, \n    'N/A (Indoors)': np.nan, 'Indoors': np.nan, 'Mostly Sunny': 'clear',  'Indoor': np.nan, \n    'Partly Sunny': 'clear', 'Mostly cloudy': 'clear', \n    'Fair': 'clear', 'N/A Indoor': np.nan, \n    'Light Rain': 'rain', 'Partly cloudy': 'overcast', 'Clear and warm': 'clear', \n    'Mostly sunny': 'clear', 'Hazy': 'overcast', 'cloudy': 'overcast', \n    'Snow': 'snow', 'Overcast': 'overcast', \n    'Clear Skies': 'clear', 'Cloudy and Cool': 'overcast', 'Clear skies': 'clear', \n    'Cloudy, 50% change of rain': 'rain', \n    'Cloudy, fog started developing in 2nd quarter': 'overcast', \n    'Clear and cold': 'clear', \n    'Partly clear': 'clear', 'Cloudy and cold': 'overcast', \n    'Sunny and clear': 'clear', 'Rain Chance 40%': 'overcast', \n    'Sunny and warm': 'clear', 'Clear and Cool': 'clear', \n    'Sunny, highs to upper 80s': 'clear', 'Sunny Skies': 'clear', \n    'Cloudy, light snow accumulating 1-3\"': 'snow', 'Scattered Showers': 'rain', \n    'Clear and Sunny': 'clear', 'Mostly Coudy': 'overcast', \n    'Rain likely, temps in low 40s.': 'rain', 'Cold': 'overcast', \n    'Sunny and cold': 'clear', 'Partly sunny': 'clear', 'Showers': 'rain', \n    'Rainy': 'rain', 'Clear to Partly Cloudy': 'clear', \n    'Clear and sunny': 'clear', 'Sunny, Windy': 'clear', 'Rain shower': 'rain', \n    'Cloudy, chance of rain': 'overcast', 'Heat Index 95': 'clear', \n    'Mostly Sunny Skies': 'clear', '10% Chance of Rain': 'overcast', \n    'Sun & clouds': 'clear', 'Cloudy, Rain': 'rain', 'Heavy lake effect snow': 'snow', \n    '30% Chance of Rain': 'overcast', 'Partly Clouidy': 'overcast', \n    'Coudy': 'overcast', \n    'Cloudy with periods of rain, thunder possible. Winds shifting to WNW, 10-20 mph.': 'rain', \n    'Party Cloudy': 'overcast', np.nan: np.nan\n}   \n\nplay['Weather'] = play['Weather'].apply(lambda x: Weather_dict[x])\n\n\nPlayTypeDict = {\n    'Pass': 'Pass', \n    'Rush': 'Rush', \n    'Extra Point': 'Extra Point', \n    'Kickoff': 'Kickoff', \n    'Punt': 'Punt', \n    'Field Goal': 'Field Goal', \n    'Kickoff Not Returned': 'Kickoff', \n    'Punt Not Returned': 'Punt', \n    'Kickoff Returned': 'Kickoff', \n    'Punt Returned': 'Punt', \n    '0': np.nan, \n    np.nan: np.nan\n}\n\nplay['PlayType'] = play['PlayType'].apply(lambda x: PlayTypeDict[x])\n\n\nplay.loc[play['PositionGroup'] == 'Missing Data', 'PositionGroup'] = np.nan","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"play.loc[play['StadiumType'] != 'indoor']['Temperature'].value_counts().sort_index()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Temperature unknown is sometimes -999.0. It should be missing value.\nplay.loc[play['Temperature'] == -999.0, 'Temperature'] = np.nan\noutdoor_temp = play.loc[(play['StadiumType'] == 'outdoor')&(play['Temperature'].notnull())].drop_duplicates(subset='GameID')['Temperature']\ntemp_q25, temp_q50, temp_q75 = np.percentile(outdoor_temp, [25, 50, 75])\nTemperatureMean = outdoor_temp.mean()\nTemperatureStd = outdoor_temp.std()\noutdoor_temp.hist(bins=75)\nprint('Temperature outdoor\\nMean: {0:.3f}\\nStd: {1:.3f}'.format(TemperatureMean, TemperatureStd))\nprint('Quartile \\n25th: {}\\n75th: {}'.format(temp_q25, temp_q75))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"game_num = play['GameID'].unique().shape[0]\noutdoor_natural = play[(play['StadiumType'] == 'outdoor')&(play['FieldType'] == 'Natural')]['GameID'].unique().shape[0]\nindoor_natural = play[(play['StadiumType'] == 'indoor')&(play['FieldType'] == 'Natural')]['GameID'].unique().shape[0]\noutdoor_synthetic = play[(play['StadiumType'] == 'outdoor')&(play['FieldType'] == 'Synthetic')]['GameID'].unique().shape[0]\nindoor_synthetic = play[(play['StadiumType'] == 'indoor')&(play['FieldType'] == 'Synthetic')]['GameID'].unique().shape[0]\n\nfig = plt.figure(figsize=(6, 4))\nax1 = fig.add_subplot(111)\nax1.bar(\n    range(4), np.array([outdoor_natural, indoor_natural, outdoor_synthetic, indoor_synthetic])/game_num*100, \n    tick_label=['out_nat', 'in_nat', 'out_syn', 'in_syn'], color='darkgreen', width=0.8, alpha=0.5)\nax1.set_xlabel('StadiumType/FieldType')\nax1.set_ylabel('Ratio(%)')\n\nfps = {\n    'family': 'monospace', \n    'weight': 'heavy', \n    'size': 20,\n    'color': 'black'\n}\nfor i, stadium_field_type in enumerate([outdoor_natural, indoor_natural, outdoor_synthetic, indoor_synthetic]):\n    ax1.text(i, 10, '{0:.1f}%'.format(stadium_field_type/game_num*100), alpha=0.8, horizontalalignment='center', fontdict=fps)\nax1.set_title('Stadium/Field type ratio', \n              fontdict={'family': 'sans-serif', 'weight': 'bold','size': 18,}\n             )\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Most of Games have played in outdoor stadium with natural turf.**"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig = plt.figure(figsize=(4, 4))\n\nax1 = fig.add_subplot(111)\nax1.pie(\n    play['PlayType'].value_counts().sort_values(ascending=False).values, \n    labels = play['PlayType'].value_counts().sort_values(ascending=False).index, \n    labeldistance = 1.1, \n    textprops = {'fontsize': 12}, \n)\nax1.set_title('Play type ratio', \n              fontdict={'family': 'sans-serif', 'weight': 'bold','size': 18,}\n             )\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Most of plays are Pass and Rush.**"},{"metadata":{"trusted":true},"cell_type":"code","source":"inj_detailed = pd.merge(inj, play[['GameID', 'PlayerDay', 'FieldType', 'StadiumType', 'Temperature', 'Weather', 'Position', 'PositionGroup', 'RosterPosition']].drop_duplicates(subset='GameID'), on='GameID', how='left')\ninj_detailed = pd.merge(inj_detailed, play[['PlayKey', 'PlayerGamePlay']], on='PlayKey', how='left')\ninj_detailed.drop(columns=['Surface'], inplace=True)\ninj_detailed.loc[inj_detailed['PlayKey'].notnull(), 'PlayType'] = inj_detailed.loc[inj_detailed['PlayKey'].notnull()].apply(lambda x: play.loc[play['PlayKey']==x['PlayKey'], 'PlayType'].iloc[0], axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# Injury probablity per PlayType\nPlayTypeCount = play.groupby('PlayType')['PlayerKey'].count().reset_index()\nPlayTypeCount.columns = ['PlayType', 'PlayTypeCount']\nInjPlayTypeCount = inj_detailed.groupby('PlayType')['PlayerKey'].count().reset_index()\nInjPlayTypeCount.columns = ['PlayType', 'InjPlayTypeCount']\nInjPRPlayType = pd.merge(PlayTypeCount, InjPlayTypeCount, on='PlayType', how='left')\nInjPRPlayType['PRPlayType'] = (InjPRPlayType['InjPlayTypeCount'] / InjPRPlayType['PlayTypeCount'])*100\nInjPRPlayType['PRPlayType'].fillna(0, inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig = plt.figure(figsize=(6, 4))\n\nax1 = fig.add_subplot(111)\nax1.bar(np.arange(0, len(InjPRPlayType)*2, 2), InjPRPlayType['PRPlayType'], tick_label=InjPRPlayType['PlayType'], color='yellow', width=1, alpha=0.75)\nax1.set_xlabel('PlayType')\nax1.set_ylabel('Probablity(%)')\nax1.set_ylim([0, 0.12])\nfps = {\n    'family': 'monospace', \n    'weight': 'heavy', \n    'size': 12,\n    'color': 'darkred'\n}\nax1.text(0, 0.09, 'Punt and Kickoff play \\nincrease the risk of injury?', alpha=0.75, fontdict=fps)\nax1.grid(False)\nax1.set_title('Injury probablity by play type', \n              fontdict={'family': 'sans-serif', 'weight': 'bold','size': 18,}\n             )\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# Injury probablity per PositionGroup\nPosCount = play.groupby('PositionGroup')['PlayerKey'].count().reset_index()\nPosCount.columns = ['PositionGroup', 'PosCount']\nInjPosCount = inj_detailed.groupby('PositionGroup')['PlayerKey'].count().reset_index()\nInjPosCount.columns = ['PositionGroup', 'InjPosCount']\nInjPRPos = pd.merge(PosCount, InjPosCount, on='PositionGroup', how='left')\nInjPRPos['PRPos'] = (InjPRPos['InjPosCount'] / InjPRPos['PosCount'])*100\nInjPRPos['PRPos'].fillna(0, inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig = plt.figure(figsize=(6, 4))\n\nax1 = fig.add_subplot(111)\nax1.bar(np.arange(0, len(InjPRPos)*2, 2), InjPRPos['PRPos'], tick_label=InjPRPos['PositionGroup'], color='yellow', width=1, alpha=0.75)\nax1.set_xlabel('PositionGroup')\nax1.set_ylabel('Probablity(%)')\n#ax1.set_ylim([0, 0.12])\nfps = {\n    'family': 'monospace', \n    'weight': 'heavy', \n    'size': 12,\n    'color': 'darkred'\n}\nax1.text(0, 0.06, 'RB and TE \\nincrease the risk of injury?', alpha=1, fontdict=fps)\nax1.grid(False)\nax1.set_title('Injury probablity by position group', \n              fontdict={'family': 'sans-serif', 'weight': 'bold','size': 18,}\n             )\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Player Track Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"print('trk null')\nprint(trk.isnull().sum())\nNoTrkPKs = play.loc[~play['PlayKey'].isin(trk['PlayKey'].unique())]['PlayKey'].unique()\nprint(len(NoTrkPKs), 'playkeys have no track data.')\nNoTrkPKs = list(NoTrkPKs)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"trk['event'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Plays start at some events (ball_snap, snap_direct, kickoff, free_kick)\n# Movement before a play start such as huddle might not be related to injuries.\n# Plays not including these event should be excluded.\nplay_start = ['ball_snap', 'snap_direct', 'kickoff', 'onside_kick', 'free_kick']\n\ndef GetNoPlayStart(d):\n    if (d['event'].isin(play_start)).any():\n        return False\n    else:\n        return True\n\nplay_start_series = trk.groupby('PlayKey').apply(GetNoPlayStart)\nno_play_start_pks = play_start_series[play_start_series==True].index\ntrk = trk[~trk['PlayKey'].isin(no_play_start_pks)]\nNoTrkPKs += list(no_play_start_pks)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Player's movement\n**In order to focus on movement, other factors should be unified as possible. Weather outdoor is clear or overcast. Temperature is between quartile 25th and 75th. In other words, we just analyze plays on good condition. **"},{"metadata":{"trusted":true},"cell_type":"code","source":"LowTemp, HighTemp = temp_q25, temp_q75\n\n\nInjPKs = list(inj_detailed.loc[inj_detailed['PlayKey'].notnull()]['PlayKey'].unique())\nInjNoPKsGameID = list(inj_detailed.loc[inj_detailed['PlayKey'].isnull()]['GameID'].unique())\nInjNoPKs = list(play.loc[play['GameID'].isin(InjNoPKsGameID)]['PlayKey'].unique())\n\nInjPKsGoodCond = list(inj_detailed.loc[\n    (inj_detailed['PlayKey'].notnull())\n    &(~play['PlayKey'].isin(NoTrkPKs))\n    &((inj_detailed['StadiumType']=='indoor')\n    |((inj_detailed['Weather'].isin(['clear', 'overcast']))\n    &(inj_detailed['Temperature'] <= HighTemp)\n    &(inj_detailed['Temperature'] >= LowTemp)))\n]['PlayKey'].unique())\n\nNoInjPKs = list(play.loc[(~play['PlayKey'].isin(InjPKs+InjNoPKs))]['PlayKey'].unique())\n\nNoInjPKsGoodCond = list(play.loc[\n    (play['PlayKey'].isin(NoInjPKs))\n    &(~play['PlayKey'].isin(NoTrkPKs))\n    &((play['StadiumType']=='indoor')\n    |((play['Weather'].isin(['clear', 'overcast']))\n    &(play['Temperature'] <= HighTemp)\n    &(play['Temperature'] >= LowTemp)))\n]['PlayKey'].unique())\n\n\nSampNoInjPKsGoodCond = random.sample(list(NoInjPKsGoodCond), 10000)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* Max speed\n* Directional changes\n* Acceleration/Deceleration\n* Distance"},{"metadata":{},"cell_type":"markdown","source":"### Max speed"},{"metadata":{"trusted":true},"cell_type":"code","source":"def GetMaxSpeed(d):\n    d['distance'] = np.sqrt(\n        (d['x'] - d['x'].shift(1))**2 + (d['y'] - d['y'].shift(1))**2\n    )\n    d['speed'] = d['distance'] / (d['time'] - d['time'].shift(1))\n    play_d = d[\n        d['time'] >= d.loc[d['event'].isin(play_start), 'time'].min() - 3.0\n    ]\n    return pd.Series(play_d['speed'].max())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"InjMaxSpeed = trk[trk['PlayKey'].isin(InjPKsGoodCond)].groupby('PlayKey').apply(GetMaxSpeed).reset_index(level='PlayKey')\nInjMaxSpeed.columns = ['PlayKey', 'MaxSpeed']\ninj_mvt = pd.merge(inj_detailed, InjMaxSpeed, on='PlayKey', how='left')\n\nNoInjMaxSpeed = trk[trk['PlayKey'].isin(SampNoInjPKsGoodCond)].groupby('PlayKey').apply(GetMaxSpeed).reset_index(level='PlayKey')\nNoInjMaxSpeed.columns = ['PlayKey', 'MaxSpeed']\nnoinj_mvt = pd.merge(play, NoInjMaxSpeed, on='PlayKey', how='left')\n\n# Fix abnormal values\ninj_mvt.loc[inj_mvt['MaxSpeed'] > 10, 'MaxSpeed'] = 10\nnoinj_mvt.loc[noinj_mvt['MaxSpeed'] > 10, 'MaxSpeed'] = 10","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig = plt.figure(figsize=(12, 10))\ngrid = plt.GridSpec(3, 2, hspace=0.5, wspace=0.1)\n\nax1 = fig.add_subplot(grid[0, :])\nhist1 = inj_mvt.loc[inj_mvt['MaxSpeed'].notnull()]['MaxSpeed']\nhist2 = noinj_mvt.loc[noinj_mvt['MaxSpeed'].notnull()]['MaxSpeed']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax1.hist(hist1, bins=25, range=(0, 12), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='Inj')\nax1.hist(hist2, bins=100, range=(0, 12), density=True, color='green', alpha=0.5, label='NoInj')\nax1.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='InjMedian')\nax1.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\nax1.annotate('', xy=(axvline1, 0.2), size=15, xytext=(axvline2, 0.2), \n             arrowprops=dict(arrowstyle='simple', color='darkred'))\n\nhandles, labels = ax1.get_legend_handles_labels()\nhandles[0], handles[1], handles[2], handles[3] = handles[1], handles[0], handles[3], handles[2]\nlabels[0], labels[1], labels[2], labels[3] = labels[1], labels[0], labels[3], labels[2]\nax1.legend(handles[::-1], labels[::-1], ncol=2, bbox_to_anchor=(1, 1))\n\nax1.set_xlabel('MaxSpeed(y/s)')\nax1.set_ylabel('Percent(%)')\n\nfps = {\n    'family': 'monospace', \n    'weight': 'heavy', \n    'size': 16,\n    'color': 'darkred'\n}\nax1.text(0, 0.25, 'Injured players had \\nhigher max speed \\n(median: {} > {})'.format(round(axvline1, 2), round(axvline2, 2)), alpha=0.75, fontdict=fps)\n\nfont = {'family': 'sans-serif',\n        'color':  'black',\n        'weight': 'bold',\n        'size': 16,\n        }\nax1.set_ylim([0, 0.4])\nax1.set_title('Injury vs NoInjury', fontdict=font)\n\n\nax2 = fig.add_subplot(grid[1, :])\nhist1 = inj_mvt.loc[(inj_mvt['MaxSpeed'].notnull())&(inj_mvt['BodyPart']=='Knee')]['MaxSpeed']\nhist2 = noinj_mvt.loc[noinj_mvt['MaxSpeed'].notnull()]['MaxSpeed']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\n\nax2.hist(hist1, bins=25, range=(0, 12), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='KneeInj')\nax2.hist(hist2, bins=100, range=(0, 12), density=True, color='green', alpha=0.5, label='NoInj')\nax2.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='KneeInjMedian')\nax2.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\nax2.annotate('', xy=(axvline1, 0.2), size=15, xytext=(axvline2, 0.2), \n             arrowprops=dict(arrowstyle='simple', color='darkred'))\n\nfps = {\n    'family': 'monospace', \n    'weight': 'heavy', \n    'size': 16,\n    'color': 'darkred'\n}\nax2.text(0, 0.25, 'High max speed increase \\nknee injury risk? ', alpha=0.75, fontdict=fps)\n\nfont = {'family': 'sans-serif',\n        'color':  'black',\n        'weight': 'bold',\n        'size': 16,\n        }\nax2.set_ylim([0, 0.4])\nax2.set_title('KneeInjury vs NoInjury', fontdict=font)\n\n\nax3 = fig.add_subplot(grid[2, 0])\nhist1 = inj_mvt.loc[(inj_mvt['MaxSpeed'].notnull())&(inj_mvt['FieldType']=='Natural')]['MaxSpeed']\nhist2 = noinj_mvt.loc[(noinj_mvt['MaxSpeed'].notnull())&(noinj_mvt['FieldType']=='Natural')]['MaxSpeed']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax3.hist(hist1, bins=25, range=(0, 12), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='KneeInj')\nax3.hist(hist2, bins=100, range=(0, 12), density=True, color='green', alpha=0.5, label='NoInj')\nax3.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='KneeInjMedian')\nax3.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\n\nax3.set_ylim([0, 0.4])\nax3.set_title('Injury vs NoInjury (OnNatTurf)', fontdict=font)\n\n\nax4 = fig.add_subplot(grid[2, 1])\nhist1 = inj_mvt.loc[(inj_mvt['MaxSpeed'].notnull())&(inj_mvt['FieldType']=='Synthetic')]['MaxSpeed']\nhist2 = noinj_mvt.loc[(noinj_mvt['MaxSpeed'].notnull())&(noinj_mvt['FieldType']=='Synthetic')]['MaxSpeed']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax4.hist(hist1, bins=25, range=(0, 12), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='KneeInj')\nax4.hist(hist2, bins=100, range=(0, 12), density=True, color='green', alpha=0.5, label='NoInj')\nax4.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='KneeInjMedian')\nax4.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\n\nax4.set_ylim([0, 0.4])\nax4.set_title('Injury vs NoInjury (OnSynTurf)', fontdict=font)\n\n\nfig.suptitle('Max Speed', fontweight='bold', size=24)\nfig.subplots_adjust(left=0.1, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Direction changes"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Direction change degree per 1/10th of a second mean\ndef GetDirChg(d):\n    d['dir_chg'] = abs(d['dir'] - d['dir'].shift(1))\n    d.loc[d['dir_chg'] > 180, 'dir_chg'] = 360 - d['dir_chg']\n    play_d = d[\n        d['time'] >= d.loc[d['event'].isin(play_start), 'time'].min() - 3.0\n    ] \n    return play_d['dir_chg'].mean()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"InjDirChg = trk[trk['PlayKey'].isin(InjPKsGoodCond)].groupby('PlayKey').apply(GetDirChg).reset_index(level='PlayKey')\nInjDirChg.columns = ['PlayKey', 'DirChg']\ninj_mvt = pd.merge(inj_mvt, InjDirChg, on='PlayKey', how='left')\n\nNoInjDirChg = trk[trk['PlayKey'].isin(SampNoInjPKsGoodCond)].groupby('PlayKey').apply(GetDirChg).reset_index(level='PlayKey')\nNoInjDirChg.columns = ['PlayKey', 'DirChg']\nnoinj_mvt = pd.merge(noinj_mvt, NoInjDirChg, on='PlayKey', how='left')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig = plt.figure(figsize=(12, 10))\ngrid = plt.GridSpec(3, 2, hspace=0.5, wspace=0.1)\n\nax1 = fig.add_subplot(grid[0, :])\nhist1 = inj_mvt.loc[inj_mvt['DirChg'].notnull()]['DirChg']\nhist2 = noinj_mvt.loc[noinj_mvt['DirChg'].notnull()]['DirChg']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax1.hist(hist1, bins=25, range=(0, 12), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='Inj')\nax1.hist(hist2, bins=100, range=(0, 12), density=True, color='green', alpha=0.5, label='NoInj')\nax1.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='InjMedian')\nax1.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\nax1.annotate('', xy=(axvline1, 0.2), size=15, xytext=(axvline2, 0.2), \n             arrowprops=dict(arrowstyle='simple', color='darkred'))\n\nhandles, labels = ax1.get_legend_handles_labels()\nhandles[0], handles[1], handles[2], handles[3] = handles[1], handles[0], handles[3], handles[2]\nlabels[0], labels[1], labels[2], labels[3] = labels[1], labels[0], labels[3], labels[2]\nax1.legend(handles[::-1], labels[::-1], ncol=2, bbox_to_anchor=(1, 1))\n\nax1.set_xlabel('DirChg(deg)')\nax1.set_ylabel('Percent(%)')\n\nfps = {\n    'family': 'monospace', \n    'weight': 'heavy', \n    'size': 16,\n    'color': 'darkred'\n}\nax1.text(0, 0.25, 'Injured players changed \\nmore direction \\n(median: {} > {})'.format(round(axvline1, 2), round(axvline2, 2)), alpha=0.75, fontdict=fps)\n\nfont = {'family': 'sans-serif',\n        'color':  'black',\n        'weight': 'bold',\n        'size': 16,\n        }\nax1.set_ylim([0, 0.4])\nax1.set_title('Injury vs NoInjury', fontdict=font)\n\n\nax2 = fig.add_subplot(grid[1, 0])\nhist1 = inj_mvt.loc[(inj_mvt['DirChg'].notnull())&(inj_mvt['BodyPart']=='Knee')]['DirChg']\nhist2 = noinj_mvt.loc[noinj_mvt['DirChg'].notnull()]['DirChg']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax2.hist(hist1, bins=25, range=(0, 12), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='KneeInj')\nax2.hist(hist2, bins=100, range=(0, 12), density=True, color='green', alpha=0.5, label='NoInj')\nax2.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='KneeInjMedian')\nax2.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\nax2.annotate('', xy=(axvline1, 0.2), size=15, xytext=(axvline2, 0.2), \n             arrowprops=dict(arrowstyle='simple', color='darkred'))\n\nfont = {'family': 'sans-serif',\n        'color':  'black',\n        'weight': 'bold',\n        'size': 16,\n        }\nax2.set_title('KneeInjury vs NoInjury', fontdict=font)\nax2.set_ylim([0, 0.4])\n\n\nax3 = fig.add_subplot(grid[1, 1])\nhist1 = inj_mvt.loc[(inj_mvt['DirChg'].notnull())&(inj_mvt['BodyPart']=='Ankle')]['DirChg']\nhist2 = noinj_mvt.loc[noinj_mvt['DirChg'].notnull()]['DirChg']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax3.hist(hist1, bins=25, range=(0, 12), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='AnkleInj')\nax3.hist(hist2, bins=100, range=(0, 12), density=True, color='green', alpha=0.5, label='NoInj')\nax3.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='AnkleInjMedian')\nax3.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\nax3.annotate('', xy=(axvline1, 0.2), size=15, xytext=(axvline2, 0.2), \n             arrowprops=dict(arrowstyle='simple', color='darkred'))\n\nfont = {'family': 'sans-serif',\n        'color':  'black',\n        'weight': 'bold',\n        'size': 16,\n        }\nax3.set_title('AnkleInjury vs NoInjury', fontdict=font)\nax3.set_ylim([0, 0.4])\n\n\nax4 = fig.add_subplot(grid[2, 0])\nhist1 = inj_mvt.loc[(inj_mvt['DirChg'].notnull())&(inj_mvt['FieldType']=='Natural')&(inj_mvt['BodyPart']=='Ankle')]['DirChg']\nhist2 = noinj_mvt.loc[(noinj_mvt['DirChg'].notnull())&(noinj_mvt['FieldType']=='Natural')]['DirChg']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax4.hist(hist1, bins=25, range=(0, 12), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='KneeInj')\nax4.hist(hist2, bins=100, range=(0, 12), density=True, color='green', alpha=0.5, label='NoInj')\nax4.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='KneeInjMedian')\nax4.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\n\nax4.set_ylim([0, 0.4])\nax4.set_title('Injury vs NoInjury (OnNatTurf)', fontdict=font)\n\n\nax5 = fig.add_subplot(grid[2, 1])\nhist1 = inj_mvt.loc[(inj_mvt['DirChg'].notnull())&(inj_mvt['FieldType']=='Synthetic')&(inj_mvt['BodyPart']=='Ankle')]['DirChg']\nhist2 = noinj_mvt.loc[(noinj_mvt['DirChg'].notnull())&(noinj_mvt['FieldType']=='Synthetic')]['DirChg']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax5.hist(hist1, bins=25, range=(0, 12), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='KneeInj')\nax5.hist(hist2, bins=100, range=(0, 12), density=True, color='green', alpha=0.5, label='NoInj')\nax5.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='KneeInjMedian')\nax5.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\n\nax5.set_ylim([0, 0.4])\nax5.set_title('Injury vs NoInjury (OnSynTurf)', fontdict=font)\n\n\nfig.suptitle('Direction change per a tenth of a second', fontweight='bold', size=24)\nfig.subplots_adjust(left=0.1, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Acceleration/Deceleration"},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"eg_pk = '46074-7-26'\neg_trk = trk[trk['PlayKey'] == eg_pk]\neg_trk['distance'] = np.sqrt(\n    (eg_trk['x'] - eg_trk['x'].shift(1))**2 + (eg_trk['y'] - eg_trk['y'].shift(1))**2\n)\neg_trk['speed'] = eg_trk['distance'] / (eg_trk['time'] - eg_trk['time'].shift(1))\neg_trk['accdec'] = (eg_trk['speed'] - eg_trk['speed'].shift(1)) / (eg_trk['time'] - eg_trk['time'].shift(1))\nplay_eg_trk = eg_trk[\n    eg_trk['time'] >= eg_trk.loc[eg_trk['event'].isin(play_start), 'time'].min() - 3.0\n]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"play_eg_trk['accdec'].reset_index(drop=True).plot()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**We use Fourier transform to change this complicated waveform graph to simple graph.**"},{"metadata":{"trusted":true},"cell_type":"code","source":"f = play_eg_trk.loc[play_eg_trk['accdec'].notnull()]['accdec'].values\nF = abs(np.fft.fft(f)/(len(f)/2))  # normalization\nF = F[:int((len(f)/2))]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(range(len(F)), F)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**This graph shows that if x and y larger, the speed in the play more changed. If x is large, y is evaluated to represet acceleration and deceleration.**"},{"metadata":{"trusted":true},"cell_type":"code","source":"def GetAccDec(d):\n    d['distance'] = np.sqrt(\n        (d['x'] - d['x'].shift(1))**2 + (d['y'] - d['y'].shift(1))**2\n    )\n    d['speed'] = d['distance'] / (d['time'] - d['time'].shift(1))\n    d['accdec'] = (d['speed'] - d['speed'].shift(1)) / (d['time'] - d['time'].shift(1))\n    play_d = d[\n        d['time'] >= d.loc[d['event'].isin(play_start), 'time'].min() - 3.0\n    ]\n    f = play_d.loc[play_d['accdec'].notnull()]['accdec'].to_list()\n    F = abs(np.fft.fft(f)/(len(f)/2))\n    F = F[:int((len(f)/2))]\n    return np.sum([math.log(i+1)*n for i, n in enumerate(F)])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"InjAccDec = trk[trk['PlayKey'].isin(InjPKsGoodCond)].groupby('PlayKey').apply(GetAccDec).reset_index(level='PlayKey')\nInjAccDec.columns = ['PlayKey', 'AccDec']\ninj_mvt = pd.merge(inj_mvt, InjAccDec, on='PlayKey', how='left')\n\nNoInjAccDec = trk[trk['PlayKey'].isin(SampNoInjPKsGoodCond)].groupby('PlayKey').apply(GetAccDec).reset_index(level='PlayKey')\nNoInjAccDec.columns = ['PlayKey', 'AccDec']\nnoinj_mvt = pd.merge(noinj_mvt, NoInjAccDec, on='PlayKey', how='left')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig = plt.figure(figsize=(12, 10))\ngrid = plt.GridSpec(3, 2, hspace=0.5, wspace=0.1)\n\nax1 = fig.add_subplot(grid[0, :])\nhist1 = inj_mvt.loc[inj_mvt['AccDec'].notnull()]['AccDec']\nhist2 = noinj_mvt.loc[noinj_mvt['AccDec'].notnull()]['AccDec']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax1.hist(hist1, bins=25, range=(0, 300), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='Inj')\nax1.hist(hist2, bins=100, range=(0, 300), density=True, color='green', alpha=0.5, label='NoInj')\nax1.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='InjMedian')\nax1.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\nax1.annotate('', xy=(axvline1, 0.01), size=15, xytext=(axvline2, 0.01), \n             arrowprops=dict(arrowstyle='simple', color='darkred'))\n\nhandles, labels = ax1.get_legend_handles_labels()\nhandles[0], handles[1], handles[2], handles[3] = handles[1], handles[0], handles[3], handles[2]\nlabels[0], labels[1], labels[2], labels[3] = labels[1], labels[0], labels[3], labels[2]\nax1.legend(handles[::-1], labels[::-1], ncol=2, bbox_to_anchor=(1, 1))\n\nax1.set_xlabel('AccDec')\nax1.set_ylabel('Percent(%)')\n\nfps = {\n    'family': 'monospace', \n    'weight': 'heavy', \n    'size': 16,\n    'color': 'darkred'\n}\nax1.text(200, 0.005, 'Injured players changed \\nspeed frecuently? \\n(median: {} > {})'.format(round(axvline1, 2), round(axvline2, 2)), alpha=0.75, fontdict=fps)\n\nfont = {'family': 'sans-serif',\n        'color':  'black',\n        'weight': 'bold',\n        'size': 16,\n        }\nax1.set_ylim([0, 0.025])\nax1.set_title('Injury vs NoInjury', fontdict=font)\n\n\nax2 = fig.add_subplot(grid[1, 0])\nhist1 = inj_mvt.loc[(inj_mvt['AccDec'].notnull())&(inj_mvt['BodyPart']=='Knee')]['AccDec']\nhist2 = noinj_mvt.loc[noinj_mvt['AccDec'].notnull()]['AccDec']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax2.hist(hist1, bins=25, range=(0, 300), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='KneeInj')\nax2.hist(hist2, bins=100, range=(0, 300), density=True, color='green', alpha=0.5, label='NoInj')\nax2.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='KneeInjMedian')\nax2.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\n\nfont = {'family': 'sans-serif',\n        'color':  'black',\n        'weight': 'bold',\n        'size': 16,\n        }\nax2.set_ylim([0, 0.025])\nax2.set_title('KneeInjury vs NoInjury', fontdict=font)\n\n\nax3 = fig.add_subplot(grid[1, 1])\nhist1 = inj_mvt.loc[(inj_mvt['AccDec'].notnull())&(inj_mvt['BodyPart']=='Ankle')]['AccDec']\nhist2 = noinj_mvt.loc[noinj_mvt['AccDec'].notnull()]['AccDec']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax3.hist(hist1, bins=25, range=(0, 300), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='AnkleInj')\nax3.hist(hist2, bins=100, range=(0, 300), density=True, color='green', alpha=0.5, label='NoInj')\nax3.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='AnkleInjMedian')\nax3.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\n\nfont = {'family': 'sans-serif',\n        'color':  'black',\n        'weight': 'bold',\n        'size': 16,\n        }\nax3.set_ylim([0, 0.025])\nax3.set_title('AnkleInjury vs NoInjury', fontdict=font)\n\n\n\nax4 = fig.add_subplot(grid[2, 0])\nhist1 = inj_mvt.loc[(inj_mvt['AccDec'].notnull())&(inj_mvt['FieldType']=='Natural')]['AccDec']\nhist2 = noinj_mvt.loc[(noinj_mvt['AccDec'].notnull())&(noinj_mvt['FieldType']=='Natural')]['AccDec']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax4.hist(hist1, bins=25, range=(0, 300), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='KneeInj')\nax4.hist(hist2, bins=100, range=(0, 300), density=True, color='green', alpha=0.5, label='NoInj')\nax4.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='KneeInjMedian')\nax4.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\n\nax4.set_ylim([0, 0.025])\nax4.set_title('Injury vs NoInjury (OnNatTurf)', fontdict=font)\n\n\nax5 = fig.add_subplot(grid[2, 1])\nhist1 = inj_mvt.loc[(inj_mvt['AccDec'].notnull())&(inj_mvt['FieldType']=='Synthetic')]['AccDec']\nhist2 = noinj_mvt.loc[(noinj_mvt['AccDec'].notnull())&(noinj_mvt['FieldType']=='Synthetic')]['AccDec']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax5.hist(hist1, bins=25, range=(0, 300), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='KneeInj')\nax5.hist(hist2, bins=100, range=(0, 300), density=True, color='green', alpha=0.5, label='NoInj')\nax5.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='KneeInjMedian')\nax5.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\n\nax5.set_ylim([0, 0.025])\nax5.set_title('Injury vs NoInjury (OnSynTurf)', fontdict=font)\n\n\nfig.suptitle('Acc/Dec frecuency by Fourier transform', fontweight='bold', size=24)\nfig.subplots_adjust(left=0.1, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Distance"},{"metadata":{"trusted":true},"cell_type":"code","source":"def GetDistance(d):\n    d['Distance'] = np.sqrt(\n        (d['x'] - d['x'].shift(1))**2 + (d['y'] - d['y'].shift(1))**2\n    )\n    play_d = d[\n        d['time'] >= d.loc[d['event'].isin(play_start), 'time'].min() - 3.0\n    ]\n    return play_d['Distance'].sum()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"InjDistance = trk[trk['PlayKey'].isin(InjPKsGoodCond)].groupby('PlayKey').apply(GetDistance).reset_index(level='PlayKey')\nInjDistance.columns = ['PlayKey', 'Distance']\ninj_mvt = pd.merge(inj_mvt, InjDistance, on='PlayKey', how='left')\n\nNoInjDistance = trk[trk['PlayKey'].isin(SampNoInjPKsGoodCond)].groupby('PlayKey').apply(GetDistance).reset_index(level='PlayKey')\nNoInjDistance.columns = ['PlayKey', 'Distance']\nnoinj_mvt = pd.merge(noinj_mvt, NoInjDistance, on='PlayKey', how='left')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig = plt.figure(figsize=(12, 10))\ngrid = plt.GridSpec(3, 2, hspace=0.5, wspace=0.1)\nax1 = fig.add_subplot(grid[0, :])\nhist1 = inj_mvt.loc[inj_mvt['Distance'].notnull()]['Distance']\nhist2 = noinj_mvt.loc[noinj_mvt['Distance'].notnull()]['Distance']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax1.hist(hist1, bins=25, range=(0, 150), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='Inj')\nax1.hist(hist2, bins=100, range=(0, 150), density=True, color='green', alpha=0.5, label='NoInj')\nax1.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='InjMedian')\nax1.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\nax1.annotate('', xy=(axvline1, 0.02), size=15, xytext=(axvline2, 0.02), \n             arrowprops=dict(arrowstyle='simple', color='darkred'))\n\nhandles, labels = ax1.get_legend_handles_labels()\nhandles[0], handles[1], handles[2], handles[3] = handles[1], handles[0], handles[3], handles[2]\nlabels[0], labels[1], labels[2], labels[3] = labels[1], labels[0], labels[3], labels[2]\nax1.legend(handles[::-1], labels[::-1], ncol=2, bbox_to_anchor=(1, 1))\n\nax1.set_xlabel('AccDec')\nax1.set_ylabel('Percent(%)')\n\nfps = {\n    'family': 'monospace', \n    'weight': 'heavy', \n    'size': 16,\n    'color': 'darkred'\n}\n#ax1.text(0, 0.25, 'Injuries changed \\nmore direction \\n(median: {} > {})'.format(round(axvline1, 2), round(axvline2, 2)), alpha=0.75, fontdict=fps)\n\nfont = {'family': 'sans-serif',\n        'color':  'black',\n        'weight': 'bold',\n        'size': 16,\n        }\nax1.set_ylim([0, 0.04])\nax1.set_title('Injury vs NoInjury', fontdict=font)\n\n\nax2 = fig.add_subplot(grid[1, 0])\nhist1 = inj_mvt.loc[(inj_mvt['Distance'].notnull())&(inj_mvt['BodyPart']=='Knee')]['Distance']\nhist2 = noinj_mvt.loc[noinj_mvt['Distance'].notnull()]['Distance']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax2.hist(hist1, bins=25, range=(0, 150), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='KneeInj')\nax2.hist(hist2, bins=100, range=(0, 150), density=True, color='green', alpha=0.5, label='NoInj')\nax2.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='KneeInjMedian')\nax2.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\n\nfont = {'family': 'sans-serif',\n        'color':  'black',\n        'weight': 'bold',\n        'size': 16,\n        }\nax2.set_ylim([0, 0.04])\nax2.set_title('KneeInjury vs NoInjury', fontdict=font)\n\n\nax3 = fig.add_subplot(grid[1, 1])\nhist1 = inj_mvt.loc[(inj_mvt['Distance'].notnull())&(inj_mvt['BodyPart']=='Ankle')]['Distance']\nhist2 = noinj_mvt.loc[noinj_mvt['Distance'].notnull()]['Distance']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax3.hist(hist1, bins=25, range=(0, 150), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='AnkleInj')\nax3.hist(hist2, bins=100, range=(0, 150), density=True, color='green', alpha=0.5, label='NoInj')\nax3.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='AnkleInjMedian')\nax3.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\n\nfont = {'family': 'sans-serif',\n        'color':  'black',\n        'weight': 'bold',\n        'size': 16,\n        }\nax3.set_ylim([0, 0.04])\nax3.set_title('AnkleInjury vs NoInjury', fontdict=font)\n\n\nax4 = fig.add_subplot(grid[2, 0])\nhist1 = inj_mvt.loc[(inj_mvt['Distance'].notnull())&(inj_mvt['FieldType']=='Natural')]['Distance']\nhist2 = noinj_mvt.loc[(noinj_mvt['Distance'].notnull())&(noinj_mvt['FieldType']=='Natural')]['Distance']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax4.hist(hist1, bins=25, range=(0, 150), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='KneeInj')\nax4.hist(hist2, bins=100, range=(0, 150), density=True, color='green', alpha=0.5, label='NoInj')\nax4.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='KneeInjMedian')\nax4.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\n\nax4.set_ylim([0, 0.04])\nax4.set_title('Injury vs NoInjury (OnNatTurf)', fontdict=font)\n\n\nax5 = fig.add_subplot(grid[2, 1])\nhist1 = inj_mvt.loc[(inj_mvt['Distance'].notnull())&(inj_mvt['FieldType']=='Synthetic')]['Distance']\nhist2 = noinj_mvt.loc[(noinj_mvt['Distance'].notnull())&(noinj_mvt['FieldType']=='Synthetic')]['Distance']\naxvline1 = statistics.median(hist1)\naxvline2 = statistics.median(hist2)\n\nax5.hist(hist1, bins=25, range=(0, 150), density=True, color='royalblue', alpha=0.75, linewidth=0.5, label='KneeInj')\nax5.hist(hist2, bins=100, range=(0, 150), density=True, color='green', alpha=0.5, label='NoInj')\nax5.axvline(axvline1, color='red', linestyle='dotted', linewidth=1.5, label='KneeInjMedian')\nax5.axvline(axvline2, color='black', linestyle='dotted', linewidth=1.5, label='NoInjMedian')\n\nax5.set_ylim([0, 0.04])\nax5.set_title('Injury vs NoInjury (OnSynTurf)', fontdict=font)\n\n\nfig.suptitle('Distance per play', fontweight='bold', size=24)\nfig.subplots_adjust(left=0.1, bottom=0.1, right=0.9, top=0.9, wspace=0.4, hspace=0.4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Summary about player's movement"},{"metadata":{"trusted":true},"cell_type":"code","source":"mvt_corr = noinj_mvt[['MaxSpeed', 'DirChg', 'AccDec', 'Distance']].corr()\nfig, ax = plt.subplots(figsize=(5, 4)) \nsns.heatmap(mvt_corr, annot=True, cmap=sns.diverging_palette(220, 20, as_cmap=True))\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig = plt.figure(figsize=(8, 8))\n\nmaxspeed_mean_play = noinj_mvt.groupby('PlayType')['MaxSpeed'].mean()\ndirchg_mean_play = noinj_mvt.groupby('PlayType')['DirChg'].mean()\n\nax1 = fig.add_subplot(211)\nax1.bar(np.arange(0.5, len(maxspeed_mean_play)*2, 2), maxspeed_mean_play, width=0.5, label='MaxSpeed', alpha=0.8)\nax1.bar(np.arange(1.0, len(dirchg_mean_play)*2, 2), dirchg_mean_play, width=0.5, label='DirChg', alpha=0.8)\nax1.set_xticks(np.arange(1, len(InjPRPlayType)*2, 2))\nax1.set_xticklabels(maxspeed_mean_play.index)\nax1.set_ylabel('MaxSpeed(y/s) / DirChg(deg)')\nax1.set_ylim([0, 10])\nax1.legend(loc=2)\n\nax2 = ax1.twinx()\nax2.bar(np.arange(1.5, len(dirchg_mean_play)*2, 2), InjPRPlayType['PRPlayType'], width=0.5, label='Probablity', color='yellow', alpha=0.5)\nax2.grid(False)\nax2.set_ylabel('Probablity(%)')\nax2.set_ylim([0, 0.12])\nax2.legend(loc=1)\n\n\nmaxspeed_mean_pos = noinj_mvt.groupby('PositionGroup')['MaxSpeed'].mean()\ndirchg_mean_pos = noinj_mvt.groupby('PositionGroup')['DirChg'].mean()\n\nax3 = fig.add_subplot(212)\nax3.bar(np.arange(0.5, len(maxspeed_mean_pos)*2, 2), maxspeed_mean_pos, width=0.5, label='MaxSpeed', alpha=0.8)\nax3.bar(np.arange(1.0, len(dirchg_mean_pos)*2, 2), dirchg_mean_pos, width=0.5, label='DirChg', alpha=0.8)\nax3.set_xticks(np.arange(1, len(maxspeed_mean_pos)*2, 2))\nax3.set_xticklabels(maxspeed_mean_pos.index)\nax3.set_ylabel('MaxSpeed(y/s) / DirChg(deg)')\nax3.set_ylim([0, 8])\nax3.legend(loc=2)\n\nax4 = ax3.twinx()\nax4.bar(np.arange(1.5, len(InjPRPos)*2, 2), InjPRPos['PRPos'], width=0.5, label='Probablity', color='yellow', alpha=0.5)\nax4.grid(False)\nax4.set_ylabel('Probablity(%)')\nax4.set_ylim([0, 0.1])\nax4.legend(loc=1)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**There could be some relevance between injury and max speed.**"}],"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":1}