{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nfrom pathlib import Path\n\nimport numpy as np\nimport pandas as pd\nfrom sklearn.preprocessing import MinMaxScaler\nfrom sklearn.model_selection import cross_validate, GridSearchCV\nfrom sklearn.pipeline import make_pipeline\nfrom sklearn.ensemble import RandomForestClassifier, VotingClassifier\nfrom sklearn.svm import SVC\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.metrics import accuracy_score","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"FILEDIR = Path('/kaggle/input/google-cloud-ncaa-march-madness-2020-division-1-mens-tournament')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 提出用ファイルを取得\nsub = pd.read_csv(FILEDIR / 'MSampleSubmissionStage1_2020.csv', usecols=['ID'])\nid_splited = sub['ID'].str.split('_', expand=True).astype(int).rename(columns={0: 'Season', 1: 'Team1', 2: 'Team2'})\nsub = pd.concat([sub, id_splited], axis=1).set_index(['Season', 'Team1', 'Team2']).sort_index()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# シーズン毎の出場チームを抽出\ntourney_teams = {}\ntourney_teams_all = set()\nfor season in sub.index.get_level_values('Season').drop_duplicates():\n    tourney_teams[season] = set()\n    tourney_teams[season].update(sub.loc[season].index.get_level_values('Team1'))\n    tourney_teams[season].update(sub.loc[season].index.get_level_values('Team2'))\n    tourney_teams_all.update(tourney_teams[season])\n{k: len(v) for k, v in tourney_teams.items()}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 所属カンファレンス情報を取得\nconferences = pd.read_csv(FILEDIR / 'MDataFiles_Stage1/MTeamConferences.csv')\nconferences = pd.concat(\n    [conferences.query('Season == @season and TeamID in @teams') for season, teams in tourney_teams.items()])\nconferences = conferences.set_index(['Season', 'TeamID']).sort_index()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# コーチ名を取得\ncoaches = pd.read_csv(FILEDIR / 'MDataFiles_Stage1/MTeamCoaches.csv')\ncoaches = pd.concat(\n    [coaches.query('Season == @season and TeamID in @team') for season, team in tourney_teams.items()])\ncoaches = coaches[coaches['LastDayNum'] == 154].set_index(['Season', 'TeamID']).sort_index()[['CoachName']]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# NCAAの初回出場年を取得し、初回出場年から現在までの年数を計算\nteams = pd.read_csv(FILEDIR / 'MDataFiles_Stage1/MTeams.csv', usecols=['TeamID', 'FirstD1Season'])\nteams['FirstD1Season'] = 2020 - teams['FirstD1Season']\nteams = pd.concat(\n    [teams.query('TeamID in @team').assign(Season=season) for season, team in tourney_teams.items()])\nteams = teams.set_index(['Season', 'TeamID']).sort_index()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 各シーズンのシードを取得\nseeds = pd.read_csv(FILEDIR / 'MDataFiles_Stage1/MNCAATourneySeeds.csv')\nseeds = pd.concat(\n    [seeds.query('Season == @season and TeamID in @teams') for season, teams in tourney_teams.items()])\nseeds = seeds.set_index(['Season', 'TeamID']).sort_index()\nseeds['Region'] = seeds['Seed'].str[0]\nseeds['Number'] = seeds['Seed'].str[1:3].astype(int)\ndel seeds['Seed']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# レギュラーシーズンの累計得点と累計失点を取得\nregular = pd.read_csv(FILEDIR / 'MDataFiles_Stage1/MRegularSeasonDetailedResults.csv')\nregular = regular.drop(columns=['DayNum', 'LTeamID'])\nregular = pd.concat(\n    [regular.query('Season == @season and WTeamID in @teams') for season, teams in tourney_teams.items()])\nregular = regular.groupby(['Season', 'WTeamID']).sum()\nregular = regular.rename_axis(index=['Season', 'TeamID'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 上記取得データをindexで結合\nctcsr = pd.concat([coaches, teams, conferences, seeds, regular], axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# NCAAMトーナメントの勝敗結果を取得\nresult = pd.read_csv(FILEDIR / 'MDataFiles_Stage1/MNCAATourneyCompactResults.csv')\nresult = result[result['Season'] >= 2015].set_index(['Season', 'WTeamID', 'LTeamID'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 各種データと勝敗結果を結合\nmerged_teams = pd.concat(\n    [ctcsr.loc[[(season, wteam), (season, lteam)], :] for season, wteam, lteam, in result.index])\n\nteam1 = merged_teams.iloc[::2, :].reset_index('TeamID') # teams winned\nteam2 = merged_teams.iloc[1::2, :].reset_index('TeamID') # teams losed\n\nmerged_teams = pd.concat([\n    pd.concat([team1.add_suffix('1'), team2.add_suffix('2')], axis=1).assign(Res=1),\n    pd.concat([team2.add_suffix('1'), team1.add_suffix('2')], axis=1).assign(Res=0),\n]).reset_index().set_index(['Season', 'TeamID1', 'TeamID2']).sort_index()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 結合データから目的変数（Res）の列を除き、説明変数Xを抽出\nx_columns = merged_teams.columns[merged_teams.columns != 'Res']\nX = merged_teams[x_columns]\n\n# 数値の列を正規化し、文字の列をダミー変数に変換\ncolumns_number = X.select_dtypes(include='number').columns\nX.loc[:, columns_number] = MinMaxScaler().fit_transform(X[columns_number])\nX = pd.get_dummies(X, columns=x_columns[X.dtypes == 'object'])\nX","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 目的変数yを設定\ny = merged_teams['Res']\ny","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 学習アルゴリズムとパrメータ候補を定義\nclfs = {}\n\n# SVC\nclfs['SVC'] = {\n    'instance': SVC(probability=True),\n    'params': [\n        {'kernel': ['linear'], 'C': [0.01, 0.05, 0.1, 0.5, 1]},\n        {'kernel': ['rbf'], 'C': [1, 10, 50, 100, 250], 'gamma': [0.1, 0.2, 0.3]}\n    ]    \n}\n\n# RandomForest\nclfs['RandomForestClassifier'] = {\n    'instance': RandomForestClassifier(n_jobs=-1),\n    'params': {        \n        'n_estimators': [25, 50, 100],\n        'criterion': ['gini', 'entropy'],\n        'max_depth': [10, 25, 50, None]\n    }\n}\n\n# LogisticRegression\nclfs['LogisticRegression'] = {\n    'instance': LogisticRegression(max_iter=200, n_jobs=-1),\n    'params': [\n            {'penalty': ['l2'], 'C': [0.1, 0.5, 1, 5, 10]},\n            {'penalty': ['l1'], 'solver': ['liblinear', 'saga'], 'C': [0.1, 0.5, 1, 5, 10]},\n            {'penalty': ['elasticnet'], 'C': [0.1, 0.5, 1, 5, 10], 'l1_ratio': [0.1, 0.3, 0.5, 0.7, 0.9]}\n        ]\n}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 学習し、最適なパラメータを探索\nfor clf_name, clf in clfs.items():\n    print('<{}>'.format(clf_name))\n    print('  training ...')\n    \n    # 学習\n    gs = GridSearchCV(clf['instance'], param_grid=clf['params'], cv=5, n_jobs=-1)\n    gs.fit(X, y)\n    \n    print('  best_score: {:.3f}'.format(gs.best_score_))\n    print('  best_params: {}'.format(gs.best_params_))\n    \n    # 最適なパラメータを記録\n    clfs[clf_name]['best_params'] = gs.best_params_","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 最適なパラメータ値で、全データで学習してみる\nfor clf_name, clf in clfs.items():\n    clf['best_estimator'] = clf['instance'].set_params(**clf['best_params']).fit(X, y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"[clf['best_estimator'] for clf in clfs.values()]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 各モデルの予測結果から多数決を採用するソフト分類器を作成\nvote = VotingClassifier(\n    estimators=[(clf_name, clf['best_estimator']) for clf_name, clf in clfs.items()], \n    voting='soft',\n    n_jobs=-1\n)\nvote.fit(X, y)\n\n# 作成したソフト分類器を、clfsに追加\nclfs['Vote'] = {}\nclfs['Vote']['best_estimator'] = vote","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 各モデルとソフト分類器で、予測結果を比較する\n# randomforestだけ精度が異常に高いのは、多分過学習してる。。。\nfor clf_name, clf in clfs.items():\n    score = accuracy_score(y, clf['best_estimator'].predict(X))\n    print(clf_name, score)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 各モデルの予測結果をDataFrameに整形（pp: predict_proba, p: predict）\npredict = pd.DataFrame(\n    {\n        **{'pp_' + clf_name: clf['best_estimator'].predict_proba(X)[:, 1] for clf_name, clf in clfs.items()},\n        **{'p_' + clf_name: clf['best_estimator'].predict(X) for clf_name, clf in clfs.items()}\n    },\n    index=X.index)\npredict","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 提出ファイルにカラムを追加し、予測結果の値を上書き\nfor column in predict.columns:\n    sub[column] = 0.5\n    \nmask = [idx for idx in sub.index if idx in X.index]\nsub.loc[mask, predict.columns] = predict.loc[mask, predict.columns]\nsub","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 予測結果をファイル出力\nfor column in predict.columns:\n    sub[['ID', column]].rename(columns={column: 'pred'}).to_csv('{}.csv'.format(column), index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}