{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":84493,"databundleVersionId":11305158,"sourceType":"competition"},{"sourceId":13939980,"sourceType":"datasetVersion","datasetId":8862728}],"dockerImageVersionId":31192,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install /kaggle/input/janestreet2025-code/janestreet-0.1-py3-none-any.whl --force-reinstall --no-deps","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-01T04:54:22.631744Z","iopub.execute_input":"2025-12-01T04:54:22.631983Z","iopub.status.idle":"2025-12-01T04:54:25.020855Z","shell.execute_reply.started":"2025-12-01T04:54:22.631960Z","shell.execute_reply":"2025-12-01T04:54:25.019948Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import lightgbm as lgb\nimport polars as pl\nimport numpy as np\nimport os\nimport joblib\nimport gc\nimport time \n\nfrom janestreet.data_processor import DataProcessor\nfrom janestreet.config import PATH_MODELS\nfrom janestreet.utils import create_folder","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T04:54:26.114229Z","iopub.execute_input":"2025-12-01T04:54:26.115007Z","iopub.status.idle":"2025-12-01T04:54:31.282246Z","shell.execute_reply.started":"2025-12-01T04:54:26.114971Z","shell.execute_reply":"2025-12-01T04:54:31.281495Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"MODEL_NAME = \"lgbm_cv_v1\"\nTARGET_COL = \"responder_6\"\nN_FOLDS = 3             \nSKIP_DAYS = 677           \n\nLGB_PARAMS = {\n    \"objective\": \"regression_l2\",\n    \"metric\": \"rmse\",\n    \"learning_rate\": 0.05,\n    \"num_leaves\": 62,\n    \"feature_fraction\": 0.8,\n    \"bagging_fraction\": 0.8,\n    \"bagging_freq\": 5,\n    \"lambda_l1\": 1.0,\n    \"lambda_l2\": 1.0,\n    \"verbosity\": -1,\n    \"seed\": 42,\n    \"n_jobs\": -1,\n    'device' : 'gpu',\n    'gpu_use_dp': True,\n}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T04:54:31.283645Z","iopub.execute_input":"2025-12-01T04:54:31.284326Z","iopub.status.idle":"2025-12-01T04:54:31.289209Z","shell.execute_reply.started":"2025-12-01T04:54:31.284303Z","shell.execute_reply":"2025-12-01T04:54:31.288467Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def r2_weighted(y_true, y_pred, weights):\n    if len(y_true) == 0:\n        return np.nan\n        \n    weights = np.array(weights)\n    y_true = np.array(y_true)\n    y_pred = np.array(y_pred)\n\n    ss_res = np.sum(weights * (y_true - y_pred) ** 2)\n    weighted_mean = np.average(y_true, weights=weights)\n    ss_tot = np.sum(weights * (y_true - weighted_mean) ** 2)\n\n    if ss_tot == 0:\n        return np.nan\n        \n    return 1 - ss_res / ss_tot\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T04:54:31.289907Z","iopub.execute_input":"2025-12-01T04:54:31.290158Z","iopub.status.idle":"2025-12-01T04:54:31.304119Z","shell.execute_reply.started":"2025-12-01T04:54:31.290134Z","shell.execute_reply":"2025-12-01T04:54:31.303391Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nprocessor = DataProcessor(\n    name=MODEL_NAME,\n    skip_days=SKIP_DAYS,\n    use_aux_targets=False\n)\n\ndf_all = processor.get_train_valid_data()\nfeatures = processor.features\n\nprint(f\"总行数: {df_all.height}\")\nprint(f\"使用特征数: {len(features)}\")\n\n\nall_dates = sorted(df_all[\"date_id\"].unique().to_list())\nfold_size = len(all_dates) // (N_FOLDS + 1)\n\nscores_r2 = []\nscores_rmse = []\n\nprint(\"\\n开始时间序列 CV...\")\nprint(\"=\" * 60)\n\nfold_Lgbpredictions = []\n\ncv_start_time = time.time()\nfor fold in range(N_FOLDS):\n    fold_start_time = time.time()\n    print(f\"\\nFOLD {fold+1}/{N_FOLDS}\")\n    print(\"-\" * 60)\n\n    valid_start = fold_size * (fold + 1)\n    valid_end = fold_size * (fold + 2)\n\n    valid_dates = set(all_dates[valid_start : valid_end])\n    train_dates = set(all_dates[:valid_start])\n\n    df_train = df_all.filter(pl.col(\"date_id\").is_in(train_dates))\n    df_valid = df_all.filter(pl.col(\"date_id\").is_in(valid_dates))\n\n    df_train = df_train.with_columns([pl.col(c).cast(pl.Float32) for c in features])\n    df_valid = df_valid.with_columns([pl.col(c).cast(pl.Float32) for c in features])\n\n    print(f\"Train rows = {df_train.height}, Valid rows = {df_valid.height}\")\n    data_prep_start = time.time()\n    # 提取矩阵\n    X_train = df_train.select(features).to_numpy()\n    y_train = df_train[TARGET_COL].to_numpy()\n    w_train = df_train[\"weight\"].to_numpy()\n\n    X_valid = df_valid.select(features).to_numpy()\n    y_valid = df_valid[TARGET_COL].to_numpy()\n    w_valid = df_valid[\"weight\"].to_numpy()\n    print(f\"Data prep time: {time.time() - data_prep_start:.2f} sec\")\n    train_set = lgb.Dataset(X_train, y_train, weight=w_train, feature_name=features)\n    valid_set = lgb.Dataset(X_valid, y_valid, weight=w_valid, feature_name=features, reference=train_set)\n    train_start = time.time()\n    # 训练\n    model = lgb.train(\n        params=LGB_PARAMS,\n        train_set=train_set,\n        num_boost_round=2000,\n        valid_sets=[train_set, valid_set],\n        valid_names=[\"train\", \"valid\"],\n        callbacks=[\n            lgb.early_stopping(stopping_rounds=50),\n            lgb.log_evaluation(period=50)\n        ]\n    )\n    print(f\"Training time: {time.time() - train_start:.2f} sec\")\n    # RMSE\n    rmse = model.best_score[\"valid\"][\"rmse\"]\n    scores_rmse.append(rmse)\n\n    # Weighted R²\n    y_pred = model.predict(X_valid)\n    r2 = r2_weighted(y_valid, y_pred, w_valid)\n    scores_r2.append(r2)\n\n    print(f\"Fold {fold+1} RMSE = {rmse:.6f}\")\n    print(f\"Fold {fold+1} R²   = {r2:.6f}\")\n\n    fold_Lgbpredictions.append({\n        \"fold\": fold,\n        \"y_valid\": y_valid.copy(),\n        \"w_valid\": w_valid.copy(),\n        \"lgb_pred\": y_pred.copy(),\n        \"valid_dates\": list(valid_dates),  # optional\n    })\n\n    del df_train, df_valid\n    del X_train, y_train, w_train\n    del X_valid, y_valid, w_valid\n    del train_set, valid_set, model\n    gc.collect()\n    print(f\"Fold {fold+1} total time: {time.time() - fold_start_time:.2f} sec\")\n\nprint(\"\\n\" + \"=\" * 60)\nprint(\"CV 完成！\")\nprint(f\"Total CV time: {time.time() - cv_start_time:.2f} sec\") \nprint(\"RMSE per fold:\", scores_rmse)\nprint(\"   Mean RMSE:\", np.mean(scores_rmse))\nprint(\"    Std RMSE:\", np.std(scores_rmse))\n\nprint(\"\\nR² per fold:\", scores_r2)\nprint(\"   Mean R² :\", np.mean(scores_r2))\nprint(\"    Std R² :\", np.std(scores_r2))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T04:54:31.305527Z","iopub.execute_input":"2025-12-01T04:54:31.305790Z","iopub.status.idle":"2025-12-01T05:11:54.923107Z","shell.execute_reply.started":"2025-12-01T04:54:31.305768Z","shell.execute_reply":"2025-12-01T05:11:54.922416Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"joblib.dump(fold_Lgbpredictions, \"/kaggle/working/lgb_cv_preds.joblib\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-01T05:13:22.717287Z","iopub.execute_input":"2025-12-01T05:13:22.717832Z","iopub.status.idle":"2025-12-01T05:13:23.007045Z","shell.execute_reply.started":"2025-12-01T05:13:22.717805Z","shell.execute_reply":"2025-12-01T05:13:23.006441Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}