From fb3173e4ab53fcba12a61bcc4613eaf8f51cbcd9 Mon Sep 17 00:00:00 2001 From: Keshav Anand Date: Wed, 22 Jul 2026 22:27:36 -0400 Subject: [PATCH] training xgb model not fully accurate --- .gitignore | 3 +- ....ipynb => baseline_combinational_xgb.ipynb | 601 +++++++++++++++++- 2 files changed, 600 insertions(+), 4 deletions(-) rename main.ipynb => baseline_combinational_xgb.ipynb (97%) diff --git a/.gitignore b/.gitignore index d817a67..8563eec 100644 --- a/.gitignore +++ b/.gitignore @@ -82,4 +82,5 @@ Desktop.ini *.bak *.swp -data/* \ No newline at end of file +data/* +models/* \ No newline at end of file diff --git a/main.ipynb b/baseline_combinational_xgb.ipynb similarity index 97% rename from main.ipynb rename to baseline_combinational_xgb.ipynb index 6cb1319..0c47cdd 100644 --- a/main.ipynb +++ b/baseline_combinational_xgb.ipynb @@ -5694,7 +5694,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "id": "99be3b8b", "metadata": {}, "outputs": [ @@ -11068,7 +11068,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "id": "b58e7aed", "metadata": {}, "outputs": [ @@ -11281,7 +11281,7 @@ "[5 rows x 26 columns]" ] }, - "execution_count": 5, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -11454,6 +11454,601 @@ "\n", "df.head()" ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "be2469ce", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Training rows: 466379\n", + "Testing rows : 116374\n", + "[0]\tvalidation_0-mae:32.71855\tvalidation_1-mae:32.46407\n", + "[100]\tvalidation_0-mae:17.67243\tvalidation_1-mae:17.56379\n", + "[200]\tvalidation_0-mae:15.99231\tvalidation_1-mae:16.02378\n", + "[300]\tvalidation_0-mae:15.81573\tvalidation_1-mae:15.89000\n", + "[400]\tvalidation_0-mae:15.76997\tvalidation_1-mae:15.86225\n", + "[500]\tvalidation_0-mae:15.74462\tvalidation_1-mae:15.84885\n", + "[600]\tvalidation_0-mae:15.72323\tvalidation_1-mae:15.83748\n", + "[700]\tvalidation_0-mae:15.70448\tvalidation_1-mae:15.82844\n", + "[800]\tvalidation_0-mae:15.68914\tvalidation_1-mae:15.82248\n", + "[900]\tvalidation_0-mae:15.67203\tvalidation_1-mae:15.81510\n", + "[1000]\tvalidation_0-mae:15.65865\tvalidation_1-mae:15.80998\n", + "[1100]\tvalidation_0-mae:15.64647\tvalidation_1-mae:15.80701\n", + "[1200]\tvalidation_0-mae:15.63444\tvalidation_1-mae:15.80456\n", + "[1300]\tvalidation_0-mae:15.62326\tvalidation_1-mae:15.80293\n", + "[1400]\tvalidation_0-mae:15.61287\tvalidation_1-mae:15.80151\n", + "[1500]\tvalidation_0-mae:15.60263\tvalidation_1-mae:15.80194\n", + "[1600]\tvalidation_0-mae:15.59322\tvalidation_1-mae:15.80148\n", + "[1700]\tvalidation_0-mae:15.58498\tvalidation_1-mae:15.80152\n", + "[1800]\tvalidation_0-mae:15.57652\tvalidation_1-mae:15.80163\n", + "[1900]\tvalidation_0-mae:15.56848\tvalidation_1-mae:15.80177\n", + "[1999]\tvalidation_0-mae:15.56159\tvalidation_1-mae:15.80210\n", + "\n", + "========================\n", + "Results\n", + "========================\n", + "MAE : 15.802 runs\n", + "RMSE : 22.194 runs\n", + "R² : 0.7054\n", + "\n", + "Feature importance:\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
featureimportance
10run_rate_factor0.477130
8run_rate0.272351
9projected_score0.162744
0delivery_number0.017518
18score_wicket_combo0.013470
19pressure_index0.010688
15middle_overs0.010050
20score_squared0.008396
1legal_ball0.004335
2score0.004045
3wickets0.003218
11wickets_remaining0.002742
13batting_strength_remaining0.002630
7overs_remaining0.002173
4innings_progress0.002061
5balls_remaining0.001827
12wicket_fraction0.001551
17score_per_ball_remaining0.001476
22score_progress_interaction0.001058
6overs_completed0.000537
14powerplay0.000000
16death_overs0.000000
21progress_squared0.000000
\n", + "
" + ], + "text/plain": [ + " feature importance\n", + "10 run_rate_factor 0.477130\n", + "8 run_rate 0.272351\n", + "9 projected_score 0.162744\n", + "0 delivery_number 0.017518\n", + "18 score_wicket_combo 0.013470\n", + "19 pressure_index 0.010688\n", + "15 middle_overs 0.010050\n", + "20 score_squared 0.008396\n", + "1 legal_ball 0.004335\n", + "2 score 0.004045\n", + "3 wickets 0.003218\n", + "11 wickets_remaining 0.002742\n", + "13 batting_strength_remaining 0.002630\n", + "7 overs_remaining 0.002173\n", + "4 innings_progress 0.002061\n", + "5 balls_remaining 0.001827\n", + "12 wicket_fraction 0.001551\n", + "17 score_per_ball_remaining 0.001476\n", + "22 score_progress_interaction 0.001058\n", + "6 overs_completed 0.000537\n", + "14 powerplay 0.000000\n", + "16 death_overs 0.000000\n", + "21 progress_squared 0.000000" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Saved model\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "from sklearn.model_selection import GroupShuffleSplit\n", + "from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score\n", + "\n", + "from xgboost import XGBRegressor\n", + "\n", + "import joblib\n", + "\n", + "\n", + "\n", + "# =====================================\n", + "# Prepare data\n", + "# =====================================\n", + "\n", + "data = df.copy()\n", + "\n", + "\n", + "# Remove identifiers / leakage\n", + "\n", + "drop_cols = [\n", + " \"target_score\",\n", + " \"match_id\",\n", + " \"over_ball\"\n", + "]\n", + "\n", + "\n", + "X = data.drop(\n", + " columns=drop_cols\n", + ")\n", + "\n", + "\n", + "y = data[\"target_score\"]\n", + "\n", + "\n", + "groups = data[\"match_id\"]\n", + "\n", + "\n", + "\n", + "# =====================================\n", + "# Match-based split\n", + "# =====================================\n", + "\n", + "splitter = GroupShuffleSplit(\n", + " n_splits=1,\n", + " test_size=0.2,\n", + " random_state=42\n", + ")\n", + "\n", + "\n", + "train_idx, test_idx = next(\n", + " splitter.split(\n", + " X,\n", + " y,\n", + " groups\n", + " )\n", + ")\n", + "\n", + "\n", + "X_train = X.iloc[train_idx]\n", + "X_test = X.iloc[test_idx]\n", + "\n", + "\n", + "y_train = y.iloc[train_idx]\n", + "y_test = y.iloc[test_idx]\n", + "\n", + "\n", + "\n", + "print(\"Training rows:\", len(X_train))\n", + "print(\"Testing rows :\", len(X_test))\n", + "\n", + "\n", + "\n", + "# =====================================\n", + "# XGBoost model\n", + "# =====================================\n", + "\n", + "model = XGBRegressor(\n", + "\n", + " # trees\n", + " n_estimators=2000,\n", + "\n", + " # learning\n", + " learning_rate=0.015,\n", + "\n", + " # tree complexity\n", + " max_depth=6,\n", + " min_child_weight=5,\n", + "\n", + " # randomness\n", + " subsample=0.85,\n", + " colsample_bytree=0.85,\n", + "\n", + " # regularization\n", + " reg_alpha=0.1,\n", + " reg_lambda=2,\n", + "\n", + " objective=\"reg:squarederror\",\n", + "\n", + " eval_metric=\"mae\",\n", + "\n", + " random_state=42,\n", + "\n", + " n_jobs=-1\n", + ")\n", + "\n", + "\n", + "\n", + "# =====================================\n", + "# Train\n", + "# =====================================\n", + "\n", + "model.fit(\n", + " X_train,\n", + " y_train,\n", + "\n", + " eval_set=[\n", + " (X_train, y_train),\n", + " (X_test, y_test)\n", + " ],\n", + "\n", + " verbose=100\n", + ")\n", + "\n", + "\n", + "\n", + "# =====================================\n", + "# Evaluate\n", + "# =====================================\n", + "\n", + "pred = model.predict(X_test)\n", + "\n", + "\n", + "mae = mean_absolute_error(\n", + " y_test,\n", + " pred\n", + ")\n", + "\n", + "\n", + "rmse = np.sqrt(\n", + " mean_squared_error(\n", + " y_test,\n", + " pred\n", + " )\n", + ")\n", + "\n", + "\n", + "r2 = r2_score(\n", + " y_test,\n", + " pred\n", + ")\n", + "\n", + "\n", + "print(\"\\n========================\")\n", + "print(\"Results\")\n", + "print(\"========================\")\n", + "\n", + "print(f\"MAE : {mae:.3f} runs\")\n", + "print(f\"RMSE : {rmse:.3f} runs\")\n", + "print(f\"R² : {r2:.4f}\")\n", + "\n", + "\n", + "\n", + "# =====================================\n", + "# Feature importance\n", + "# =====================================\n", + "\n", + "importance = pd.DataFrame(\n", + " {\n", + " \"feature\": X.columns,\n", + " \"importance\": model.feature_importances_\n", + " }\n", + ")\n", + "\n", + "\n", + "importance = importance.sort_values(\n", + " \"importance\",\n", + " ascending=False\n", + ")\n", + "\n", + "\n", + "print(\"\\nFeature importance:\")\n", + "display(importance)\n", + "\n", + "\n", + "\n", + "# =====================================\n", + "# Save model\n", + "# =====================================\n", + "\n", + "joblib.dump(\n", + " model,\n", + " \"models/xgb_run_predictor.pkl\"\n", + ")\n", + "\n", + "print(\"\\nSaved model\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "acfb9aa7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "======================\n", + "DLS BASELINE RESULTS\n", + "======================\n", + "Rows evaluated : 116374\n", + "MAE : 23.02 runs\n", + "RMSE : 38.91 runs\n", + "R² : 0.0947\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score\n", + "\n", + "\n", + "# ==========================================\n", + "# Create DLS-style resource table from train\n", + "# ==========================================\n", + "\n", + "dls_train = X_train.copy()\n", + "dls_train[\"target_score\"] = y_train.values\n", + "\n", + "dls_train[\"resource_used\"] = (\n", + " dls_train[\"score\"] /\n", + " dls_train[\"target_score\"]\n", + ")\n", + "\n", + "# Remove weird cases\n", + "dls_train[\"resource_used\"] = (\n", + " dls_train[\"resource_used\"]\n", + " .replace([np.inf, -np.inf], np.nan)\n", + ")\n", + "\n", + "dls_train = dls_train.dropna(\n", + " subset=[\"resource_used\"]\n", + ")\n", + "\n", + "dls_train[\"resource_used\"] = (\n", + " dls_train[\"resource_used\"]\n", + " .clip(0.01, 1.0)\n", + ")\n", + "\n", + "\n", + "# Average resource remaining at each state\n", + "resource_table = (\n", + " dls_train\n", + " .groupby(\n", + " [\n", + " \"legal_ball\",\n", + " \"wickets\"\n", + " ]\n", + " )[\"resource_used\"]\n", + " .mean()\n", + ")\n", + "\n", + "\n", + "# ==========================================\n", + "# DLS prediction function\n", + "# ==========================================\n", + "\n", + "def dls_predict(row):\n", + "\n", + " key = (\n", + " row[\"legal_ball\"],\n", + " row[\"wickets\"]\n", + " )\n", + "\n", + " # exact state\n", + " if key in resource_table.index:\n", + " resource = resource_table[key]\n", + "\n", + " else:\n", + " # nearest legal ball fallback\n", + " subset = resource_table.reset_index()\n", + "\n", + " subset = subset[\n", + " subset[\"wickets\"] == row[\"wickets\"]\n", + " ]\n", + "\n", + " if len(subset) == 0:\n", + " return np.nan\n", + "\n", + " idx = (\n", + " abs(\n", + " subset[\"legal_ball\"]\n", + " - row[\"legal_ball\"]\n", + " )\n", + " .idxmin()\n", + " )\n", + "\n", + " resource = subset.loc[\n", + " idx,\n", + " \"resource_used\"\n", + " ]\n", + "\n", + "\n", + " return row[\"score\"] / resource\n", + "\n", + "\n", + "\n", + "# ==========================================\n", + "# Predict test set\n", + "# ==========================================\n", + "\n", + "dls_predictions = X_test.apply(\n", + " dls_predict,\n", + " axis=1\n", + ")\n", + "\n", + "\n", + "# Remove failures\n", + "mask = ~dls_predictions.isna()\n", + "\n", + "dls_predictions = dls_predictions[mask]\n", + "dls_actual = y_test[mask]\n", + "\n", + "\n", + "# ==========================================\n", + "# Metrics\n", + "# ==========================================\n", + "\n", + "mae = mean_absolute_error(\n", + " dls_actual,\n", + " dls_predictions\n", + ")\n", + "\n", + "rmse = np.sqrt(\n", + " mean_squared_error(\n", + " dls_actual,\n", + " dls_predictions\n", + " )\n", + ")\n", + "\n", + "r2 = r2_score(\n", + " dls_actual,\n", + " dls_predictions\n", + ")\n", + "\n", + "\n", + "print(\"======================\")\n", + "print(\"DLS BASELINE RESULTS\")\n", + "print(\"======================\")\n", + "print(f\"Rows evaluated : {len(dls_actual)}\")\n", + "print(f\"MAE : {mae:.2f} runs\")\n", + "print(f\"RMSE : {rmse:.2f} runs\")\n", + "print(f\"R² : {r2:.4f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5853752b", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": {