{"cells":[{"metadata":{},"cell_type":"markdown","source":"# 머신러닝 기반 데이터 분석_김소현","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"# NFL 부상 분석","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"우리가 어떻게 삶의 다른 영역에 데이터 과학을 적용 할 수 있는지는 놀랍습니다. 스포츠에서도 데이터 과학은 운동 선수에게 더 안전한 게임을 만드는 데 도움이 될 수 있습니다.\n\n이 분석의 주요 목표는 부상을 초래하는 요인을 찾는 것입니다. 특히, 인조 잔디 대 천연 잔디가 플레이어의 움직임에 미칠 수있는 영향과 사지 부상을 줄일 수있는 요인을 알아보십시오.","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport itertools\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n        \n# image utils\nimport PIL\nfrom PIL import Image\n\n# import plotting\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport scipy.stats as ss\n\n# import machine learning\nfrom sklearn.model_selection import StratifiedKFold\nfrom imblearn.over_sampling import RandomOverSampler, SMOTE\nimport xgboost as xgb\nfrom sklearn.metrics import accuracy_score, confusion_matrix, cohen_kappa_score","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 데이터 로드","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Load the data as pandas dataframes:","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"play_df = pd.read_csv('../input/nfl-playing-surface-analytics/PlayList.csv')\nplayer_df = pd.read_csv('../input/nfl-playing-surface-analytics/PlayerTrackData.csv')\ninjury_df = pd.read_csv('../input/nfl-playing-surface-analytics/InjuryRecord.csv')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 데이터 탐색","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"우선, 초기 전처리를 수행하고 시각화한 데이터에 익숙해지고 추가 분석을 위한 아이디어를 생성하길 희망합니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"### 데이터셋 탐색","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"`1` 일반적인 정보:","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"unique_players = play_df.PlayerKey.nunique()\nunique_games = play_df.GameID.nunique()\nunique_plays = play_df.PlayKey.nunique()\n\nprint('There are {} players in the dataset.'.format(unique_players))\nprint('There are {} games in the dataset.'.format(unique_games))\nprint('There are {} plays in the dataset.'.format(unique_plays))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"`2` 게임 탐색:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# create a dataframe with game-level information\ngame_df = play_df[['GameID', 'StadiumType', 'FieldType', 'Weather', 'Temperature']].drop_duplicates().reset_index().drop(columns=['index'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# https://stackoverflow.com/questions/28931224/adding-value-labels-on-a-matplotlib-bar-chart\ndef add_value_labels(ax, spacing=5, decimals = 0):\n    \"\"\"Add labels to the end of each bar in a bar chart.\n\n    Arguments:\n        ax (matplotlib.axes.Axes): The matplotlib object containing the axes\n            of the plot to annotate.\n        spacing (int): The distance between the labels and the bars.\n    \"\"\"\n\n    # For each bar: Place a label\n    for rect in ax.patches:\n        # Get X and Y placement of label from rect.\n        y_value = rect.get_height()\n        x_value = rect.get_x() + rect.get_width() / 2\n\n        # Number of points between bar and label. Change to your liking.\n        space = spacing\n        # Vertical alignment for positive values\n        va = 'bottom'\n\n        # If value of bar is negative: Place label below bar\n        if y_value < 0:\n            # Invert space to place label below\n            space *= -1\n            # Vertically align label at top\n            va = 'top'\n\n        # Use Y value as label and format number with one decimal place\n        format_str = \"{:.\" + str(decimals) + \"f}\"\n        label = format_str.format(y_value)\n\n        # Create annotation\n        ax.annotate(\n            label,                      # Use `label` as label\n            (x_value, y_value),         # Place label at end of the bar\n            xytext=(0, space),          # Vertically shift label by `space`\n            textcoords=\"offset points\", # Interpret `xytext` as offset in points\n            ha='center',                # Horizontally center label\n            va=va)                      # Vertically align label differently for\n                                        # positive and negative values.\n\n\ndef visualize_game_features(game_df, rotation = 90, add_labels = False, figsize=(10,10)):\n    plt.style.use('ggplot')\n    fig = plt.figure(figsize=figsize)\n    grid = plt.GridSpec(4, 3, hspace=0.2, wspace=0.2)\n    stadium_ax = fig.add_subplot(grid[0, :2])\n    fieldtype_ax = fig.add_subplot(grid[0, 2])\n    weather_ax = fig.add_subplot(grid[1, 0:])\n    temperature_ax = fig.add_subplot(grid[2, 0:])\n    temperature_box_ax = fig.add_subplot(grid[3, 0:])\n\n    stadium_ax.bar(game_df.StadiumType.value_counts().keys(), game_df.StadiumType.value_counts().values, color='#00c2c7')\n    stadium_ax.set_title('StadiumType')\n    stadium_ax.set_xticklabels(game_df.StadiumType.value_counts().keys(), rotation=rotation)\n    \n    if add_labels:\n        add_value_labels(stadium_ax, spacing=5)\n\n    fieldtype_ax.bar(game_df.FieldType.value_counts().keys(), game_df.FieldType.value_counts().values, color=['#00c2c7', '#ff9e15'])\n    fieldtype_ax.set_title('FieldType')\n    fieldtype_ax.set_xticklabels(game_df.FieldType.value_counts().keys(), rotation=0)\n    \n    if add_labels:\n        add_value_labels(fieldtype_ax, spacing=5)\n\n    weather_ax.bar(game_df.Weather.value_counts().keys(), game_df.Weather.value_counts().values, color='#00c2c7')\n    weather_ax.set_title('Weather')\n    weather_ax.set_xticklabels(game_df.Weather.value_counts().keys(), rotation=rotation)\n    \n    if add_labels:\n        add_value_labels(weather_ax, spacing=5)\n        \n    temperature_ax.hist(game_df.Temperature.astype(int).values, bins=30, range=(0,90))\n    temperature_ax.set_xlim(0,110)\n    temperature_ax.set_xticks(range(0,110,10))\n    temperature_ax.set_xticklabels(range(0,110,10))\n    temperature_ax.set_title('Temperature')\n    \n    temperature_box_ax.boxplot(game_df.Temperature.astype(int).values, vert=False)\n    temperature_box_ax.set_xlim(0,110)\n    temperature_box_ax.set_xticks(range(0,110,10))\n    temperature_box_ax.set_xticklabels(range(0,110,10))\n    temperature_box_ax.set_yticklabels(['Temperature'])\n\n    plt.suptitle('Game-Level Exploration', fontsize=16)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def clean_weather(row):\n    cloudy = ['Cloudy 50% change of rain', 'Hazy', 'Cloudy.', 'Overcast', 'Mostly Cloudy',\n          'Cloudy, fog started developing in 2nd quarter', 'Partly Cloudy',\n          'Mostly cloudy', 'Rain Chance 40%',' Partly cloudy', 'Party Cloudy',\n          'Rain likely, temps in low 40s', 'Partly Clouidy', 'Cloudy, 50% change of rain','Mostly Coudy', '10% Chance of Rain',\n          'Cloudy, chance of rain', '30% Chance of Rain', 'Cloudy, light snow accumulating 1-3\"',\n          'cloudy', 'Coudy', 'Cloudy with periods of rain, thunder possible. Winds shifting to WNW, 10-20 mph.',\n         'Cloudy fog started developing in 2nd quarter', 'Cloudy light snow accumulating 1-3\"',\n         'Cloudywith periods of rain, thunder possible. Winds shifting to WNW, 10-20 mph.',\n         'Cloudy 50% change of rain', 'Cloudy and cold',\n       'Cloudy and Cool', 'Partly cloudy']\n    \n    clear = ['Clear, Windy',' Clear to Cloudy', 'Clear, highs to upper 80s',\n             'Clear and clear','Partly sunny',\n             'Clear, Windy', 'Clear skies', 'Sunny', 'Partly Sunny', 'Mostly Sunny', 'Clear Skies',\n             'Sunny Skies', 'Partly clear', 'Fair', 'Sunny, highs to upper 80s', 'Sun & clouds', 'Mostly sunny','Sunny, Windy',\n             'Mostly Sunny Skies', 'Clear and Sunny', 'Clear and sunny','Clear to Partly Cloudy', 'Clear Skies',\n            'Clear and cold', 'Clear and warm', 'Clear and Cool', 'Sunny and cold', 'Sunny and warm', 'Sunny and clear']\n    \n    rainy = ['Rainy', 'Scattered Showers', 'Showers', 'Cloudy Rain', 'Light Rain', 'Rain shower', 'Rain likely, temps in low 40s.', 'Cloudy, Rain']\n    \n    snow = ['Heavy lake effect snow']\n    \n    indoor = ['Controlled Climate', 'Indoors', 'N/A Indoor', 'N/A (Indoors)']\n        \n    if row.Weather in cloudy:\n        return 'Cloudy'\n    \n    if row.Weather in indoor:\n        return 'Indoor'\n    \n    if row.Weather in clear:\n        return 'Clear'\n    \n    if row.Weather in rainy:\n        return 'Rain'\n    \n    if row.Weather in snow:\n        return 'Snow'\n      \n    if row.Weather in ['Cloudy.', 'Heat Index 95', 'Cold']:\n        return np.nan\n    \n    return row.Weather\n\ndef clean_stadiumtype(row):\n    if row.StadiumType in ['Bowl', 'Heinz Field', 'Cloudy']:\n        return np.nan\n    else:\n        return row.StadiumType\n\ndef clean_play_df(play_df):\n    play_df_cleaned = play_df.copy()\n    \n    # clean StadiumType\n    play_df_cleaned['StadiumType'] = play_df_cleaned['StadiumType'].str.replace(r'Oudoor|Outdoors|Ourdoor|Outddors|Outdor|Outside', 'Outdoor')\n    play_df_cleaned['StadiumType'] = play_df_cleaned['StadiumType'].str.replace(r'Indoors|Indoor, Roof Closed|Indoor, Open Roof', 'Indoor')\n    play_df_cleaned['StadiumType'] = play_df_cleaned['StadiumType'].str.replace(r'Closed Dome|Domed, closed|Domed, Open|Domed, open|Dome, closed|Domed', 'Dome')\n    play_df_cleaned['StadiumType'] = play_df_cleaned['StadiumType'].str.replace(r'Retr. Roof-Closed|Outdoor Retr Roof-Open|Retr. Roof - Closed|Retr. Roof-Open|Retr. Roof - Open|Retr. Roof Closed', 'Retractable Roof')\n    play_df_cleaned['StadiumType'] = play_df_cleaned['StadiumType'].str.replace('Open', 'Outdoor')\n    play_df_cleaned['StadiumType'] = play_df_cleaned.apply(lambda row: clean_stadiumtype(row), axis=1)\n    \n    # clean Weather\n    play_df_cleaned['Weather'] = play_df_cleaned.apply(lambda row: clean_weather(row), axis=1)\n    \n    return play_df_cleaned","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"play_df_cleaned = clean_play_df(play_df)\ngame_df_cleaned = play_df_cleaned[['GameID', 'StadiumType', 'FieldType', 'Weather', 'Temperature']].drop_duplicates().reset_index().drop(columns=['index'])\nvisualize_game_features(game_df_cleaned, rotation=0, add_labels = True, figsize=(12,16))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"분포는 위와 같이 나타납니다:\n\n* __대부분의 게임은 야외에서 진행됩니다.__ 그래서 날씨가 중요합니다.\n* __합성잔디는 매우 흔하지만, 자연 잔디에서 약 30 % 더 많은 게임이 진행됩니다.__\n* __온도와 다른 기상 조건은 아주 다양합니다__. 온도가 부상에 어떤 영향을 미치는지 살펴보는 것은 흥미로울 것입니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"`3` 선수 능력치 탐색:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"player_data_df = play_df_cleaned[['PlayerKey', 'RosterPosition', 'PlayerGamePlay', 'Position', 'PositionGroup']]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def visualize_player_features(player_df, figsize=(25,20), add_labels=False):\n    plt.style.use('ggplot')\n    fig = plt.figure(figsize=figsize)\n    \n    grid = plt.GridSpec(3, 4, hspace=0.2, wspace=0.2)\n    \n    plays_ax = fig.add_subplot(grid[0, 0:2])\n    max_rolling_plays_ax = fig.add_subplot(grid[1, 0:2])\n    \n    rosterposition_ax = fig.add_subplot(grid[0, 2:])\n    positiongroup_ax = fig.add_subplot(grid[1, 2:])\n    position_ax = fig.add_subplot(grid[2, 0:])\n    \n    plays_ax.hist(player_df.groupby(by=['PlayerKey']).count()['RosterPosition'].values, bins=20, color='#00c2c7')\n    plays_ax.set_title('Number of plays per player')\n    \n    max_rolling_plays_ax.hist(player_df.groupby(by=['PlayerKey']).PlayerGamePlay.max().values, bins=20, color='#00c2c7')\n    max_rolling_plays_ax.set_title('Maximum number of rolling plays per player')\n    \n    rosterposition_ax.bar(player_df.RosterPosition.value_counts().keys().values, player_df.RosterPosition.value_counts().values)\n    rosterposition_ax.set_xticklabels(player_df.RosterPosition.value_counts().keys().values, rotation=20)\n    rosterposition_ax.set_title('Roster Position')\n    if add_labels:\n        add_value_labels(rosterposition_ax, spacing=5)\n    \n    position_ax.bar(player_df.Position.value_counts().keys().values, player_df.Position.value_counts().values, color='#ff9e15')\n    position_ax.set_title('Position')\n    if add_labels:\n        add_value_labels(position_ax, spacing=5)\n        \n    positiongroup_ax.bar(player_df.PositionGroup.value_counts().keys().values, player_df.PositionGroup.value_counts().values)\n    positiongroup_ax.set_title('Position Group')\n    if add_labels:\n        add_value_labels(positiongroup_ax, spacing=5)\n    \n    plt.suptitle('Player-Level Exploration', fontsize=16)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"visualize_player_features(player_data_df, add_labels=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"위의 도표는 선수 주변의 환경이 크게 다르다는 것을 보여줍니다. 어떤 선수들은 다른 선수들보다 훨씬 더 많은 게임을 하고, 다른 포지션도 많이 있습니다. 이 모든 요소들이 부상의 원인이 될 수 있습니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"`4` 경기 수준 탐색:","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def visualize_play(play_df_cleaned):\n    plt.style.use('ggplot')\n    fig, ax = plt.subplots(1,1,figsize=(15,5))\n    \n    plt.bar(play_df_cleaned.PlayType.value_counts().keys().values, play_df_cleaned.PlayType.value_counts().values)\n    plt.xticks(range(len(play_df_cleaned.PlayType.value_counts().keys().values)), play_df_cleaned.PlayType.value_counts().keys().values, rotation=20)\n    add_value_labels(ax, spacing=5)\n    plt.title('Play-Level Exploration: PlayType', fontsize=16)\n    \n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"visualize_play(play_df_cleaned)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"제 생각에는 플레이 유형이 부상에 어떤 영향을 미치는지 보는 것이 흥미진진할 것 같습니다. 어떤 형태는 다른 형태보다 훨씬 더 위험한 상황을 일으킬 수 있다고 생각됩니다!","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"### 선수 데이터셋 및 탐색","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"`1` 필드의 열 지도를 작성","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def visualize_field_heatmap(player_df, xbins=13, ybins=6, annotate = False):\n    # create a grid\n    x = np.linspace(0, 120, xbins)\n    y = np.linspace(0, 53, ybins)\n    \n    # initialize heatmap\n    hmap = np.zeros((xbins,ybins))\n    \n    for i in range(xbins-1):\n        for j in range(ybins-1):\n            hmap[i,j] = len(player_df[(player_df.x >= x[i]) & (player_df.x <= x[i+1]) & (player_df.y >= y[j]) & (player_df.y <= y[j+1])])\n            \n    fig = plt.figure(figsize=(10,5))\n    ax = sns.heatmap(np.transpose(hmap), annot=annotate, fmt = '.0f')\n    plt.title('Field Heatmap \\n the most visited areas of the field are highlighted')\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"visualize_field_heatmap(player_df)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"우리는 그 분야의 어떤 지역이 다른 지역보다 더 '바쁨'이 있다는 것을 알 수 있습니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"### 부상 데이터셋 탐색적 분석","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"부상에 대해 간단히 살펴보겠습니다:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"print('There are {} injury records in total.'.format(len(injury_df)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('{} unique players injured'.format(len(injury_df.PlayerKey.unique())))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"이것은 두 번 다친 선수들이 있다는 것을 의미합니다!","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"print('There are {} PlayKey values missing.'.format(len(injury_df) - injury_df.PlayKey.count()))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"부상의 약 30%는 발생한 시점을 알 수 없습니다. 꽤 중요한 숫자입니다.","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def visualize_injury(injury_df):\n    injury_df_cleaned = injury_df.copy()\n    injury_df_cleaned.DM_M1 = injury_df_cleaned.DM_M1 - injury_df_cleaned.DM_M7\n    injury_df_cleaned.DM_M7 = injury_df_cleaned.DM_M7 - injury_df_cleaned.DM_M28\n    injury_df_cleaned.DM_M28 = injury_df_cleaned.DM_M28 - injury_df_cleaned.DM_M42\n    \n    fig, axs = plt.subplots(1,3, figsize=(15,5))\n    \n    axs[0].bar(injury_df_cleaned.BodyPart.value_counts().keys().values, injury_df_cleaned.BodyPart.value_counts().values, color='#00c2c7')\n    axs[0].set_title('Body Part')\n    add_value_labels(axs[0], spacing=5)\n    \n    axs[1].bar(injury_df_cleaned.Surface.value_counts().keys().values, injury_df_cleaned.Surface.value_counts().values, color='#ff9e15')\n    axs[1].set_title('Surface')\n    add_value_labels(axs[1], spacing=5)\n    \n    M1 = injury_df_cleaned.DM_M1.sum()\n    M7 = injury_df_cleaned.DM_M7.sum()\n    M28 = injury_df_cleaned.DM_M28.sum()\n    M42 = injury_df_cleaned.DM_M42.sum()\n    \n    axs[2].bar(['1-7', '7-28', '28-42', '>=42'], [M1, M7, M28, M42])\n    axs[2].set_title('Missed Days')\n    add_value_labels(axs[2], spacing=5)\n    \n    plt.suptitle('Injury', fontsize=16)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"visualize_injury(injury_df)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"전체적으로 105건의 상당히 적은 부상 기록이 있습니다.\n\n* 우리는 무릎과 발목이 가장 많이 다친 신체 부위라는 것을 알 수 있습니다.\n* 합성 표면과 자연 표면에 대한 관측 값이 거의 같습니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Injury Analysis","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"`1` 부상 데이터를 게임 데이터와 병합(플레이 레벨 정보 삭제)하여 부상과 게임 레벨 요인 간의 종속성을 탐색할 수 있습니다.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# joined cleaned games dataset and injury dataset\ngame_injury_df = injury_df.set_index('GameID').join(game_df_cleaned.set_index('GameID'), how = 'outer')\n\n# fill null values for the injury columns with zeros\ngame_injury_df['DM_M1'] = game_injury_df['DM_M1'].fillna(0).astype(int)\ngame_injury_df['DM_M7'] = game_injury_df['DM_M7'].fillna(0).astype(int)\ngame_injury_df['DM_M28'] = game_injury_df['DM_M28'].fillna(0).astype(int)\ngame_injury_df['DM_M42'] = game_injury_df['DM_M42'].fillna(0).astype(int)\n\ngame_injury_df.DM_M1 = game_injury_df.DM_M1 - game_injury_df.DM_M7\ngame_injury_df.DM_M7 = game_injury_df.DM_M7 - game_injury_df.DM_M28\ngame_injury_df.DM_M28 = game_injury_df.DM_M28 - game_injury_df.DM_M42\n\n# introduce a column with a flag indicating an injury\ngame_injury_df['Injury'] = game_injury_df['DM_M1'] + game_injury_df['DM_M7'] + game_injury_df['DM_M28'] + game_injury_df['DM_M42']\n\n# drop duplicated surface column\ngame_injury_df = game_injury_df.drop(columns=['Surface'])\n\n# drop play-level features just for now\ngame_injury_df = game_injury_df.drop(columns=['PlayerKey', 'PlayKey'])\n\n# create dummy variables\ngame_injury_df_dummies = pd.get_dummies(game_injury_df, dummy_na = True, drop_first = True).drop(columns=['FieldType_nan'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"`2` 상관관계를 시각화:","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"corr_df = game_injury_df_dummies[['Temperature', 'StadiumType_Indoor', 'StadiumType_Outdoor', 'StadiumType_Retractable Roof',\n                                 'FieldType_Synthetic', 'Weather_Cloudy', 'Weather_Rain', 'Weather_Snow', 'Injury']].corr()\n\nfig = plt.figure(figsize=(10,7))\nsns.heatmap(corr_df, annot=True, cmap=sns.diverging_palette(220, 20, as_cmap=True))\nplt.title('Correlation Heatmap')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"안타깝게도, 요소들과 부상 사이에는 아무런 상관관계가 없습니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Let's look at [Cramer's V](https://en.wikipedia.org/wiki/Cram%C3%A9r%27s_V):","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"# Source:\n# https://stackoverflow.com/questions/46498455/categorical-features-correlation/46498792#46498792\ndef cramers_v(confusion_matrix):\n    \"\"\" calculate Cramers V statistic for categorial-categorial association.\n        uses correction from Bergsma and Wicher,\n        Journal of the Korean Statistical Society 42 (2013): 323-328\n    \"\"\"\n    chi2 = ss.chi2_contingency(confusion_matrix)[0]\n    n = confusion_matrix.sum()\n    phi2 = chi2 / n\n    r, k = confusion_matrix.shape\n    phi2corr = max(0, phi2 - ((k-1)*(r-1))/(n-1))\n    rcorr = r - ((r-1)**2)/(n-1)\n    kcorr = k - ((k-1)**2)/(n-1)\n    return np.sqrt(phi2corr / min((kcorr-1), (rcorr-1)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Source:\n# https://stackoverflow.com/questions/51859894/how-to-plot-a-cramer-s-v-heatmap-for-categorical-features\ndef plot_cramers_v_heatmap(df, cols):\n    corrM = np.zeros((len(cols),len(cols)))\n\n    for col1, col2 in itertools.combinations(cols, 2):\n        idx1, idx2 = cols.index(col1), cols.index(col2)\n        corrM[idx1, idx2] = cramers_v(pd.crosstab(df[col1], df[col2]).as_matrix())\n        corrM[idx2, idx1] = corrM[idx1, idx2]\n\n    corr = pd.DataFrame(corrM, index=cols, columns=cols)\n    fig, ax = plt.subplots(figsize=(7, 6))\n    ax = sns.heatmap(corr, annot=True, cmap=sns.diverging_palette(220, 20, as_cmap=True), ax=ax); ax.set_title(\"Cramer V Correlation between Variables\");","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cols = [\"StadiumType\", \"FieldType\", \"Weather\", \"Temperature\", \"Injury\"]\nplot_cramers_v_heatmap(game_injury_df, cols)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"이 테이블이 훨씬 흥미로워 보이네요!\n* 우리는 날씨와 온도 사이에 상관관계가 있다는 것을 알 수 있습니다(분명히, 눈과 비는 맑은 날씨보다 낮은 온도를 의미합니다).\n* 스타디움 유형과 온도 사이에는 약간의 상관관계가 있습니다.\n\n하지만 안타깝게도, 여전히 부상과 아무런 상관관계가 없습니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Let's try [Theil’s U](https://docs.oracle.com/cd/E40248_01/epm.1112/cb_statistical/frameset.htm?ch07s02s03s04.html) to find some insights:","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"# Source:\n# https://github.com/shakedzy/dython/blob/master/dython/nominal.py\n\nfrom collections import Counter\nimport math\n\ndef conditional_entropy(x, y, nan_strategy='replace', nan_replace_value=0):\n    \"\"\"\n    Calculates the conditional entropy of x given y: S(x|y)\n    Wikipedia: https://en.wikipedia.org/wiki/Conditional_entropy\n    **Returns:** float\n    Parameters\n    ----------\n    x : list / NumPy ndarray / Pandas Series\n        A sequence of measurements\n    y : list / NumPy ndarray / Pandas Series\n        A sequence of measurements\n    nan_strategy : string, default = 'replace'\n        How to handle missing values: can be either 'drop' to remove samples with missing values, or 'replace'\n        to replace all missing values with the nan_replace_value. Missing values are None and np.nan.\n    nan_replace_value : any, default = 0.0\n        The value used to replace missing values with. Only applicable when nan_strategy is set to 'replace'.\n    \"\"\"\n    y_counter = Counter(y)\n    xy_counter = Counter(list(zip(x,y)))\n    total_occurrences = sum(y_counter.values())\n    entropy = 0.0\n    for xy in xy_counter.keys():\n        p_xy = xy_counter[xy] / total_occurrences\n        p_y = y_counter[xy[1]] / total_occurrences\n        entropy += p_xy * math.log(p_y/p_xy)\n    return entropy\n\ndef theils_u(x, y):\n    s_xy = conditional_entropy(x,y)\n    x_counter = Counter(x)\n    total_occurrences = sum(x_counter.values())\n    p_x = list(map(lambda n: n/total_occurrences, x_counter.values()))\n    s_x = ss.entropy(p_x)\n    if s_x == 0:\n        return 1\n    else:\n        return (s_x - s_xy) / s_x","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def plot_theils_u_heatmap(df, cols):\n    corrM = np.zeros((len(cols),len(cols)))\n\n    for col1, col2 in itertools.combinations(cols, 2):\n        idx1, idx2 = cols.index(col1), cols.index(col2)\n        corrM[idx1, idx2] = theils_u(df[col1].values, df[col2].values)\n        corrM[idx2, idx1] = corrM[idx1, idx2]\n\n    corr = pd.DataFrame(corrM, index=cols, columns=cols)\n    fig, ax = plt.subplots(figsize=(7, 6))\n    ax = sns.heatmap(corr, annot=True, cmap=sns.diverging_palette(220, 20, as_cmap=True), ax=ax); ax.set_title(\"Theil's U Correlation between Variables\");","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cols = [\"StadiumType\", \"FieldType\", \"Weather\", \"Temperature\", \"Injury\"]\nplot_theils_u_heatmap(game_injury_df, cols)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"다시 말하지만, 상처에 대한 통찰력은 없습니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"`3` 부상과 관련하여 게임 요소들을 탐색:","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"온도:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# get the temperature values for games \n# be sure to only take the values where the game was played outdoors\nnon_injury_temp = game_injury_df[(game_injury_df.StadiumType == 'Outdoor') & (game_injury_df.Temperature >= 0) & (game_injury_df.Injury == 0)].Temperature.values\ninjury_temp = game_injury_df[(game_injury_df.StadiumType == 'Outdoor') & (game_injury_df.Temperature >= 0) & (game_injury_df.Injury == 1)].Temperature.values","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(10,5))\nplt.boxplot([non_injury_temp, injury_temp], vert = False)\nplt.title('Temperature Distribution (Box Plot)')\nplt.yticks([1,2], ['No Injury', 'Injury'])\nplt.xlim(0,100)\nplt.xlabel('Temperature')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"fig, axs = plt.subplots(1,1, figsize=(10,5))\nsns.kdeplot(non_injury_temp, label = 'No Injury')\nsns.kdeplot(injury_temp, label = 'Injury')\nplt.title('Temperature Distribution')\nplt.xlabel('Temperature')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Kolmogorov-Smirnov 검정을 확인하여 온도 샘플이 하나의 분포에서 나오는지 확인:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# compare maximum play speed samples\nD, pvalue = ss.ks_2samp(non_injury_temp, injury_temp)\nD, pvalue","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"p-값이 높습니다. 온도 값이 서로 다른 분포에서 나온다고는 말할 수 없습니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"`4` 가설 검정","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"합성 잔디의 부상자 수가 유의하게 더 많은지 확인하기 위해 간단한 가설 테스트를 해보겠습니다. 기본적으로, 합성 잔디에서 경기할 때 부상 확률이 더 높다는 것을 알 수 있습니다. 하지만 이것은 통계적으로 중요한 것일까요?","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# compute the injury probability for synthetic and natural turf\np_injury = game_injury_df[['FieldType', 'Injury']].groupby('FieldType').mean()['Injury']\np_injury","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"귀무 가설은 천연잔디 부상의 확률이 합성잔디 부상의 확률과 같거나 작다는 것입니다.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# get number of trials and overall injury rate under null\nn_natural = game_injury_df[['FieldType', 'Injury']].groupby('FieldType').size()[0]\nn_synthetic = game_injury_df[['FieldType', 'Injury']].groupby('FieldType').size()[1]\n\np_null = game_injury_df[['FieldType', 'Injury']][game_injury_df.FieldType == 'Natural'].mean()[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# compute standard error\nse_p = np.sqrt(p_null * (1-p_null) * (1/n_natural + 1/n_synthetic))\n\n#  compute z-score and p-value\nz = (p_injury[1] - p_injury[0]) / se_p\n\nprint('The z-score is: {}'.format(z))\nprint('The p-value is: {}'.format(1-ss.norm.cdf(z)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"95% 신뢰도 이하에서는 p-값이 0.05보다 작으면 귀무 가설을 기각합니다. 계산된 p-값은 약 0.002이므로 천연 잔디의 부상 확률이 합성 잔디의 부상 확률보다 작거나 같다는 귀무 가설을 기각할 수 있습니다. 합성잔디 부상 확률은 천연잔디 부상 확률(99% 신뢰도)보다 높다고 결론을 내릴 수 있습니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"`5` 경기 수준 요소들:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# joined cleaned games dataset and injury dataset\nplay_injury_df = injury_df.dropna(subset=['PlayKey']).set_index('PlayKey').join(play_df_cleaned.set_index('PlayKey'), how = 'outer', lsuffix='_left', rsuffix='_right')\n\n# fill null values for the injury columns with zeros\nplay_injury_df['DM_M1'] = play_injury_df['DM_M1'].fillna(0).astype(int)\nplay_injury_df['DM_M7'] = play_injury_df['DM_M7'].fillna(0).astype(int)\nplay_injury_df['DM_M28'] = play_injury_df['DM_M28'].fillna(0).astype(int)\nplay_injury_df['DM_M42'] = play_injury_df['DM_M42'].fillna(0).astype(int)\n\n# introduce a column with a flag indicating an injury\nplay_injury_df.DM_M1 = play_injury_df.DM_M1 - play_injury_df.DM_M7\nplay_injury_df.DM_M7 = play_injury_df.DM_M7 - play_injury_df.DM_M28\nplay_injury_df.DM_M28 = play_injury_df.DM_M28 - play_injury_df.DM_M42\n\nplay_injury_df['Injury'] = play_injury_df['DM_M1'] + play_injury_df['DM_M7'] + play_injury_df['DM_M28']+ play_injury_df['DM_M42']\n\n# drop duplicated surface column\nplay_injury_df = play_injury_df.drop(columns=['Surface'])\n\n# create dummy variables\nplay_injury_df_dummies = pd.get_dummies(play_injury_df, columns = ['PlayType', 'PositionGroup'], dummy_na = True, drop_first = True)","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"corr_df = play_injury_df_dummies[['PlayType_Pass', 'PlayType_Kickoff', 'PlayType_Punt', 'PlayType_Rush',\n                                  'PositionGroup_QB', 'PositionGroup_DL', 'PositionGroup_LB', 'PositionGroup_OL',\n                                  'PositionGroup_RB', 'PositionGroup_SPEC', 'PositionGroup_TE', 'PositionGroup_WR',\n                                  'Injury']].corr()\n\nfig = plt.figure(figsize=(15,7))\nsns.heatmap(corr_df, annot=True, cmap=sns.diverging_palette(220, 20, as_cmap=True))\nplt.title('Correlation Heatmap')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Cramer's V:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"cols = [\"RosterPosition\", \"StadiumType\", \"FieldType\", \"Temperature\", \"Weather\", 'PlayType', 'PlayerGamePlay', 'Position', 'PositionGroup', 'Injury']\nplot_cramers_v_heatmap(play_injury_df, cols)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"이 차트는 명백한 상관 관계를 보여 주지만 부상과 상관관계가 있는 것은 없습니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Let's tru Theil's U:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_theils_u_heatmap(play_injury_df, cols)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"안타깝게도, 부상에 대한 인사이트는 없습니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"부상을 입은 플레이를 사용하여 필드의 열지도 시각화:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# find the keys of the plays related to injuries\nplay_injuries = play_injury_df.reset_index().dropna()[['PlayKey']]\n# merge the playkeys associated with injuries with players' positions\nplayer_injuries = player_df.merge(play_injuries, on='PlayKey', how='inner') # use inner join!\n# visualize the heatmap\nvisualize_field_heatmap(player_injuries, annotate = True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"부상의 열 지도는 현장의 일반적인 열 지도와 다소 다르게 보입니다! 아마도 경기장에는 선수들이 부상을 입을 가능성이 더 높은 위험 구역이 더 많을 거예요!\n\n이 통찰력을 부상 예측 모델의 피쳐 엔지니어링에 사용할 수 있습니다!","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def visualize_field_kde(player_df):\n    # plot kde\n    fig = plt.figure(figsize=(10,5))\n    ax = sns.jointplot(x=\"x\", y=\"y\", data=player_df, kind=\"kde\")\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"이것은 현장에서 부상 플레이 위치에 대한 KDE 그림:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"visualize_field_kde(player_injuries)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 게임 타임 라인 및 부상 분석","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"플레이어의 게임 시간 표시줄을 그리고 부상당한 날 강조:","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def player_games_timeline(player_key, play_df, injury_df):\n    '''\n    Function to plot the player's timeline\n    '''\n    player_games = play_df[play_df.PlayerKey == player_key][['GameID', 'PlayKey', 'PlayerDay', 'PlayerGame']]\n    \n    # plot timeline for the player\n    plt.figure(figsize=(20,5))\n    plt.title('Player Games Timeline \\n PlayerKey: ' + str(player_key))  \n    plt.plot(player_games.PlayerDay.unique(), np.zeros(len(player_games.PlayerDay.unique())), color='#00c2c7')\n    plt.scatter(player_games.PlayerDay.unique(), np.zeros(len(player_games.PlayerDay.unique())), s=100, color='#00c2c7', label='games')\n    \n    # add games with injury\n    injured_players = injury_df.PlayerKey.unique()\n    if player_key in injured_players:\n        injury_games = injury_df[injury_df.PlayerKey == player_key].GameID.values\n        injury_days = player_games[player_games.GameID.isin(injury_games)].PlayerDay.unique()\n        \n        plt.scatter(injury_days, np.zeros(len(injury_days)), s=100, color='#e01e5a', label='injury')\n    \n    plt.legend()\n    plt.xlabel('days')\n    plt.yticks([])\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"player_games_timeline(26624, play_df, injury_df)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"player_games_timeline(33337, play_df, injury_df)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"player_games_timeline(43540, play_df, injury_df)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"player_games_timeline(39873, play_df, injury_df)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"데이터 세트에서 무작위로 부상당한 선수들을 몇 명 골랐어요. 시즌 초반에 (선수마다) 부상이 일어나는 것 같습니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"그렇다면 선수의 속도, 경기장에서의 포지션, 경기 횟수(\"플레이어 게임\")가 부상과 관련이 있는 것일까요?","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"play_injury = play_injury_df[['PlayerGame', 'PlayerGamePlay', 'Injury']]\ncorrs = play_injury.corr()\n\nfig = plt.figure(figsize=(7,5))\nsns.heatmap(corrs, annot=True, cmap=sns.diverging_palette(220, 20, as_cmap=True))\nplt.title('Correlation Heatmap')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"위의 다이어그램은 부상과 게임당 게임/플레이 수 사이에 상관관계가 없음을 보여줍니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## 데이터 엔지니어링","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"다음 단계는 피쳐를 추출하고 부상을 예측할 수 있는 모델을 만드는 것입니다. 이 모델에서 기능을 가져와 부상당한 운전자를 알아낼 수 있기를 바랍니다.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# reset index \nfeatures_df = play_injury_df.copy().reset_index()\n# drop the irrelevant columns\nfeatures_df = features_df.drop(columns=['PlayerKey_left','GameID_left','BodyPart', 'PlayKey', 'PlayerKey_right', 'GameID_right', 'DM_M1', 'DM_M7', 'DM_M28', 'DM_M42'])\n# convert into dummies\nfeatures_df = pd.get_dummies(features_df, dummy_na = False, drop_first = True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Machine Learning","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"준비된 데이터를 얻었으므로 이제 기계 학습 부분으로 이동할 수 있습니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"`1` 피쳐와 타겟으로 나누기:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# split into X and y\ny = features_df['Injury']\nX = features_df.drop(columns=['Injury'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"`2` 계층화된 분할을 사용하여 Train과 test로 분할하여 클래스 라벨이 열차와 시험 세트 사이에 균등하게 배분:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"skf = StratifiedKFold(n_splits=2)\n\nfor train_index, test_index in skf.split(X, y):\n    X_train, X_test = X.values[train_index, :], X.values[test_index, :]\n    y_train, y_test = y[train_index], y[test_index]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"`3` 데이터셋 재 샘플링:\n\n부상 플레이 횟수가 너무 적어서 데이터를 그대로 사용할 수 없습니다. 저희 모델은 항상 아무런 부상도 없을 것이라고 예측합니다. 그것이 우리가 우리의 데이터 세트를 다시 샘플링해야 하는 이유이다. 재샘플링은 희귀한 등급(부상)에서 더 많은 사례의 예를 생성하는 데 도움이 되므로 모델을 교육할 수 있습니다! 불균형 학습 라이브러리[imbalanced-learn](https://imbalanced-learn.readthedocs.io/en/stable/index.html)를 사용할 것입니다.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"res = RandomOverSampler(random_state=0)\nX_resampled, y_resampled = res.fit_resample(X_train, y_train)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"`4` 모델 트레이닝:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"model = xgb.XGBClassifier(max_depth=3,\n                      learning_rate=0.1,\n                      n_estimators=100,\n                      objective='binary:logistic',\n                      booster='gbtree',\n                      tree_method='auto',\n                      n_jobs=50,\n                      gamma=0,\n                      min_child_weight=1,\n                      max_delta_step=0,\n                      subsample=1,\n                      colsample_bytree=1,\n                      colsample_bylevel=1,\n                      colsample_bynode=1,\n                      reg_alpha=0,\n                      reg_lambda=1,\n                      scale_pos_weight=1,\n                      base_score=0.5,\n                      random_state=42)\nmodel.fit(X_resampled, y_resampled)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"`5` 모형 평가:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"y_pred = model.predict(X_test)\n\naccuracy = accuracy_score(y_test, y_pred)\nconf_matrix = confusion_matrix(y_test, y_pred)\ncohen_kappa = cohen_kappa_score(y_test, y_pred)\n\nprint('Accuracy: {}'.format(accuracy))\nprint('Cohen kappa: {}'.format(cohen_kappa))\nprint('Confusion Matrix: \\n {}'.format(conf_matrix))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"모델의 성능은 상당히 좋지 않지만 여전히 기능의 중요성을 볼 수 있습니다:","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# extract the feature importances from XGBoost model\nfeature_importances = model.feature_importances_\nfeature_importances = pd.DataFrame(feature_importances, index = X.columns).reset_index().rename(columns={'index':'feature', 0:'importance'}).sort_values(by=['importance'], ascending=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# plot as a bar chart\nplt.figure(figsize=(20,7))\nplt.bar(range(len(feature_importances)), feature_importances.importance.values)\nplt.xticks(range(len(feature_importances)), feature_importances.feature.values, rotation=90)\n\nplt.title('Feature importances')\nplt.xlabel('features')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"위의 차트를 보면 다음과 같이 말할 수 있습니다:\n* 플레이 유형은 부상에 영향을 주는 기능 중 하나입니다.\n* 현장 유형 기능도 부상 예측 모델에서 중요한 기능 중 하나입니다.\n* 플레이어 게임과 플라이어 데이도 부상에 영향을 미치는 중요한 기능 중 하나입니다.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## 결론:\n* 합성 잔디에서 경기할 경우 부상 위험이 높습니다.\n* 심한 날씨 조건 하에서(비 또는 눈) 합성 잔디에 있는 플레이어는 천연 잔디에 있는 플레이어보다 속도가 더 느린 경향이 있습니다.\n* 아마도 인조잔디는 빠른 속도를 유지할 수 없을 것입니다. 그것은 선수들이 날씨가 나쁠 때 속도를 늦추게 합니다. 아마도 합성 잔디에서 너무 빨리 움직이면 특정 위치에서 경기할 때 부상의 위험도 높아질 수 있습니다.","execution_count":null}],"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}