{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":81933,"databundleVersionId":9643020,"sourceType":"competition"},{"sourceId":197506774,"sourceType":"kernelVersion"},{"sourceType":"kernelVersion","sourceId":205014390}],"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Modular Data Load Class for Starter Notebook\n\nI improved the [starter notebook](https://www.kaggle.com/code/onodera/starter-notebook-with-polars-gpu)  by turning the data load into a class. This helped me get up to speed faster and will hopefully make it easier for others to jump in as well!\n\n","metadata":{}},{"cell_type":"code","source":"!nvidia-smi","metadata":{"execution":{"iopub.status.busy":"2024-11-04T19:24:36.063490Z","iopub.execute_input":"2024-11-04T19:24:36.064546Z","iopub.status.idle":"2024-11-04T19:24:37.221416Z","shell.execute_reply.started":"2024-11-04T19:24:36.064497Z","shell.execute_reply":"2024-11-04T19:24:37.220268Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install /kaggle/input/polars-gpu-1-7-1/cupy_cuda12x-13.3.0-cp310-cp310-manylinux2014_x86_64.whl\n!pip install /kaggle/input/polars-gpu-1-7-1/rmm_cu12-24.8.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl\n!pip install /kaggle/input/polars-gpu-1-7-1/cudf_cu12-24.8.3-cp310-cp310-manylinux_2_28_x86_64.whl\n!pip install /kaggle/input/polars-gpu-1-7-1/polars-1.7.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\n!pip install /kaggle/input/polars-gpu-1-7-1/cudf_polars_cu12-24.8.3-py3-none-any.whl","metadata":{"execution":{"iopub.status.busy":"2024-11-04T19:24:37.223693Z","iopub.execute_input":"2024-11-04T19:24:37.224100Z","iopub.status.idle":"2024-11-04T19:27:23.174344Z","shell.execute_reply.started":"2024-11-04T19:24:37.224047Z","shell.execute_reply":"2024-11-04T19:27:23.173008Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls /kaggle/usr/lib\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-04T19:27:23.176146Z","iopub.execute_input":"2024-11-04T19:27:23.176595Z","iopub.status.idle":"2024-11-04T19:27:24.250862Z","shell.execute_reply.started":"2024-11-04T19:27:23.176545Z","shell.execute_reply":"2024-11-04T19:27:24.249529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import warnings\nfrom functools import partial\nfrom pathlib import Path\n\nfrom tqdm import tqdm\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport optuna\nimport polars as pl\nimport polars.selectors as cs\nfrom catboost import CatBoostRegressor, MultiTargetCustomMetric\nfrom numpy.typing import ArrayLike, NDArray\nfrom polars.testing import assert_frame_equal\nfrom sklearn.base import BaseEstimator\nfrom sklearn.metrics import cohen_kappa_score\nfrom sklearn.model_selection import StratifiedKFold\n\nwarnings.filterwarnings(\"ignore\", message=\"Failed to optimize method\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-04T19:27:24.272402Z","iopub.execute_input":"2024-11-04T19:27:24.272773Z","iopub.status.idle":"2024-11-04T19:27:24.283355Z","shell.execute_reply.started":"2024-11-04T19:27:24.272694Z","shell.execute_reply":"2024-11-04T19:27:24.282272Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Load_Child_Mind_Data:\n    \"\"\" loads in the csv and parquet data, defines target cols and feature columns, and combines \n    all the data into a final 'train' and 'test' set. Performs some validation on the train/test sets\n    \"\"\"\n    def __init__(self):\n        self.IS_TEST = None\n        self.train = None\n        self.test = None\n        self.train_test = None\n        self.train_agg = None\n        self.test_agg = None\n        self.X = None\n        self.X_test = None\n        self.y = None\n        self.y_sii = None\n        self.cat_features = None\n        self.DATA_DIR = Path(\"/kaggle/input/child-mind-institute-problematic-internet-use\")\n        self.TARGET_COLS = [\n            \"PCIAT-PCIAT_01\",\n            \"PCIAT-PCIAT_02\",\n            \"PCIAT-PCIAT_03\",\n            \"PCIAT-PCIAT_04\",\n            \"PCIAT-PCIAT_05\",\n            \"PCIAT-PCIAT_06\",\n            \"PCIAT-PCIAT_07\",\n            \"PCIAT-PCIAT_08\",\n            \"PCIAT-PCIAT_09\",\n            \"PCIAT-PCIAT_10\",\n            \"PCIAT-PCIAT_11\",\n            \"PCIAT-PCIAT_12\",\n            \"PCIAT-PCIAT_13\",\n            \"PCIAT-PCIAT_14\",\n            \"PCIAT-PCIAT_15\",\n            \"PCIAT-PCIAT_16\",\n            \"PCIAT-PCIAT_17\",\n            \"PCIAT-PCIAT_18\",\n            \"PCIAT-PCIAT_19\",\n            \"PCIAT-PCIAT_20\",\n            \"PCIAT-PCIAT_Total\",\n            \"sii\",\n        ]\n        self.FEATURE_COLS = [\n            \"Basic_Demos-Enroll_Season\",\n            \"Basic_Demos-Age\",\n            \"Basic_Demos-Sex\",\n            \"CGAS-Season\",\n            \"CGAS-CGAS_Score\",\n            \"Physical-Season\",\n            \"Physical-BMI\",\n            \"Physical-Height\",\n            \"Physical-Weight\",\n            \"Physical-Waist_Circumference\",\n            \"Physical-Diastolic_BP\",\n            \"Physical-HeartRate\",\n            \"Physical-Systolic_BP\",\n            \"Fitness_Endurance-Season\",\n            \"Fitness_Endurance-Max_Stage\",\n            \"Fitness_Endurance-Time_Mins\",\n            \"Fitness_Endurance-Time_Sec\",\n            \"FGC-Season\",\n            \"FGC-FGC_CU\",\n            \"FGC-FGC_CU_Zone\",\n            \"FGC-FGC_GSND\",\n            \"FGC-FGC_GSND_Zone\",\n            \"FGC-FGC_GSD\",\n            \"FGC-FGC_GSD_Zone\",\n            \"FGC-FGC_PU\",\n            \"FGC-FGC_PU_Zone\",\n            \"FGC-FGC_SRL\",\n            \"FGC-FGC_SRL_Zone\",\n            \"FGC-FGC_SRR\",\n            \"FGC-FGC_SRR_Zone\",\n            \"FGC-FGC_TL\",\n            \"FGC-FGC_TL_Zone\",\n            \"BIA-Season\",\n            \"BIA-BIA_Activity_Level_num\",\n            \"BIA-BIA_BMC\",\n            \"BIA-BIA_BMI\",\n            \"BIA-BIA_BMR\",\n            \"BIA-BIA_DEE\",\n            \"BIA-BIA_ECW\",\n            \"BIA-BIA_FFM\",\n            \"BIA-BIA_FFMI\",\n            \"BIA-BIA_FMI\",\n            \"BIA-BIA_Fat\",\n            \"BIA-BIA_Frame_num\",\n            \"BIA-BIA_ICW\",\n            \"BIA-BIA_LDM\",\n            \"BIA-BIA_LST\",\n            \"BIA-BIA_SMM\",\n            \"BIA-BIA_TBW\",\n            \"PAQ_A-Season\",\n            \"PAQ_A-PAQ_A_Total\",\n            \"PAQ_C-Season\",\n            \"PAQ_C-PAQ_C_Total\",\n            \"SDS-Season\",\n            \"SDS-SDS_Total_Raw\",\n            \"SDS-SDS_Total_T\",\n            \"PreInt_EduHx-Season\",\n            \"PreInt_EduHx-computerinternet_hoursday\",\n            \n            # stats features from parquets\n            \"X_min\",\n            \"Y_min\",\n            \"Z_min\",\n            \"enmo_min\",\n            \"anglez_min\",\n            \"light_min\",\n            \"battery_voltage_min\",\n            \"X_mean\",\n            \"Y_mean\",\n            \"Z_mean\",\n            \"enmo_mean\",\n            \"anglez_mean\",\n            \"light_mean\",\n            \"battery_voltage_mean\",\n            \"X_max\",\n            \"Y_max\",\n            \"Z_max\",\n            \"enmo_max\",\n            \"anglez_max\",\n            \"light_max\",\n            \"battery_voltage_max\",\n            \"X_std\",\n            \"Y_std\",\n            \"Z_std\",\n            \"enmo_std\",\n            \"anglez_std\",\n            \"light_std\",\n            \"battery_voltage_std\"]\n\n    def load_csv_data(self):\n        \"\"\" reads in train, test, train_test data\"\"\"\n        self.train = pl.read_csv(self.DATA_DIR / \"train.csv\")\n        self.test = pl.read_csv(self.DATA_DIR / \"test.csv\")\n        self.train_test = pl.concat([self.train, self.test], how=\"diagonal\")\n        return self.train, self.test, self.train_test\n\n    def validate_csv_data(self):\n        \"\"\"validates that the datasets are at the appropriate height, and that train and test \n        were combined properly into train_test. Sets IS_TEST variable.\n        Since this is encapsulated in a function, I need to figure something out for the assert_frame_equal\"\"\"\n        self.IS_TEST = self.test.height <= 100\n        assert_frame_equal(self.train, self.train_test[: self.train.height].select(self.train.columns))\n        assert_frame_equal(self.test, self.train_test[self.train.height :].select(self.test.columns))\n        return\n\n    def fill_nans_csv_data(self):\n        \"\"\"fill NANs, returns train,test,train_test\"\"\"\n        self.train_test = self.train_test.with_columns(cs.string().cast(pl.Categorical).fill_null(\"NAN\"))\n        self.train = self.train_test[: self.train.height]\n        self.test = self.train_test[self.train.height :]\n        return self.train, self.test, self.train_test\n        \n    def get_globals(self):\n        \"\"\"data_dir , target_cols,and  feature_cols \"\"\"\n        return self.IS_TEST, self.DATA_DIR, self.TARGET_COLS, self.FEATURE_COLS\n        \n    def split_array(self,ar, n_group):\n        for i_chunk in range(n_group):\n            yield ar[i_chunk * len(ar) // n_group : (i_chunk + 1) * len(ar) // n_group]\n        return\n    \n    def agg_parquets(self,files):\n        cols = [\"X\", \"Y\", \"Z\", \"enmo\", \"anglez\", \"light\", \"battery_voltage\"]\n        aggs = []\n        files_chunks = list(self.split_array(files, 10))\n        for files_tmp in tqdm(files_chunks):\n            if len(files_tmp) == 0:\n                continue\n            dfs = []\n            for file in files_tmp:\n                df = pl.scan_parquet(file)\n                df = df.with_columns(pl.lit(file.parts[-1].split(\"=\")[1]).alias(\"id\"))\n                dfs.append(df)\n            df = pl.concat(dfs)\n            agg = (\n                df.group_by(\"id\")\n                .agg(\n                    [pl.col(c).cast(pl.Float32).min().alias(f\"{c}_min\") for c in cols]\n                    + [pl.col(c).cast(pl.Float32).mean().alias(f\"{c}_mean\") for c in cols]\n                    + [pl.col(c).cast(pl.Float32).max().alias(f\"{c}_max\") for c in cols]\n                    + [pl.col(c).cast(pl.Float32).std().alias(f\"{c}_std\") for c in cols]\n                )\n                .collect(engine=\"gpu\")\n            )\n            aggs.append(agg)\n        return pl.concat(aggs)\n    \n    def train_test_parquet_agg(self):\n        \"\"\" runs the agg_parquets() function on the test and train data. returns train_agg and test_agg\"\"\"\n        self.train_agg = self.agg_parquets(sorted(Path(\"/kaggle/input/child-mind-institute-problematic-internet-use/series_train.parquet\").glob(\"*\")))\n        self.test_agg = self.agg_parquets(sorted(Path(\"/kaggle/input/child-mind-institute-problematic-internet-use/series_test.parquet\").glob(\"*\")))\n        return self.train_agg, self.test_agg\n    \n    def combine_datasets(self):\n        \"\"\"this combines the combine train_agg/test_agg from parquet with the dataframe train/test loaded earlier.\n        Returns train, test\"\"\"\n        self.train = self.train.join(self.train_agg.with_columns(pl.col(\"id\").cast(pl.Categorical)), on='id', how='left')\n        self.test = self.test.join(self.test_agg.with_columns(pl.col(\"id\").cast(pl.Categorical)), on='id', how='left')\n        return self.train, self.test\n\n    def final_datasets(self):\n        \"\"\"ignore rows with null values in TARGET_COLS, create ground_truth column, \n        separate into X, X_test, y, y_sii, and categorical features\"\"\"\n        train_without_null = self.train.drop_nulls(subset=self.TARGET_COLS)\n        self.X = train_without_null.select(self.FEATURE_COLS)\n        self.X_test = self.test.select(self.FEATURE_COLS)\n        self.y = train_without_null.select(self.TARGET_COLS)\n        self.y_sii = self.y.get_column(\"sii\").to_numpy()  # ground truth\n        self.cat_features = self.X.select(cs.categorical()).columns\n        return \n\n    def load_data(self):\n        \"\"\"loads csv data, validates csv data, loads parquet data and aggregates, then combines these datasets. They become\n        X, X_test, y, y_sii and cat_features as attributes of the Load_Child_Mind_Data object\n        Returns none\"\"\"\n        self.load_csv_data()\n        self.validate_csv_data()\n        self.fill_nans_csv_data()\n        self.train_test_parquet_agg()\n        self.combine_datasets()\n        self.final_datasets()\n        return \n\n    def get_final_datasets(self):\n        \"\"\"returns self.X, self.X_test, self.y, self.y_sii, self.cat_features\n        which are created in load_data function\"\"\"\n        return self.X, self.X_test, self.y, self.y_sii, self.cat_features, self.test\n        ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-04T19:27:24.284714Z","iopub.execute_input":"2024-11-04T19:27:24.285051Z","iopub.status.idle":"2024-11-04T19:27:24.319990Z","shell.execute_reply.started":"2024-11-04T19:27:24.285016Z","shell.execute_reply":"2024-11-04T19:27:24.319110Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nimport load_child_mind_institute_data as data_class\n\ndata_obj = Load_Child_Mind_Data()\nIS_TEST, DATA_DIR, TARGET_COLS, FEATURE_COLS = data_obj.get_globals()\ndata_obj.load_data()\nX, X_test, y, y_sii, cat_features,test = data_obj.get_final_datasets()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-04T19:27:24.321247Z","iopub.execute_input":"2024-11-04T19:27:24.321571Z","iopub.status.idle":"2024-11-04T19:27:57.558655Z","shell.execute_reply.started":"2024-11-04T19:27:24.321528Z","shell.execute_reply":"2024-11-04T19:27:57.557588Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X_test.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-04T19:27:57.559935Z","iopub.execute_input":"2024-11-04T19:27:57.560294Z","iopub.status.idle":"2024-11-04T19:27:57.573528Z","shell.execute_reply.started":"2024-11-04T19:27:57.560257Z","shell.execute_reply":"2024-11-04T19:27:57.572661Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class MultiTargetQWK(MultiTargetCustomMetric):\n    def get_final_error(self, error, weight):\n        return np.sum(error)  # / np.sum(weight)\n\n    def is_max_optimal(self):\n        # if True, the bigger the better\n        return True\n\n    def evaluate(self, approxes, targets, weight):\n        # approxes: 予測値 (shape: [ターゲット数, サンプル数])\n        # targets: 実際の値 (shape: [ターゲット数, サンプル数])\n        # weight: サンプルごとの重み (Noneも可)\n\n        approx = np.clip(approxes[-1], 0, 3).round().astype(int)\n        target = targets[-1]\n\n        qwk = cohen_kappa_score(target, approx, weights=\"quadratic\")\n\n        return qwk, 1\n\n    def get_custom_metric_name(self):\n        return \"MultiTargetQWK\"\n\n\nclass OptimizedRounder:\n    \"\"\"\n    A class for optimizing the rounding of continuous predictions into discrete class labels using Optuna.\n    The optimization process maximizes the Quadratic Weighted Kappa score by learning thresholds that separate\n    continuous predictions into class intervals.\n\n    Args:\n        n_classes (int): The number of discrete class labels.\n        n_trials (int, optional): The number of trials for the Optuna optimization. Defaults to 100.\n\n    Attributes:\n        n_classes (int): The number of discrete class labels.\n        labels (NDArray[np.int_]): An array of class labels from 0 to `n_classes - 1`.\n        n_trials (int): The number of optimization trials.\n        metric (Callable): The Quadratic Weighted Kappa score metric used for optimization.\n        thresholds (List[float]): The optimized thresholds learned after calling `fit()`.\n\n    Methods:\n        fit(y_pred: NDArray[np.float_], y_true: NDArray[np.int_]) -> None:\n            Fits the rounding thresholds based on continuous predictions and ground truth labels.\n\n            Args:\n                y_pred (NDArray[np.float_]): Continuous predictions that need to be rounded.\n                y_true (NDArray[np.int_]): Ground truth class labels.\n\n            Returns:\n                None\n\n        predict(y_pred: NDArray[np.float_]) -> NDArray[np.int_]:\n            Predicts discrete class labels by rounding continuous predictions using the fitted thresholds.\n            `fit()` must be called before `predict()`.\n\n            Args:\n                y_pred (NDArray[np.float_]): Continuous predictions to be rounded.\n\n            Returns:\n                NDArray[np.int_]: Predicted class labels.\n\n        _normalize(y: NDArray[np.float_]) -> NDArray[np.float_]:\n            Normalizes the continuous values to the range [0, `n_classes - 1`].\n\n            Args:\n                y (NDArray[np.float_]): Continuous values to be normalized.\n\n            Returns:\n                NDArray[np.float_]: Normalized values.\n\n    References:\n        - This implementation uses Optuna for threshold optimization.\n        - Quadratic Weighted Kappa is used as the evaluation metric.\n    \"\"\"\n\n    def __init__(self, n_classes: int, n_trials: int = 100):\n        self.n_classes = n_classes\n        self.labels = np.arange(n_classes)\n        self.n_trials = n_trials\n        self.metric = partial(cohen_kappa_score, weights=\"quadratic\")\n\n    def fit(self, y_pred: NDArray[np.float_], y_true: NDArray[np.int_]) -> None:\n        y_pred = self._normalize(y_pred)\n\n        def objective(trial: optuna.Trial) -> float:\n            thresholds = []\n            for i in range(self.n_classes - 1):\n                low = max(thresholds) if i > 0 else min(self.labels)\n                high = max(self.labels)\n                th = trial.suggest_float(f\"threshold_{i}\", low, high)\n                thresholds.append(th)\n            try:\n                y_pred_rounded = np.digitize(y_pred, thresholds)\n            except ValueError:\n                return -100\n            return self.metric(y_true, y_pred_rounded)\n\n        optuna.logging.disable_default_handler()\n        study = optuna.create_study(direction=\"maximize\")\n        study.optimize(\n            objective,\n            n_trials=self.n_trials,\n        )\n        self.thresholds = [study.best_params[f\"threshold_{i}\"] for i in range(self.n_classes - 1)]\n\n    def predict(self, y_pred: NDArray[np.float_]) -> NDArray[np.int_]:\n        assert hasattr(self, \"thresholds\"), \"fit() must be called before predict()\"\n        y_pred = self._normalize(y_pred)\n        return np.digitize(y_pred, self.thresholds)\n\n    def _normalize(self, y: NDArray[np.float_]) -> NDArray[np.float_]:\n        # normalize y_pred to [0, n_classes - 1]\n        return (y - y.min()) / (y.max() - y.min()) * (self.n_classes - 1)","metadata":{"execution":{"iopub.status.busy":"2024-11-04T19:27:57.575044Z","iopub.execute_input":"2024-11-04T19:27:57.575380Z","iopub.status.idle":"2024-11-04T19:27:57.600557Z","shell.execute_reply.started":"2024-11-04T19:27:57.575347Z","shell.execute_reply":"2024-11-04T19:27:57.599607Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# setting catboost parameters\nparams = dict(\n    loss_function=\"MultiRMSE\",\n    eval_metric=MultiTargetQWK(),\n    iterations=1 if IS_TEST else 100000,\n    learning_rate=0.1,\n    depth=5,\n    early_stopping_rounds=50,\n)\n\n# Cross-validation\nskf = StratifiedKFold(n_splits=5, shuffle=True, random_state=52)\nmodels: list[CatBoostRegressor] = []\ny_pred = np.full((X.height, len(TARGET_COLS)), fill_value=np.nan)\nfor train_idx, val_idx in skf.split(X, y_sii):\n    X_train: pl.DataFrame\n    X_val: pl.DataFrame\n    y_train: pl.DataFrame\n    y_val: pl.DataFrame\n    X_train, X_val = X[train_idx], X[val_idx]\n    y_train, y_val = y[train_idx], y[val_idx]\n\n    # train model\n    model = CatBoostRegressor(**params)\n    model.fit(\n        X_train.to_pandas(),\n        y_train.to_pandas(),\n        eval_set=(X_val.to_pandas(), y_val.to_pandas()),\n        cat_features=cat_features,\n        verbose=False,\n    )\n    models.append(model)\n\n    # predict\n    y_pred[val_idx] = model.predict(X_val.to_pandas())\n\nassert np.isnan(y_pred).sum() == 0\n# Optimize thresholds\noptimizer = OptimizedRounder(n_classes=4, n_trials=300)\ny_pred_total = y_pred[:, TARGET_COLS.index(\"PCIAT-PCIAT_Total\")]\noptimizer.fit(y_pred_total, y_sii)\ny_pred_rounded = optimizer.predict(y_pred_total)\n\n# Calculate QWK\nqwk = cohen_kappa_score(y_sii, y_pred_rounded, weights=\"quadratic\")\nprint(f\"Cross-Validated QWK Score: {qwk}\")","metadata":{"execution":{"iopub.status.busy":"2024-11-04T19:27:57.604017Z","iopub.execute_input":"2024-11-04T19:27:57.604483Z","iopub.status.idle":"2024-11-04T19:28:06.945605Z","shell.execute_reply.started":"2024-11-04T19:27:57.604445Z","shell.execute_reply":"2024-11-04T19:28:06.944571Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"feature_importance = np.mean([model.get_feature_importance() for model in models], axis=0)\nsorted_idx = np.argsort(feature_importance)\nsorted_idx = sorted_idx[-30:]\nfig = plt.figure(figsize=(12, 10))\nplt.barh(range(len(sorted_idx)), feature_importance[sorted_idx], align=\"center\")\nplt.yticks(range(len(sorted_idx)), np.array(X_test.columns)[sorted_idx])\nplt.title(\"Feature Importance\")","metadata":{"execution":{"iopub.status.busy":"2024-11-04T19:28:06.947378Z","iopub.execute_input":"2024-11-04T19:28:06.947770Z","iopub.status.idle":"2024-11-04T19:28:07.654222Z","shell.execute_reply.started":"2024-11-04T19:28:06.947725Z","shell.execute_reply":"2024-11-04T19:28:07.652802Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AvgModel:\n    def __init__(self, models: list[BaseEstimator]):\n        self.models = models\n\n    def predict(self, X: ArrayLike) -> NDArray[np.int_]:\n        preds: list[NDArray[np.int_]] = []\n        for model in self.models:\n            pred = model.predict(X)\n            preds.append(pred)\n\n        return np.mean(preds, axis=0)","metadata":{"execution":{"iopub.status.busy":"2024-11-04T19:28:07.656225Z","iopub.execute_input":"2024-11-04T19:28:07.656844Z","iopub.status.idle":"2024-11-04T19:28:07.670436Z","shell.execute_reply.started":"2024-11-04T19:28:07.656793Z","shell.execute_reply":"2024-11-04T19:28:07.668264Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"avg_model = AvgModel(models)\ntest_pred = avg_model.predict(X_test.to_pandas())[:, TARGET_COLS.index(\"PCIAT-PCIAT_Total\")]\ntest_pred_rounded = optimizer.predict(test_pred)\ntest.select(\"id\").with_columns(\n    pl.Series(\"sii\", pl.Series(\"sii\", test_pred_rounded)),\n).write_csv(\"submission.csv\")","metadata":{"execution":{"iopub.status.busy":"2024-11-04T19:28:07.674981Z","iopub.execute_input":"2024-11-04T19:28:07.675397Z","iopub.status.idle":"2024-11-04T19:28:07.735434Z","shell.execute_reply.started":"2024-11-04T19:28:07.675352Z","shell.execute_reply":"2024-11-04T19:28:07.734048Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}