{"cells":[{"cell_type":"code","execution_count":null,"id":"77fbb229","metadata":{},"outputs":[],"source":"import numpy as np\nimport pandas as pd\nimport gc\nimport time\nfrom sklearn.model_selection import KFold\nfrom sklearn.preprocessing import OneHotEncoder\nfrom scipy.stats import dirichlet\nfrom catboost import CatBoostRegressor\nfrom xgboost import XGBRegressor\nfrom lightgbm import LGBMRegressor\n\nBASE = '/kaggle/input/competitions/playground-series-s4e12'\ntrain = pd.read_csv(f'{BASE}/train.csv')\ntest = pd.read_csv(f'{BASE}/test.csv')\n\ntarget = 'Premium Amount'\ny = train[target].values\ntest_ids = test['id'].values\ntrain.drop(columns=[target, 'id'], inplace=True)\ntest.drop(columns=['id'], inplace=True)\n\nnum_cols = [c for c in train.columns if train[c].dtype.kind in 'ifu']\ncat_cols = [c for c in train.columns if train[c].dtype == object and c != 'Policy Start Date']\nn_tr, n_te = len(train), len(test)\n\nX_num = np.zeros((n_tr + n_te, len(num_cols)), dtype=np.float32)\nfor j, c in enumerate(num_cols):\n    med = float(train[c].median())\n    X_num[:n_tr, j] = train[c].fillna(med).to_numpy(dtype=np.float32)\n    X_num[n_tr:, j] = test[c].fillna(med).to_numpy(dtype=np.float32)\n\ndates = pd.to_datetime(pd.concat([train['Policy Start Date'], test['Policy Start Date']]), errors='coerce')\ndate_names = ['year', 'month', 'day', 'dow', 'seconds']\ndate_feats = np.zeros((n_tr + n_te, len(date_names)), dtype=np.float32)\ndate_feats[:, 0] = dates.dt.year.to_numpy(dtype=np.float32)\ndate_feats[:, 1] = dates.dt.month.to_numpy(dtype=np.float32)\ndate_feats[:, 2] = dates.dt.day.to_numpy(dtype=np.float32)\ndate_feats[:, 3] = dates.dt.dayofweek.to_numpy(dtype=np.float32)\nsec = (dates.astype('int64') // 10**9).to_numpy(dtype=np.float32)\nsec[dates.isna().to_numpy()] = np.nan\ndate_feats[:, 4] = sec\ndate_feats = np.nan_to_num(date_feats, nan=np.nanmean(date_feats, axis=0))\nX_num = np.hstack([X_num, date_feats])\ndel dates, sec\n\ncodes = np.zeros((n_tr + n_te, len(cat_cols)), dtype=np.int16)\nn_cats = []\nfor j, c in enumerate(cat_cols):\n    cat = pd.Categorical(pd.concat([train[c].fillna('missing'), test[c].fillna('missing')]))\n    codes[:, j] = cat.codes.astype(np.int16)\n    n_cats.append(len(cat.categories))\n    del cat\n\nohe = OneHotEncoder(categories=[np.arange(k) for k in n_cats], sparse_output=True, dtype=np.float32, handle_unknown='ignore')\nX_cat = ohe.fit_transform(codes).toarray()\ndel train, test\ngc.collect()\n\nD = pd.DataFrame(X_num, columns=num_cols + date_names)\nfor j, c in enumerate(cat_cols):\n    D[c] = codes[:, j]\ny_log = np.log1p(y)\ndel X_num, codes\ngc.collect()\n\nOHE_COLS = [f'O{i}' for i in range(X_cat.shape[1])]\nFEATURES = num_cols + date_names + cat_cols + OHE_COLS\n\ndef make_model(name, gpu=True):\n    if name == 'catboost':\n        return CatBoostRegressor(verbose=0, random_state=42, task_type='GPU', devices='0') if gpu else CatBoostRegressor(verbose=0, random_state=42)\n    if name == 'xgboost':\n        return XGBRegressor(n_jobs=-1, random_state=42, device='cuda') if gpu else XGBRegressor(n_jobs=-1, random_state=42)\n    return LGBMRegressor(n_jobs=-1, random_state=42, verbose=-1, device='gpu') if gpu else LGBMRegressor(n_jobs=-1, random_state=42, verbose=-1)\n\nNFOLDS = 5\nkf = KFold(n_splits=NFOLDS, shuffle=True, random_state=42)\nMODEL_NAMES = ['catboost', 'xgboost', 'lightgbm']\noof = {m: np.zeros(n_tr) for m in MODEL_NAMES}\ntest_pred = {m: np.zeros(n_te) for m in MODEL_NAMES}\nBASE_COLS = num_cols + date_names + cat_cols\n\nfor fold, (tr_idx, va_idx) in enumerate(kf.split(np.arange(n_tr))):\n    t0 = time.time()\n    trf = D.iloc[tr_idx][BASE_COLS].reset_index(drop=True)\n    vaf = D.iloc[va_idx][BASE_COLS].reset_index(drop=True)\n    tef = D.iloc[n_tr:][BASE_COLS].reset_index(drop=True)\n    trf[OHE_COLS] = X_cat[tr_idx]\n    vaf[OHE_COLS] = X_cat[va_idx]\n    tef[OHE_COLS] = X_cat[n_tr:]\n    X_tr = trf[FEATURES]\n    y_tr = np.log1p(y[tr_idx])\n    X_va = vaf[FEATURES]\n    X_te = tef[FEATURES]\n    for name in MODEL_NAMES:\n        model = make_model(name, gpu=True)\n        try:\n            model.fit(X_tr, y_tr)\n        except Exception as e:\n            print(f'{name} GPU failed ({e}), falling back to CPU', flush=True)\n            model = make_model(name, gpu=False)\n            model.fit(X_tr, y_tr)\n        oof[name][va_idx] = model.predict(X_va)\n        test_pred[name] += model.predict(X_te) / NFOLDS\n    print(f'fold {fold + 1}/5 done in {time.time() - t0:.0f}s', flush=True)\n\nnames = MODEL_NAMES\nOOF = np.column_stack([oof[m] for m in names])\nTP = np.column_stack([test_pred[m] for m in names])\n\nbest_score = np.inf\nbest_w = None\nfor i in range(500):\n    w = dirichlet.rvs(np.ones(len(names)))[0]\n    s = np.sqrt(np.mean((OOF @ w - y_log) ** 2))\n    if s < best_score:\n        best_score, best_w = s, w\n\nfinal_pred = np.expm1(TP @ best_w)\nsub = pd.DataFrame({'id': test_ids, 'Premium Amount': final_pred})\nsub.to_csv('submission.csv', index=False)\nprint('best OOF RMSLE:', best_score)\nprint('dirichlet weights:', best_w)\nsub.head()"}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"}},"nbformat":4,"nbformat_minor":5}