{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Football Match Probability Prediction\n\n> **In case you fork/copy/like this notebook:**\n> **Upvote it s'il te plaît/Per favore/Please**","metadata":{"_uuid":"7cd960c6-91d4-4ca0-a69a-9e4e520d184a","_cell_guid":"eab67375-a4a9-4e08-bb4a-3c099e21dfa9","trusted":true}},{"cell_type":"markdown","source":"## Import modules and loading the data\nFirst let's import modules, the training and the test set. The test set contains the same columns than the training set without the target.","metadata":{"_uuid":"a1e98e57-05f8-42b9-815d-023b303cd789","_cell_guid":"000b4f69-0b86-45f3-9560-8c549acb8e78","trusted":true}},{"cell_type":"code","source":"# Import libraries\n# import gc\nimport numpy as np\nimport pandas as pd\nimport datetime as dt\nimport matplotlib.pyplot as plt\n#\nfrom sklearn.model_selection import KFold, StratifiedKFold\nfrom sklearn.preprocessing import RobustScaler, LabelEncoder\nfrom sklearn.metrics import accuracy_score, log_loss, precision_score, roc_auc_score\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay, classification_report\n#\nimport lightgbm as lgb","metadata":{"_uuid":"920e6d1a-69cf-46e8-a78b-24f7fe780f73","_cell_guid":"c6c6ebe4-3bf5-4a40-8f8e-3f065ecd9e16","collapsed":false,"execution":{"iopub.status.busy":"2022-02-01T15:19:26.012172Z","iopub.execute_input":"2022-02-01T15:19:26.013113Z","iopub.status.idle":"2022-02-01T15:19:33.550109Z","shell.execute_reply.started":"2022-02-01T15:19:26.013044Z","shell.execute_reply":"2022-02-01T15:19:33.549186Z"},"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#loading the data\ntrain = pd.read_csv('/kaggle/input/football-match-probability-prediction/train.csv')\ntest = pd.read_csv('/kaggle/input/football-match-probability-prediction/test.csv')\nsubmission = pd.read_csv('/kaggle/input/football-match-probability-prediction/sample_submission.csv')","metadata":{"_uuid":"f9cd6673-ccc8-4e4c-bce0-c4e7e1d8e98a","_cell_guid":"e5fbcac1-440c-4d84-8f6f-6ef0f1102c70","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Parameters\nSet some parameters that will be used later.","metadata":{"_uuid":"ac3c4d94-2456-491c-b634-480be3505386","_cell_guid":"62203296-73b6-416a-b8af-83919edc6721","trusted":true}},{"cell_type":"code","source":"# Set seed\n# np.random.seed(123)\n# tf.random.set_seed(123)\n\n#Some parameters\nMASK = -666 # fill NA with -666 (the number of the beast)\nT_HIST = 10 # time history, last 10 games\nCLASS = 3 #number of classes (home, draw, away)\n\nDEBUG = False\n# Run on a small sample of the data\nif DEBUG:\n    train = train[:10000]","metadata":{"_uuid":"9bc24db5-b55a-4e16-87c3-ce6b4cd8a552","_cell_guid":"72e32380-622d-40ce-b35a-674120f981b1","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# exclude matches with no history at date 1 - full of NA (1159 rows excluded)\ntrain.dropna(subset=['home_team_history_match_date_1'], inplace = True)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"Train: {train.shape} \\n Submission: {submission.shape}\")\ntrain.head()","metadata":{"_uuid":"f98d00e1-b8db-475f-926b-3f27fc07bc55","_cell_guid":"36d932ff-1cf7-4fa3-97c3-2657a83150a9","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Feature Engineering","metadata":{"_uuid":"91794a39-6ab8-4fac-bf6a-833de1182b06","_cell_guid":"838bf7ec-34de-46d8-8de9-0c9be9cb1fea","trusted":true}},{"cell_type":"code","source":"# for cols \"date\", change to datatime \nfor col in train.filter(regex='date', axis=1).columns:\n    train[col] = pd.to_datetime(train[col])\n    test[col] = pd.to_datetime(test[col])\n\n# Some feature engineering\n\ndef add_features(df):\n    df['home_team_history_match_date_0'] = df['match_date']\n    df['away_team_history_match_date_0'] = df['match_date']\n    for i in range(1, 11): # range from 1 to 10\n        # Feat. difference of days\n        df[f'home_team_history_match_DIFF_days_{i}'] = (df['match_date'] - df[f'home_team_history_match_date_{i}']).dt.days\n        df[f'away_team_history_match_DIFF_days_{i}'] = (df['match_date'] - df[f'away_team_history_match_date_{i}']).dt.days\n        # date diff 2\n        # df[f'home_team_history_match_DIFF2_days_{i}'] = (df[f'home_team_history_match_date_{i}'] - df[f'home_team_history_match_date_{i-1}']).dt.days\n        # df[f'away_team_history_match_DIFF2_days_{i}'] = (df[f'away_team_history_match_date_{i}'] - df[f'away_team_history_match_date_{i-1}']).dt.days\n    # Feat. difference of scored goals\n        df[f'home_team_history_DIFF_goal_{i}'] = df[f'home_team_history_goal_{i}'] - df[f'home_team_history_opponent_goal_{i}']\n        df[f'away_team_history_DIFF_goal_{i}'] = df[f'away_team_history_goal_{i}'] - df[f'away_team_history_opponent_goal_{i}']\n    # Feat dummy winner x loser\n        df[f'home_winner_{i}'] = np.where(df[f'home_team_history_DIFF_goal_{i}'] > 0, 1., 0.) \n        df[f'home_loser_{i}'] = np.where(df[f'home_team_history_DIFF_goal_{i}'] < 0, 1., 0.)\n        df[f'away_winner_{i}'] = np.where(df[f'away_team_history_DIFF_goal_{i}'] > 0, 1., 0.)\n        df[f'away_loser_{i}'] = np.where(df[f'away_team_history_DIFF_goal_{i}'] < 0, 1., 0.)\n    # Results: multiple nested where # away:0, draw:1, home:2\n        df[f'home_team_result_{i}'] = np.where(df[f'home_team_history_DIFF_goal_{i}'] > 0., 2.,\n                         (np.where(df[f'home_team_history_DIFF_goal_{i}'] == 0., 1,\n                                   np.where(df[f'home_team_history_DIFF_goal_{i}'].isna(), np.nan, 0))))\n        df[f'away_team_result_{i}'] = np.where(df[f'away_team_history_DIFF_goal_{i}'] > 0., 2.,\n                         (np.where(df[f'away_team_history_DIFF_goal_{i}'] == 0., 1.,\n                                   np.where(df[f'away_team_history_DIFF_goal_{i}'].isna(), np.nan, 0.))))\n    # Feat. difference of rating (\"modified\" ELO RATING)\n        df[f'home_team_history_ELO_rating_{i}'] = 1/(1+10**((df[f'home_team_history_opponent_rating_{i}']-df[f'home_team_history_rating_{i}'])/10))\n        df[f'away_team_history_ELO_rating_{i}'] = 1/(1+10**((df[f'away_team_history_opponent_rating_{i}']-df[f'away_team_history_rating_{i}'])/10))\n        df[f'home_away_team_history_ELO_rating_{i}'] = 1/(1+10**((df[f'away_team_history_rating_{i}']-df[f'home_team_history_rating_{i}'])/10))\n    # Dif\n       #  df[f'home_team_history_DIF_rating_{i}'] = -df[f'home_team_history_opponent_rating_{i}']+df[f'home_team_history_rating_{i}']\n       #  df[f'away_team_history_DIF_rating_{i}'] = -df[f'away_team_history_opponent_rating_{i}']+df[f'away_team_history_rating_{i}']\n       #  df[f'home_away_team_history_DIF_rating_{i}'] = -df[f'away_team_history_rating_{i}']+df[f'home_team_history_rating_{i}']\n    # Feat. same coach id\n        df[f'home_team_history_SAME_coaX_{i}'] = np.where(df['home_team_coach_id']==df[f'home_team_history_coach_{i}'],1,0)\n        df[f'away_team_history_SAME_coaX_{i}'] = np.where(df['away_team_coach_id']==df[f'away_team_history_coach_{i}'],1,0) \n    # Feat. same league id\n        df[f'home_team_history_SAME_leaG_{i}'] = np.where(df['league_id']==df[f'home_team_history_league_id_{i}'],1,0)\n        df[f'away_team_history_SAME_leaG_{i}'] = np.where(df['league_id']==df[f'away_team_history_league_id_{i}'],1,0) \n    # Features...\n        df[f'feature_A_{i}'] = df[f'home_team_history_ELO_rating_{i}'] * df[f'home_team_history_is_play_home_{i}']\n        df[f'feature_B_{i}'] = df[f'away_team_history_ELO_rating_{i}'] * df[f'away_team_history_is_play_home_{i}']\n        df[f'feature_C_{i}'] = df[f'home_away_team_history_ELO_rating_{i}'] * df[f'home_team_history_is_play_home_{i}']\n        df[f'feature_X_{i}'] = df[f'home_team_history_ELO_rating_{i}'] * df[f'home_team_history_SAME_leaG_{i}']\n        df[f'feature_Y_{i}'] = df[f'away_team_history_ELO_rating_{i}'] * df[f'away_team_history_SAME_leaG_{i}']\n        df[f'feature_Z_{i}'] = df[f'home_away_team_history_ELO_rating_{i}'] * df[f'home_team_history_SAME_leaG_{i}']\n    # Fill NA with -666\n    # df.fillna(MASK, inplace = True)\n    return df\n\ntrain = add_features(train)\ntest = add_features(test)","metadata":{"_uuid":"daed24ca-8f78-4419-b19f-3b97d78f29f7","_cell_guid":"fa41a07c-c823-4716-8666-21f3f8cc12ed","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# The feature based on target do not reduce the log loss \n'''\nleague_pivot = train.pivot_table(index='league_id', columns='target',\n                          aggfunc='size',  fill_value=0).reset_index()\nleague_pivot['total'] = league_pivot['away']+ league_pivot['draw'] + league_pivot['home']\nleague_pivot['away'] /= league_pivot['total']\nleague_pivot['draw'] /= league_pivot['total']\nleague_pivot['home'] /= league_pivot['total']\n\ntrain_league = pd.merge(train[['id', 'league_id']], league_pivot, left_on=\"league_id\", right_on=\"league_id\").copy()\ntest_league = pd.merge(test[['id', 'league_id']], league_pivot, left_on=\"league_id\", right_on=\"league_id\").copy()\n'''","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# league_pivot.head(5)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Scaling and Reshape","metadata":{"_uuid":"0fa67e85-50f7-43af-a9dc-b11c05bcbf8c","_cell_guid":"878d27a4-831a-4a9f-9c9b-275409afc69b","trusted":true}},{"cell_type":"code","source":"# save targets\n# train_id = train['id'].copy()\ntrain_y = train['target'].copy()\n#keep only some features\ntrain_x = train.drop(['target', 'home_team_name', 'away_team_name'], axis=1) #, inplace=True) # is_cup EXCLUDED\n# Exclude all date, league, coach columns\ntrain_x.drop(train.filter(regex='date').columns, axis=1, inplace = True)\ntrain_x.drop(train.filter(regex='league').columns, axis=1, inplace = True)\ntrain_x.drop(train.filter(regex='coach').columns, axis=1, inplace = True)\n#\n# Test set\n# test_id = test['id'].copy()\ntest_x = test.drop(['home_team_name', 'away_team_name'], axis=1)#, inplace=True) # is_cup EXCLUDED\n# Exclude all date, league, coach columns\ntest_x.drop(test.filter(regex='date').columns, axis=1, inplace = True)\ntest_x.drop(test.filter(regex='league').columns, axis=1, inplace = True)\ntest_x.drop(test.filter(regex='coach').columns, axis=1, inplace = True)\n\n# Deal with the is_cup feature\n# There are NA in 'is_cup'\ntrain_x=train_x.fillna({'is_cup':False})\ntrain_x['is_cup'] = pd.get_dummies(train_x['is_cup'], drop_first=True)\n#\ntest_x=test_x.fillna({'is_cup':False})\ntest_x['is_cup']= pd.get_dummies(test_x['is_cup'], drop_first=True)","metadata":{"_uuid":"7b65ce25-5a33-4fb8-b04b-0f288ea3d9bb","_cell_guid":"fe6715ba-250e-4a67-bc76-f046ba57b793","collapsed":false,"execution":{"iopub.status.busy":"2022-02-01T15:19:33.551844Z","iopub.execute_input":"2022-02-01T15:19:33.552117Z","iopub.status.idle":"2022-02-01T15:19:33.583148Z","shell.execute_reply.started":"2022-02-01T15:19:33.552068Z","shell.execute_reply":"2022-02-01T15:19:33.582099Z"},"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Target, train and test shape\nprint(f\"Target: {train_y.shape} \\n Train shape: {train_x.shape} \\n Test: {test_x.shape}\")\nprint(f\"Column names: {list(train_x.columns)}\")","metadata":{"_uuid":"9c748333-e838-48d8-88f0-33ef0051e57e","_cell_guid":"9ab58872-8c97-4c9a-a110-a55588e0f29f","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_x.head()","metadata":{"_uuid":"e45561e1-2c45-4bb8-8b20-70aa386fc82a","_cell_guid":"9dda4bc6-19b1-40f4-bab6-ca33dae90f12","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_y.head()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Store feature names\n# feature_names = list(train.columns)\n# Pivot dataframe to create an input array for the LSTM network\nfeature_groups = [\"home_team_history_is_play_home\", \"home_team_history_is_cup\",\n    \"home_team_history_goal\", \"home_team_history_opponent_goal\",\n    \"home_team_history_rating\", \"home_team_history_opponent_rating\",  \n    \"away_team_history_is_play_home\", \"away_team_history_is_cup\",\n    \"away_team_history_goal\", \"away_team_history_opponent_goal\",\n    \"away_team_history_rating\", \"away_team_history_opponent_rating\",  \n    \"home_team_history_match_DIFF_days\", \"away_team_history_match_DIFF_days\",\n    # \"home_team_history_match_DIFF2_days\", \"away_team_history_match_DIFF2_days\",\n    \"home_team_history_DIFF_goal\",\"away_team_history_DIFF_goal\",\n    \"home_team_history_ELO_rating\",\"away_team_history_ELO_rating\",\n    \"home_away_team_history_ELO_rating\",\n    \"home_team_history_SAME_coaX\", \"away_team_history_SAME_coaX\",\n    \"home_team_history_SAME_leaG\", \"away_team_history_SAME_leaG\",\n    \"home_team_result\", \"away_team_result\",\n    \"home_winner\", \"home_loser\", \"away_winner\", \"away_loser\",\n    \"feature_A\", \"feature_B\", \"feature_C\",\n    \"feature_X\", \"feature_Y\", \"feature_Z\",\n    # \"home_team_history_DIF_rating\",\"away_team_history_DIF_rating\",\"home_away_team_history_DIF_rating\"\n                 ]      \n# Pivot dimension (id*features) x time_history\ntrain_x_pivot = pd.wide_to_long(train_x, stubnames=feature_groups, \n                i=['id','is_cup'], j='time', sep='_', suffix='\\d+')\ntest_x_pivot = pd.wide_to_long(test_x, stubnames=feature_groups, \n                i=['id','is_cup'], j='time', sep='_', suffix='\\d+')\n#\nprint(f\"Train pivot shape: {train_x_pivot.shape}\")  \nprint(f\"Test pivot shape: {test_x_pivot.shape}\") ","metadata":{"_uuid":"c316690b-dbb6-45f2-882c-18bcb932af61","_cell_guid":"46437c51-e209-4f27-8d53-1bf0e8547fc4","collapsed":false,"execution":{"iopub.status.busy":"2022-02-01T15:19:33.584528Z","iopub.execute_input":"2022-02-01T15:19:33.584813Z","iopub.status.idle":"2022-02-01T15:19:33.590424Z","shell.execute_reply.started":"2022-02-01T15:19:33.58477Z","shell.execute_reply":"2022-02-01T15:19:33.589437Z"},"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create columns based on index\ntrain_x_pivot = train_x_pivot.reset_index()\ntest_x_pivot = test_x_pivot.reset_index()\n# Deal with the is_cup feature\n# There are NA in 'is_cup'\ntrain_x_pivot=train_x_pivot.fillna({'is_cup':False})\ntrain_x_pivot['is_cup'] = pd.get_dummies(train_x_pivot['is_cup'], drop_first=True)\n#\ntest_x_pivot=test_x_pivot.fillna({'is_cup':False})\ntest_x_pivot['is_cup']= pd.get_dummies(test_x_pivot['is_cup'], drop_first=True)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_x_pivot.head(20)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# x_train['league_id'] = train[['league_id']]\n# x_test['league_id'] = test[['league_id']]","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Feature engineering again!!! Group by id, stats over time\ndef agg_features(df):\n    # vol_cols = ['log_return1_realized_volatility', 'log_return2_realized_volatility']\n    # Group by match id\n    df_agg = df.groupby(['id'])[feature_groups].agg(['mean', 'median', 'std', 'max', 'min', 'sum',]).reset_index()\n    # Rename columns joining suffix\n    df_agg.columns = ['_'.join(col) for col in df_agg.columns]\n    return df_agg\n\ntrain_x_agg = agg_features(train_x_pivot)\ntest_x_agg = agg_features(test_x_pivot)\n\ntrain_x_last = train_x_pivot.loc[train_x_pivot['time'] == 1]\ntest_x_last = test_x_pivot.loc[train_x_pivot['time'] == 1]\n\n# keep order\n# Merge and drop columns\nx_train = pd.merge(train_x_last, train_x_agg, left_on=\"id\", right_on=\"id_\").drop(['id', 'id_', 'time'], axis = 1).copy()\nx_test = pd.merge(test_x_last, test_x_agg, left_on=\"id\", right_on=\"id_\").drop(['id', 'id_', 'time'], axis = 1).copy()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Merge with the feature based on target\n# with the code below the Score: 1.00849 (no good!)\n'''\nif False:\n    x_train_ = pd.merge(train_x_last, train_x_agg, left_on=\"id\", right_on=\"id_\").drop(['id_', 'time'], axis = 1)\n    x_test_ = pd.merge(test_x_last, test_x_agg, left_on=\"id\", right_on=\"id_\").drop(['id_', 'time'], axis = 1)\n    # Merge keep original order\n    x_train = x_train_.reset_index().merge(train_league, how='left', on='id', sort=False).sort_index()\n    x_test = x_test_.reset_index().merge(test_league, how='left', on='id', sort=False).sort_index()\n    #\n    x_train = x_train.drop(['id', 'index'], axis = 1)\n    x_test = x_test.drop(['id', 'index'], axis = 1)\n'''","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x_train.head(20)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(x_train.shape)\nprint(x_test.shape)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# x_train = train_x_agg.drop(['id_'], axis=1).copy() \n# x_test = test_x_agg.drop(['id_'], axis=1).copy() \n\n# Fill NA with mean\n# fill_mean = False\n# if fill_mean:\n#     x_train = np.where(np.isnan(x_train), np.nanmean(x_train, axis=0), x_train)\n#     x_test = np.where(np.isnan(x_test), np.nanmean(x_test, axis=0), x_test)\n\n'''\nelse:\n    # Fill NA with MASK\n    x_train = np.nan_to_num(x_train, nan=MASK)\n    x_test = np.nan_to_num(x_test, nan=MASK)\n\n# Scale features using statistics that are robust to outliers\nRS = RobustScaler()\nx_train = RS.fit_transform(x_train)\nx_test = RS.transform(x_test)\n# Reshape \nx_train = x_train.reshape(-1, T_HIST, x_train.shape[-1])\nx_test = x_test.reshape(-1, T_HIST, x_test.shape[-1])\n'''\n# Back to dataframe ids x columns_1_10\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Deal with targets\n# encode class values as integers\n'''encoder = LabelEncoder()\nencoder.fit(train_y)\nencoded_y = encoder.transform(train_y)\n# convert integers to dummy variables (i.e. one hot encoded)\ndummy_y = to_categorical(encoded_y)\n# \nprint(encoded_y.shape)\nprint(dummy_y.shape)\n'''\ntarget2int = {'away': 0, 'draw': 1, 'home': 2}\n# encode target\ndummy_y = train_y.map(target2int)\n\n# multi task\n# target2int_2 = {'away': 0, 'draw': 1, 'home': 0}\n# encode target\n# dummy2_y = train_y.map(target2int_2)","metadata":{"_uuid":"129f90f7-7744-488c-9e61-b49bb2c90992","_cell_guid":"40d047c0-ca6f-4bdc-af0f-17e0d1f843f5","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# encoding away: 0 draw: 1 home: 2 \ndummy_y.head()","metadata":{"_uuid":"f66ba6cb-16e0-4560-a345-e5a38b5ed82c","_cell_guid":"6a9dcfac-a3a7-40a2-b7c1-c515319b7e0c","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(dummy_y.shape)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Make a model\nXGBOOST model with aggregated time features.","metadata":{"_uuid":"f0fd77a2-0d9c-4fba-ac6d-f879a553bf4c","_cell_guid":"51235a13-fea9-47fd-a2b9-caeccbd0b67f","trusted":true}},{"cell_type":"markdown","source":"## Fit the model and a make submission\nOnce the model is fitted we make the **probabilities prediction**. Then we make the submission dataframe with **4 columns**. The columns home, away and draw contain probability while the column id contains the match id.","metadata":{"_uuid":"ea635cb3-5380-4259-ad5f-fd94e9606f26","_cell_guid":"0c123082-ce45-4f81-841d-eb90adea1783","trusted":true}},{"cell_type":"code","source":"# N_SPLITS of the traning set for validation using KFold\n# Parameters\n# Train model and predict\n# models = []\n# aucs = []\n# preds = np.zeros(len(train))\n#\nnum_boost_round = 1000\nseed = 123\nN_SPLITS = 5 # 10 (5 is better than 10 Folds)\nFIRST_OOF_ONLY = False\n'''\n# Set LGBM hyper parameters\nlgbm_params = { \"objective\":\"multiclass\"\n    , \"boosting_type\":\"gbdt\"\n    , 'num_class':CLASS\n    , 'metric': 'multi_logloss'\n    , \"random_seed\":SEED\n    , \"max_depth\":5\n    , \"colsample_bytree\":0.5\n    , \"subsample\":0.5\n    , \"lambda_l1\":0.1 #reg_alpha(L1)\n    , \"lambda_l2\":0.9 #reg_lambda(L2)\n    , \"learning_rate\":0.1\n    , \"num_leaves\": 5\n} \n'''\n# Params 2\nlgbm_params = {\n    \"objective\":\"multiclass\" #\"binary\"\n    , \"boosting_type\":\"gbdt\"\n    , 'num_class':CLASS\n    , 'metric': \"multi_logloss\" #''binary_logloss\n    ,        'learning_rate': 0.05,        \n            'lambda_l1': 2,\n            'lambda_l2': 7,\n            'num_leaves': 400,\n            'min_sum_hessian_in_leaf': 20,\n            'feature_fraction': 0.5,\n            'feature_fraction_bynode': 0.5,\n            'bagging_fraction': 0.5,\n            'bagging_freq': 42,\n            'min_data_in_leaf': 700,\n            'max_depth': 5,\n            'seed': seed,\n            'feature_fraction_seed': seed,\n            'bagging_seed': seed,\n            'drop_seed': seed,\n            'data_random_seed': seed,\n            'verbosity': -1\n        }\n\ntest_preds = []\n\nkf = KFold(n_splits=N_SPLITS, random_state=seed, shuffle=True) # KFold\n\nfor fold, (train_idx, test_idx) in enumerate(kf.split(x_train, dummy_y)):\n    print('-'*15, '>', f'Fold {fold+1}/{N_SPLITS}', '<', '-'*15)\n    X_train, X_valid =  x_train.iloc[train_idx], x_train.iloc[test_idx]\n    Y_train, Y_valid =  dummy_y.iloc[train_idx], dummy_y.iloc[test_idx]\n    train_dataset = lgb.Dataset(X_train, Y_train) #, categorical_feature = ['is_cup'])\n    val_dataset = lgb.Dataset(X_valid, Y_valid) # , categorical_feature = ['is_cup'])\n    model = lgb.train(params = lgbm_params, \n                        train_set = train_dataset, \n                        valid_sets = [train_dataset, val_dataset], \n                        num_boost_round = num_boost_round, \n                        callbacks=[lgb.early_stopping(stopping_rounds=50)],\n                        verbose_eval = 50)\n    # Model validation    \n    y_true = Y_valid.squeeze()\n    y_pred = model.predict(X_valid).squeeze()\n    score1 = log_loss(y_true, y_pred)\n    print(f\"Fold-{fold+1} | OOF LogLoss Score: {score1}\")\n    # print(roc_auc_score(y_true, y_pred))\n    # Predictions\n    test_preds.append(model.predict(x_test).squeeze())\n    lgb.plot_importance(model,max_num_features=20)\n    # df_importance = pd.DataFrame({'Value':model.feature_importance(),'Feature':X_train.columns.tolist()}).sort_values(by=\"Value\",ascending=False)\n    # print(df_importance.head(30))\n    if FIRST_OOF_ONLY: break","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# weights\n    # away 0 draw 1 home 2\n    # train_weights = np.where(Y_train == 0,1.,np.where(Y_train == 1,1.25,1.))\n    # val_weights =  np.where(Y_valid == 0,1.,np.where(Y_valid == 1,1.25,1.))\n    # train_dataset = lgb.Dataset(X_train, Y_train, weight = train_weights) #, categorical_feature = ['is_cup'])\n    # val_dataset = lgb.Dataset(X_valid, Y_valid, weight = val_weights)# , categorical_feature = ['is_cup'])","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Second LightGB model\nOnly the last 5 matches...\n\nCancelled due to poor results.","metadata":{}},{"cell_type":"code","source":"'''\n\n# Do it again with up to 5 matches\n\ntrain_x_last_5 = train_x_pivot.loc[train_x_pivot['time'] < 6]\ntest_x_last_5 = test_x_pivot.loc[train_x_pivot['time'] < 6]\n\ntrain_x_agg = agg_features(train_x_last_5)\ntest_x_agg = agg_features(test_x_last_5)\n\n# train_x_last = train_x_pivot.loc[train_x_pivot['time'] == 1]\n# test_x_last = test_x_pivot.loc[train_x_pivot['time'] == 1]\n\n# keep order\n# Merge and drop columns\nx_train = pd.merge(train_x_last, train_x_agg, left_on=\"id\", right_on=\"id_\").drop(['id', 'id_', 'time'], axis = 1).copy()\nx_test = pd.merge(test_x_last, test_x_agg, left_on=\"id\", right_on=\"id_\").drop(['id', 'id_', 'time'], axis = 1).copy()\n'''","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"'''\n# N_SPLITS of the traning set for validation using KFold\n# Parameters\n# Train model and predict\n# models = []\n# aucs = []\n# preds = np.zeros(len(train))\n#\nnum_boost_round = 1000\nSEED = 123\nN_SPLITS = 5\n#\n# Set LGBM hyper parameters\nlgbm_params = { \"objective\":\"multiclass\"\n    , \"boosting_type\":\"gbdt\"\n    , 'num_class':CLASS\n    , 'metric': 'multi_logloss'\n    , \"random_seed\":SEED\n    , \"max_depth\":5\n    , \"colsample_bytree\":0.5\n    , \"subsample\":0.5\n    , \"lambda_l1\":0.1 #reg_alpha(L1)\n    , \"lambda_l2\":0.9 #reg_lambda(L2)\n    , \"learning_rate\":0.1\n    , \"num_leaves\": 5\n} \n'''\n\n'''\n# Params 2\nseed = 2022\nlgbm_params = {\n    \"objective\":\"multiclass\" #\"binary\"\n    , \"boosting_type\":\"gbdt\"\n    , 'num_class':CLASS\n    , 'metric': \"multi_logloss\" #''binary_logloss\n    ,        'learning_rate': 0.1,        \n            'lambda_l1': 2,\n            'lambda_l2': 7,\n            'num_leaves': 400,\n            'min_sum_hessian_in_leaf': 20,\n            'feature_fraction': 0.5,\n            'feature_fraction_bynode': 0.5,\n            'bagging_fraction': 0.25,\n            'bagging_freq': 42,\n            'min_data_in_leaf': 700,\n            'max_depth': 10,\n            'seed': seed,\n            'feature_fraction_seed': seed,\n            'bagging_seed': seed,\n            'drop_seed': seed,\n            'data_random_seed': seed,\n            'verbosity': -1\n        }\n\n\n\ntest_preds_2 = []\n\nkf = StratifiedKFold(n_splits=N_SPLITS, random_state=seed, shuffle=True) # KFold\n\nfor fold, (train_idx, test_idx) in enumerate(kf.split(x_train, dummy_y)):\n    print('-'*15, '>', f'Fold {fold+1}/{N_SPLITS}', '<', '-'*15)\n    X_train, X_valid = x_train.iloc[train_idx], x_train.iloc[test_idx]\n    Y_train, Y_valid = dummy_y.iloc[train_idx], dummy_y.iloc[test_idx]\n    # \n    train_dataset = lgb.Dataset(X_train, Y_train) #, categorical_feature = ['is_cup'])\n    val_dataset = lgb.Dataset(X_valid, Y_valid)# , categorical_feature = ['is_cup'])\n    model = lgb.train(params = lgbm_params, \n                        train_set = train_dataset, \n                        valid_sets = [train_dataset, val_dataset], \n                        num_boost_round = num_boost_round, \n                        callbacks=[lgb.early_stopping(stopping_rounds=50)],\n                        verbose_eval = 50)\n    # Model validation    \n    y_true = Y_valid.squeeze()\n    y_pred = model.predict(X_valid).squeeze()\n    score1 = log_loss(y_true, y_pred)\n    print(f\"Fold-{fold+1} | OOF LogLoss Score: {score1}\")\n    # print(roc_auc_score(y_true, y_pred))\n    # Predictions\n    test_preds_2.append(model.predict(x_test).squeeze())\n    lgb.plot_importance(model,max_num_features=20)\n'''","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"preds = np.argmax(y_pred, axis=1) # preds = np.where(y_pred > 0.5, 1, 0)\ncm = confusion_matrix(y_true, preds)\n# # encoding away: 0 draw: 1 home:2\ndisp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels={'away', 'draw','home',})\ndisp.plot()\nreport = classification_report(y_true, preds)\nprint(report)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions = sum(test_preds)/N_SPLITS\n\n# away, draw, home\nsubmission = pd.DataFrame(predictions,columns=['away', 'draw', 'home'])\n\n# Round\nround_num = False\nif round_num:\n    submission = submission.round(2)\n    submission['draw'] = 1 - (submission['home'] + submission['away'])  \n    \n#do not forget the id column\nsubmission['id'] = test[['id']]\n\n#submit!\nsubmission[['id', 'home', 'away', 'draw']].to_csv('submission.csv', index=False)","metadata":{"_uuid":"fbc22907-d44b-4d98-a63e-7308371f2575","_cell_guid":"daf73b19-9b2b-426f-a75a-eb1842f15261","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission[['id', 'home', 'away', 'draw']].head()","metadata":{"_uuid":"a5aeb080-c652-4e2c-9476-e662c51ff731","_cell_guid":"a7b164c3-f7d6-47a8-b6a6-b84ebb382b4d","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Conclusion\n**Good luck!**\n\nReport any error that you will probably find.","metadata":{"_uuid":"002cd78f-9689-47ca-a8fe-2e28eba99b1d","_cell_guid":"4a755058-46c1-4ab7-9693-2381814c1bc0","trusted":true}}]}