{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceType":"competition","sourceId":119083,"databundleVersionId":15997195,"isSourceIdPinned":false}],"dockerImageVersionId":31286,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install -qU polars[gpu] --extra-index-url=https://pypi.nvidia.com","metadata":{"execution":{"iopub.status.busy":"2026-03-13T20:54:49.240536Z","iopub.execute_input":"2026-03-13T20:54:49.240825Z","iopub.status.idle":"2026-03-13T20:54:54.042636Z","shell.execute_reply.started":"2026-03-13T20:54:49.240799Z","shell.execute_reply":"2026-03-13T20:54:54.041761Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Import Libraries\n","metadata":{}},{"cell_type":"code","source":"import gc\nimport re\n\nimport polars as pl\nimport xgboost as xgb\nimport numpy as np\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import fbeta_score\n\nTRAIN_PATH = \"/kaggle/input/competitions/cyber-physical-anomaly-detection-for-der-systems/train.csv\"\nTEST_PATH = \"/kaggle/input/competitions/cyber-physical-anomaly-detection-for-der-systems/test.csv\"","metadata":{"execution":{"iopub.status.busy":"2026-03-13T20:54:54.044213Z","iopub.execute_input":"2026-03-13T20:54:54.044557Z","iopub.status.idle":"2026-03-13T20:54:55.244461Z","shell.execute_reply.started":"2026-03-13T20:54:54.044519Z","shell.execute_reply":"2026-03-13T20:54:55.243901Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Pre-processing\n","metadata":{}},{"cell_type":"code","source":"# cast types to save memory\nlazy_query = pl.scan_csv(TRAIN_PATH).with_columns(\n    pl.col(pl.Float64).cast(pl.Float32),\n    pl.col(pl.Int64).cast(pl.Int32),\n    pl.col(pl.String).cast(pl.Categorical),\n)\ntrain_df = lazy_query.collect(engine=\"gpu\")\n\n# drop 100% empty columns\nnull_counts = train_df.null_count()\nempty_cols = [\n    col for col in null_counts.columns if null_counts[col][0] == train_df.height\n]\ntrain_df = train_df.drop(empty_cols)\n\n# sanitize column names\nsafe_columns = {col: re.sub(r\"[\\[\\]<]\", \"_\", col) for col in train_df.columns}\ntrain_df = train_df.rename(safe_columns)\n\nif \"Id\" in train_df.columns:\n    train_df = train_df.drop(\"Id\")\n\nX = train_df.drop(\"Label\")\ny = train_df.select(\"Label\").to_numpy().ravel()\n\nX_train, X_val, y_train, y_val = train_test_split(\n    X, y, test_size=0.2, random_state=42, stratify=y\n)","metadata":{"execution":{"iopub.status.busy":"2026-03-13T20:54:55.245210Z","iopub.execute_input":"2026-03-13T20:54:55.245554Z","iopub.status.idle":"2026-03-13T20:57:02.714438Z","shell.execute_reply.started":"2026-03-13T20:54:55.245531Z","shell.execute_reply":"2026-03-13T20:57:02.713808Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## XGBoost Training\n","metadata":{}},{"cell_type":"code","source":"dtrain = xgb.DMatrix(X_train, label=y_train, enable_categorical=True)\ndval = xgb.DMatrix(X_val, label=y_val, enable_categorical=True)\n\nparams = {\n    \"objective\": \"binary:logistic\",\n    \"eval_metric\": \"logloss\",\n    \"tree_method\": \"hist\",\n    \"device\": \"cuda\",\n    \"learning_rate\": 0.05,\n    \"max_depth\": 6,\n    \"random_state\": 42,\n}\n\nevals = [(dtrain, \"train\"), (dval, \"eval\")]\nmodel = xgb.train(\n    params,\n    dtrain,\n    num_boost_round=500,\n    evals=evals,\n    early_stopping_rounds=50,\n    verbose_eval=100,\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-13T20:57:02.716000Z","iopub.execute_input":"2026-03-13T20:57:02.716236Z","iopub.status.idle":"2026-03-13T20:59:27.757404Z","shell.execute_reply.started":"2026-03-13T20:57:02.716213Z","shell.execute_reply":"2026-03-13T20:59:27.756857Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Threshold Optimization\n","metadata":{}},{"cell_type":"code","source":"val_preds = model.predict(dval)\nbest_threshold, best_f2 = 0.5, 0.0\nthresholds = np.arange(0.1, 0.9, 0.01)\n\nfor thresh in thresholds:\n    binary_preds = (val_preds >= thresh).astype(int)\n    f2 = fbeta_score(y_val, binary_preds, beta=2)\n    if f2 > best_f2:\n        best_f2 = f2\n        best_threshold = thresh\n\nprint(f\"Optimal Threshold: {best_threshold:.2f} | F2 Score: {best_f2:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-13T20:59:27.758066Z","iopub.execute_input":"2026-03-13T20:59:27.758266Z","iopub.status.idle":"2026-03-13T20:59:31.771376Z","shell.execute_reply.started":"2026-03-13T20:59:27.758246Z","shell.execute_reply":"2026-03-13T20:59:31.770698Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Submission Hack\n","metadata":{}},{"cell_type":"code","source":"# Delete variables that are no longer needed\ndel train_df, X, y, X_train, X_val, y_train, y_val, dtrain, dval\ngc.collect()\nprint(\"Memory cleared!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-13T20:59:31.772251Z","iopub.execute_input":"2026-03-13T20:59:31.772604Z","iopub.status.idle":"2026-03-13T20:59:32.121084Z","shell.execute_reply.started":"2026-03-13T20:59:31.772575Z","shell.execute_reply":"2026-03-13T20:59:32.120283Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"lazy_test = pl.scan_csv(TEST_PATH).with_columns(\n    pl.col(pl.Float64).cast(pl.Float32),\n    pl.col(pl.Int64).cast(pl.Int32),\n    pl.col(pl.String).cast(pl.Categorical),\n)\ntest_df = lazy_test.collect(engine=\"gpu\")\n\ntest_df = test_df.drop(empty_cols)\nsafe_columns_test = {col: re.sub(r\"[\\[\\]<]\", \"_\", col) for col in test_df.columns}\ntest_df = test_df.rename(safe_columns_test)\n\nsubmission_ids = test_df[\"Id\"]\nX_test = test_df.drop(\"Id\")\n\ndtest = xgb.DMatrix(X_test, enable_categorical=True)\ntest_preds = model.predict(dtest)\n\noptimized_labels = (test_preds >= best_threshold).astype(int)\n\nsubmission_df = pl.DataFrame({\"Id\": submission_ids, \"Label\": optimized_labels})\nsubmission_df.write_csv(\"submission.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-13T20:59:32.122045Z","iopub.execute_input":"2026-03-13T20:59:32.122434Z","iopub.status.idle":"2026-03-13T21:00:47.624691Z","shell.execute_reply.started":"2026-03-13T20:59:32.122408Z","shell.execute_reply":"2026-03-13T21:00:47.623833Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-13T21:03:09.143477Z","iopub.execute_input":"2026-03-13T21:03:09.144117Z","iopub.status.idle":"2026-03-13T21:03:09.161213Z","shell.execute_reply.started":"2026-03-13T21:03:09.144088Z","shell.execute_reply":"2026-03-13T21:03:09.160526Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}