{"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":"# NCAAM2020: XGBoost + LightGBM K-Fold Ensemble (Baseline)","metadata":{}},{"cell_type":"markdown","source":"- Original logs from 2020:\n    - Built upon from https://www.kaggle.com/ratan123/march-madness-2020-ncaam-simple-lightgbm-on-kfold\n    - Added XGBoost and K-fold ensemble\n- 2021 logs:\n    - added option to use 2021 data in stage 1","metadata":{}},{"cell_type":"markdown","source":"## Master Configs","metadata":{}},{"cell_type":"code","source":"YEAR = 2021 # or 2020 from google cloud competition\nSTAGE = 2\nNCAAM = True\nNCAAW = False","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if NCAAM:\n    DATA_DIR = f'../input/ncaam-march-mania-2021/MDataFiles_Stage{STAGE}/'\nif NCAAW:\n    DATA_DIR = f'../input/ncaaw-march-mania-2021/WDataFiles_Stage{STAGE}/'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Import Library & Load Data","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nfrom sklearn.linear_model import LogisticRegression\nimport matplotlib.pyplot as plt\nfrom sklearn.utils import shuffle\nfrom sklearn.model_selection import GridSearchCV\nfrom sklearn.model_selection import KFold\nimport lightgbm as lgb\nimport xgboost as xgb\nfrom xgboost import XGBClassifier\nimport gc","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if YEAR == 2020:\n    tourney_result = pd.read_csv('../input/google-cloud-ncaa-march-madness-2020-division-1-mens-tournament/MDataFiles_Stage1/MNCAATourneyCompactResults.csv')\n    tourney_seed = pd.read_csv('../input/google-cloud-ncaa-march-madness-2020-division-1-mens-tournament/MDataFiles_Stage1/MNCAATourneySeeds.csv')\nelif YEAR == 2021:\n    tourney_result = pd.read_csv(DATA_DIR + 'MNCAATourneyCompactResults.csv')\n    tourney_seed = pd.read_csv(DATA_DIR + 'MNCAATourneySeeds.csv')","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# deleting unnecessary columns\ntourney_result = tourney_result.drop(['DayNum', 'WScore', 'LScore', 'WLoc', 'NumOT'], axis=1)\ntourney_result","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Merge Seed","metadata":{}},{"cell_type":"code","source":"tourney_result = pd.merge(tourney_result, tourney_seed, left_on=['Season', 'WTeamID'], right_on=['Season', 'TeamID'], how='left')\ntourney_result.rename(columns={'Seed':'WSeed'}, inplace=True)\ntourney_result = tourney_result.drop('TeamID', axis=1)\ntourney_result = pd.merge(tourney_result, tourney_seed, left_on=['Season', 'LTeamID'], right_on=['Season', 'TeamID'], how='left')\ntourney_result.rename(columns={'Seed':'LSeed'}, inplace=True)\ntourney_result = tourney_result.drop('TeamID', axis=1)\ntourney_result","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_seed(x):\n    return int(x[1:3])\n\ntourney_result['WSeed'] = tourney_result['WSeed'].map(lambda x: get_seed(x))\ntourney_result['LSeed'] = tourney_result['LSeed'].map(lambda x: get_seed(x))\ntourney_result","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Merge Score","metadata":{}},{"cell_type":"code","source":"# select year's data to use\nif YEAR == 2020:\n    season_result = pd.read_csv('../input/google-cloud-ncaa-march-madness-2020-division-1-mens-tournament/MDataFiles_Stage1/MRegularSeasonCompactResults.csv')\nelif YEAR == 2021:\n    season_result = pd.read_csv(DATA_DIR + 'MRegularSeasonCompactResults.csv')","metadata":{"execution":{"iopub.status.busy":"2021-06-24T13:33:29.558715Z","iopub.execute_input":"2021-06-24T13:33:29.559193Z","iopub.status.idle":"2021-06-24T13:33:29.649402Z","shell.execute_reply.started":"2021-06-24T13:33:29.559141Z","shell.execute_reply":"2021-06-24T13:33:29.648116Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"season_win_result = season_result[['Season', 'WTeamID', 'WScore']]\nseason_lose_result = season_result[['Season', 'LTeamID', 'LScore']]\nseason_win_result.rename(columns={'WTeamID':'TeamID', 'WScore':'Score'}, inplace=True)\nseason_lose_result.rename(columns={'LTeamID':'TeamID', 'LScore':'Score'}, inplace=True)\nseason_result = pd.concat((season_win_result, season_lose_result)).reset_index(drop=True)\nseason_result","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"season_score = season_result.groupby(['Season', 'TeamID'])['Score'].sum().reset_index()\nseason_score","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tourney_result = pd.merge(tourney_result, season_score, left_on=['Season', 'WTeamID'], right_on=['Season', 'TeamID'], how='left')\ntourney_result.rename(columns={'Score':'WScoreT'}, inplace=True)\ntourney_result = tourney_result.drop('TeamID', axis=1)\ntourney_result = pd.merge(tourney_result, season_score, left_on=['Season', 'LTeamID'], right_on=['Season', 'TeamID'], how='left')\ntourney_result.rename(columns={'Score':'LScoreT'}, inplace=True)\ntourney_result = tourney_result.drop('TeamID', axis=1)\ntourney_result","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tourney_win_result = tourney_result.drop(['Season', 'WTeamID', 'LTeamID'], axis=1)\ntourney_win_result.rename(columns={'WSeed':'Seed1', 'LSeed':'Seed2', 'WScoreT':'ScoreT1', 'LScoreT':'ScoreT2'}, inplace=True)\ntourney_win_result","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tourney_lose_result = tourney_win_result.copy()\ntourney_lose_result['Seed1'] = tourney_win_result['Seed2']\ntourney_lose_result['Seed2'] = tourney_win_result['Seed1']\ntourney_lose_result['ScoreT1'] = tourney_win_result['ScoreT2']\ntourney_lose_result['ScoreT2'] = tourney_win_result['ScoreT1']\ntourney_lose_result","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prepare Training Data","metadata":{}},{"cell_type":"code","source":"tourney_win_result['Seed_diff'] = tourney_win_result['Seed1'] - tourney_win_result['Seed2']\ntourney_win_result['ScoreT_diff'] = tourney_win_result['ScoreT1'] - tourney_win_result['ScoreT2']\ntourney_lose_result['Seed_diff'] = tourney_lose_result['Seed1'] - tourney_lose_result['Seed2']\ntourney_lose_result['ScoreT_diff'] = tourney_lose_result['ScoreT1'] - tourney_lose_result['ScoreT2']","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tourney_win_result['result'] = 1\ntourney_lose_result['result'] = 0\ntourney_result = pd.concat((tourney_win_result, tourney_lose_result)).reset_index(drop=True)\ntourney_result","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preparing testing data","metadata":{}},{"cell_type":"code","source":"if YEAR == 2020:\n    test_df = pd.read_csv('../input/google-cloud-ncaa-march-madness-2020-division-1-mens-tournament/MSampleSubmissionStage1_2020.csv')\nelif YEAR == 2021:\n    test_df = pd.read_csv(DATA_DIR + f'MSampleSubmissionStage{STAGE}.csv')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df['Season'] = test_df['ID'].map(lambda x: int(x[:4]))\ntest_df['WTeamID'] = test_df['ID'].map(lambda x: int(x[5:9]))\ntest_df['LTeamID'] = test_df['ID'].map(lambda x: int(x[10:14]))\ntest_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df = pd.merge(test_df, tourney_seed, left_on=['Season', 'WTeamID'], right_on=['Season', 'TeamID'], how='left')\ntest_df.rename(columns={'Seed':'Seed1'}, inplace=True)\ntest_df = test_df.drop('TeamID', axis=1)\ntest_df = pd.merge(test_df, tourney_seed, left_on=['Season', 'LTeamID'], right_on=['Season', 'TeamID'], how='left')\ntest_df.rename(columns={'Seed':'Seed2'}, inplace=True)\ntest_df = test_df.drop('TeamID', axis=1)\ntest_df = pd.merge(test_df, season_score, left_on=['Season', 'WTeamID'], right_on=['Season', 'TeamID'], how='left')\ntest_df.rename(columns={'Score':'ScoreT1'}, inplace=True)\ntest_df = test_df.drop('TeamID', axis=1)\ntest_df = pd.merge(test_df, season_score, left_on=['Season', 'LTeamID'], right_on=['Season', 'TeamID'], how='left')\ntest_df.rename(columns={'Score':'ScoreT2'}, inplace=True)\ntest_df = test_df.drop('TeamID', axis=1)\ntest_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df['Seed1'] = test_df['Seed1'].map(lambda x: get_seed(x))\ntest_df['Seed2'] = test_df['Seed2'].map(lambda x: get_seed(x))\ntest_df['Seed_diff'] = test_df['Seed1'] - test_df['Seed2']\ntest_df['ScoreT_diff'] = test_df['ScoreT1'] - test_df['ScoreT2']\ntest_df = test_df.drop(['ID', 'Pred', 'Season', 'WTeamID', 'LTeamID'], axis=1)\ntest_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train","metadata":{}},{"cell_type":"code","source":"X = tourney_result.drop('result', axis=1)\ny = tourney_result.result","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(X.head(5))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(y.head(5))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model Training & Evaluation","metadata":{}},{"cell_type":"code","source":"params_lgb = {'num_leaves': 127,\n          'min_data_in_leaf': 10,\n          'objective': 'binary',\n          'max_depth': -1,\n          'learning_rate': 0.01,\n          \"boosting_type\": \"gbdt\",\n          \"bagging_seed\": 11,\n          \"metric\": 'logloss',\n          \"verbosity\": 0\n          }\n\nparams_xgb = {'colsample_bytree': 0.8,                 \n              'learning_rate': 0.0003,\n              'max_depth': 31,\n              'subsample': 1,\n              'objective':'binary:logistic',\n              'eval_metric':'logloss',\n              'min_child_weight':3,\n              'gamma':0.25,\n              'n_estimators':5000,\n              'verbosity':0\n              }","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### LightGBM Predictions","metadata":{}},{"cell_type":"code","source":"NFOLDS = 5 #10\nfolds = KFold(n_splits=NFOLDS)\n\ncolumns = X.columns\nsplits = folds.split(X, y)\ny_preds_lgb = np.zeros(test_df.shape[0])\ny_oof_lgb = np.zeros(X.shape[0])\n  \nfor fold_n, (train_index, valid_index) in enumerate(splits):\n    #print('Fold:',fold_n+1)\n    X_train, X_valid = X[columns].iloc[train_index], X[columns].iloc[valid_index]\n    y_train, y_valid = y.iloc[train_index], y.iloc[valid_index]\n    \n    dtrain = lgb.Dataset(X_train, label=y_train)\n    dvalid = lgb.Dataset(X_valid, label=y_valid)\n\n    clf = lgb.train(params_lgb, dtrain, 10000, valid_sets = [dtrain, dvalid], verbose_eval=200)\n    \n    y_pred_valid = clf.predict(X_valid)\n    y_oof_lgb[valid_index] = y_pred_valid\n    \n    y_preds_lgb += clf.predict(test_df) / NFOLDS\n    \n    del X_train, X_valid, y_train, y_valid\n    gc.collect()","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### XGBoost Predictions","metadata":{}},{"cell_type":"code","source":"NFOLDS = 10\nfolds = KFold(n_splits=NFOLDS)\n\ncolumns = X.columns\nsplits = folds.split(X, y)\n\ny_preds_xgb = np.zeros(test_df.shape[0])\ny_oof_xgb = np.zeros(X.shape[0])\n  \nfor fold_n, (train_index, valid_index) in enumerate(splits):\n    #print('Fold:',fold_n+1)\n    X_train, X_valid = X[columns].iloc[train_index], X[columns].iloc[valid_index]\n    y_train, y_valid = y.iloc[train_index], y.iloc[valid_index]\n    \n    train_set = xgb.DMatrix(X_train, y_train)\n    val_set = xgb.DMatrix(X_valid, y_valid)\n    test_set = xgb.DMatrix(test_df)\n    \n    clf = xgb.train(params_xgb, train_set,num_boost_round=5000, evals=[(train_set, 'train'), (val_set, 'val')], early_stopping_rounds=100, verbose_eval=100)\n    \n    y_preds_xgb += clf.predict(test_set) / NFOLDS\n    \n    del X_train, X_valid, y_train, y_valid\n    gc.collect()","metadata":{"_kg_hide-output":true,"_kg_hide-input":false,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(len(y_preds_xgb))\nprint(len(y_preds_lgb))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_preds_lgb","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_preds_xgb","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Ensemble & Make Submission File","metadata":{}},{"cell_type":"code","source":"if YEAR == 2020:\n    submission_df = pd.read_csv('../input/google-cloud-ncaa-march-madness-2020-division-1-mens-tournament/MSampleSubmissionStage1_2020.csv')\nelif YEAR == 2021:\n    submission_df = pd.read_csv(DATA_DIR + f'MSampleSubmissionStage{STAGE}.csv')\nsubmission_df['Pred'] = 0.9*y_preds_lgb + 0.1*y_preds_xgb\nsubmission_df","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df['Pred'].hist()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Future Work\n\n- GridSearchCV (since this runs considerably fast)\n- CatBoost\n- LSTM\n- Ensembles of XGBoost, LightGBM, CatBoost, LSTM\n- Ensemble weights by correlations","metadata":{}}]}