{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":104857,"databundleVersionId":12651513,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-14T08:21:12.079530Z","iopub.execute_input":"2025-06-14T08:21:12.079826Z","iopub.status.idle":"2025-06-14T08:21:13.331273Z","shell.execute_reply.started":"2025-06-14T08:21:12.079802Z","shell.execute_reply":"2025-06-14T08:21:13.330619Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\ntrain = pd.read_csv('/kaggle/input/burnout-datathon-ieeecsmuj/train.csv')\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-14T08:21:18.693470Z","iopub.execute_input":"2025-06-14T08:21:18.693892Z","iopub.status.idle":"2025-06-14T08:21:33.936409Z","shell.execute_reply.started":"2025-06-14T08:21:18.693865Z","shell.execute_reply":"2025-06-14T08:21:33.935622Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.info()","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.describe()","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport seaborn as sns\n\n# Plot histogram of Lap_Time_Seconds (target)\nplt.figure(figsize=(8,5))\nsns.histplot(train['Lap_Time_Seconds'], kde=True)\nplt.title('Distribution of Lap Time')\nplt.show()\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.isnull().sum().sort_values(ascending=False)\n\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train['Penalty'].fillna('No Penalty', inplace=True)\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\n\ncategorical_cols = [\n    'category_x', 'Track_Condition', 'Tire_Compound_Front', 'Tire_Compound_Rear', \n    'Penalty', 'Session', 'shortname', 'circuit_name', 'rider_name', \n    'team_name', 'bike_name', 'weather', 'track'\n]\n\nle = LabelEncoder()\n\nfor col in categorical_cols:\n    train[col] = le.fit_transform(train[col].astype(str))\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Take just 100k rows to test\ntrain_small = train.sample(100000, random_state=42)\n\n# Prepare features and target again\nX_small = train_small.drop(['Lap_Time_Seconds', 'Unique ID'], axis=1)\ny_small = train_small['Lap_Time_Seconds']\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.metrics import mean_squared_error\nimport numpy as np\n\n# Split\nX_train, X_valid, y_train, y_valid = train_test_split(X_small, y_small, test_size=0.2, random_state=42)\n\n# Model (lower estimators for faster training)\nmodel = RandomForestRegressor(n_estimators=50, random_state=42, n_jobs=-1)\nmodel.fit(X_train, y_train)\n\n# Predict\ny_pred = model.predict(X_valid)\n\n# RMSE\nrmse = np.sqrt(mean_squared_error(y_valid, y_pred))\nprint(f'Validation RMSE: {rmse}')\n","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pip install lightgbm\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-14T08:20:27.809976Z","iopub.execute_input":"2025-06-14T08:20:27.810857Z","iopub.status.idle":"2025-06-14T08:20:32.600451Z","shell.execute_reply.started":"2025-06-14T08:20:27.810826Z","shell.execute_reply":"2025-06-14T08:20:32.599386Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport lightgbm as lgb\nfrom lightgbm import early_stopping\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import mean_squared_error\n\n# Load data\ntrain = pd.read_csv('/kaggle/input/burnout-datathon-ieeecsmuj/train.csv')\nval = pd.read_csv('/kaggle/input/burnout-datathon-ieeecsmuj/val.csv')\n\n# Subsample train data to 100k rows\ntrain_small = train.sample(100000, random_state=42)\n\n# Handle missing Penalty column\ntrain_small['Penalty'] = train_small['Penalty'].fillna('NoPenalty')\nval['Penalty'] = val['Penalty'].fillna('NoPenalty')\n\n# Convert all object columns to category (this is KEY fix)\nfor col in train_small.columns:\n    if train_small[col].dtype == 'object':\n        train_small[col] = train_small[col].astype('category')\n        val[col] = val[col].astype('category')\n\n# Separate features & target\ny_train = train_small['Lap_Time_Seconds']\nX_train = train_small.drop(['Lap_Time_Seconds', 'Unique ID'], axis=1)\n\ny_val = val['Lap_Time_Seconds']\nX_val = val.drop(['Lap_Time_Seconds', 'Unique ID'], axis=1)\n\n# Detect categorical columns automatically\ncat_cols = X_train.select_dtypes(include='category').columns.tolist()\n\n# Create LightGBM datasets\nlgb_train = lgb.Dataset(X_train, label=y_train, categorical_feature=cat_cols)\nlgb_val = lgb.Dataset(X_val, label=y_val, categorical_feature=cat_cols, reference=lgb_train)\n\n# LightGBM parameters\nparams = {\n    'objective': 'regression',\n    'metric': 'rmse',\n    'learning_rate': 0.1,\n    'num_leaves': 31,\n    'verbose': -1\n}\n\n# Train model with early stopping (LightGBM 4.x compatible)\nmodel = lgb.train(\n    params,\n    lgb_train,\n    valid_sets=[lgb_val],\n    callbacks=[early_stopping(stopping_rounds=20)]\n)\n\n# Predict & evaluate\ny_pred = model.predict(X_val)\nrmse = np.sqrt(mean_squared_error(y_val, y_pred))\nprint(f'Validation RMSE: {rmse}')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-14T08:26:36.818951Z","iopub.execute_input":"2025-06-14T08:26:36.819299Z","iopub.status.idle":"2025-06-14T08:26:56.015519Z","shell.execute_reply.started":"2025-06-14T08:26:36.819274Z","shell.execute_reply":"2025-06-14T08:26:56.014751Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-14T08:31:37.148671Z","iopub.execute_input":"2025-06-14T08:31:37.148997Z","iopub.status.idle":"2025-06-14T08:31:37.178157Z","shell.execute_reply.started":"2025-06-14T08:31:37.148956Z","shell.execute_reply":"2025-06-14T08:31:37.177191Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport lightgbm as lgb\nfrom lightgbm import early_stopping\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.metrics import mean_squared_error\nimport matplotlib.pyplot as plt\n\n# Load data\ntrain = pd.read_csv('/kaggle/input/burnout-datathon-ieeecsmuj/train.csv')\nval = pd.read_csv('/kaggle/input/burnout-datathon-ieeecsmuj/val.csv')\n\n# Sample 100k rows for faster experimentation\ntrain_small = train.sample(100000, random_state=42)\n\n# Fill missing penalties\ntrain_small['Penalty'] = train_small['Penalty'].fillna('NoPenalty')\nval['Penalty'] = val['Penalty'].fillna('NoPenalty')\n\n# Drop useless ID-like columns\ndrop_cols = [\n    'Unique ID', 'Rider_ID', 'rider', 'team', 'bike',\n    'shortname', 'circuit_name', 'rider_name',\n    'team_name', 'bike_name', 'Session', 'category_x',\n    'min_year', 'max_year', 'years_active',\n    'starts', 'finishes', 'with_points', 'podiums', 'wins', \n    'Championship_Points', 'Championship_Position', 'Penalty',\n    'sequence', 'track', 'weather'\n]\ntrain_small = train_small.drop(columns=drop_cols)\nval = val.drop(columns=drop_cols)\n\n# Feature Engineering (filtered stronger features only)\nfor df in [train_small, val]:\n    df['Temp_Diff'] = df['Track_Temperature_Celsius'] - df['Ambient_Temperature_Celsius']\n    df['Pit_Per_Lap'] = df['Pit_Stop_Duration_Seconds'] / (df['Laps'] + 1)  # avoid division by zero\n    df['Deg_x_Laps'] = df['Tire_Degradation_Factor_per_Lap'] * df['Laps']\n    df['Pit_x_Deg'] = df['Pit_Stop_Duration_Seconds'] * df['Tire_Degradation_Factor_per_Lap']\n    df['Temp_x_Deg'] = df['Temp_Diff'] * df['Tire_Degradation_Factor_per_Lap']\n\n# Separate target\ny_train = train_small['Lap_Time_Seconds']\nX_train = train_small.drop(['Lap_Time_Seconds'], axis=1)\n\ny_val = val['Lap_Time_Seconds']\nX_val = val.drop(['Lap_Time_Seconds'], axis=1)\n\n### RANDOM FOREST — FINAL TUNING ###\n\nX_train_rf = pd.get_dummies(X_train)\nX_val_rf = pd.get_dummies(X_val)\nX_train_rf, X_val_rf = X_train_rf.align(X_val_rf, join='left', axis=1, fill_value=0)\n\nrf = RandomForestRegressor(\n    n_estimators=700, \n    max_depth=28, \n    min_samples_split=4, \n    min_samples_leaf=3,\n    random_state=42, \n    n_jobs=-1\n)\nrf.fit(X_train_rf, y_train)\nrf_preds = rf.predict(X_val_rf)\nrf_rmse = np.sqrt(mean_squared_error(y_val, rf_preds))\nprint(f'Random Forest Validation RMSE: {rf_rmse}')\n\n# Feature Importance Random Forest\nimportances = rf.feature_importances_\nfeat_imp = pd.Series(importances, index=X_train_rf.columns).sort_values(ascending=False)\nprint(\"\\nTop 15 important features (Random Forest):\")\nprint(feat_imp.head(15))\n\n### LIGHTGBM FINAL TUNING ###\n\n# Handle categorical features\nfor col in X_train.columns:\n    if X_train[col].dtype == 'object':\n        X_train[col] = X_train[col].astype('category')\n        X_val[col] = X_val[col].astype('category')\n\ncat_cols = X_train.select_dtypes(include='category').columns.tolist()\n\nlgb_train = lgb.Dataset(X_train, label=y_train, categorical_feature=cat_cols)\nlgb_val = lgb.Dataset(X_val, label=y_val, categorical_feature=cat_cols, reference=lgb_train)\n\nparams = {\n    'objective': 'regression',\n    'metric': 'rmse',\n    'learning_rate': 0.015,\n    'num_leaves': 120,\n    'min_data_in_leaf': 30,\n    'feature_fraction': 0.85,\n    'bagging_fraction': 0.85,\n    'bagging_freq': 5,\n    'lambda_l1': 1.0,\n    'lambda_l2': 1.0,\n    'verbose': -1\n}\n\nmodel = lgb.train(\n    params,\n    lgb_train,\n    valid_sets=[lgb_val],\n    num_boost_round=7000,\n    callbacks=[early_stopping(stopping_rounds=100)]\n)\n\nlgb_preds = model.predict(X_val)\nlgb_rmse = np.sqrt(mean_squared_error(y_val, lgb_preds))\nprint(f'LightGBM Validation RMSE: {lgb_rmse}')\n\n# LightGBM Feature Importance\nlgb.plot_importance(model, max_num_features=15, importance_type='gain')\nplt.show()\n\n### BLENDING PREDICTIONS ###\n\n# Simple weighted average blending (currently 50-50, you can adjust)\nblend_preds = 0.5 * rf_preds + 0.5 * lgb_preds\nblend_rmse = np.sqrt(mean_squared_error(y_val, blend_preds))\nprint(f'Blended Model Validation RMSE: {blend_rmse}')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-14T11:27:10.318950Z","iopub.execute_input":"2025-06-14T11:27:10.319319Z","iopub.status.idle":"2025-06-14T11:39:41.995754Z","shell.execute_reply.started":"2025-06-14T11:27:10.319292Z","shell.execute_reply":"2025-06-14T11:39:41.994799Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-14T08:40:09.738863Z","iopub.execute_input":"2025-06-14T08:40:09.739296Z","iopub.status.idle":"2025-06-14T08:40:09.758843Z","shell.execute_reply.started":"2025-06-14T08:40:09.739264Z","shell.execute_reply":"2025-06-14T08:40:09.758028Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport lightgbm as lgb\nfrom lightgbm import early_stopping\nfrom sklearn.metrics import mean_squared_error\nimport matplotlib.pyplot as plt\n\n# Load data\ntrain = pd.read_csv('/kaggle/input/burnout-datathon-ieeecsmuj/train.csv')\nval = pd.read_csv('/kaggle/input/burnout-datathon-ieeecsmuj/val.csv')\ntest = pd.read_csv('/kaggle/input/burnout-datathon-ieeecsmuj/test.csv')\n\n# Use small sample (speed)\ntrain_small = train.sample(100000, random_state=42)\n\n# Fill missing penalties\nfor df in [train_small, val, test]:\n    df['Penalty'] = df['Penalty'].fillna('NoPenalty')\n\n# Drop useless ID-like columns\ndrop_cols = [\n    'Rider_ID', 'rider', 'team', 'bike',\n    'shortname', 'circuit_name', 'rider_name',\n    'team_name', 'bike_name', 'Session', 'category_x',\n    'min_year', 'max_year', 'years_active',\n    'starts', 'finishes', 'with_points', 'podiums', 'wins', \n    'Championship_Points', 'Championship_Position', 'Penalty',\n    'sequence', 'track', 'weather'\n]\n\ntrain_small = train_small.drop(columns=drop_cols + ['Unique ID'])\nval = val.drop(columns=drop_cols + ['Unique ID'])\ntest_features = test.drop(columns=drop_cols)\n\n# Feature Engineering (more powerful now)\nfor df in [train_small, val, test_features]:\n    df['Temp_Diff'] = df['Track_Temperature_Celsius'] - df['Ambient_Temperature_Celsius']\n    df['Pit_Per_Lap'] = df['Pit_Stop_Duration_Seconds'] / (df['Laps'] + 1)\n    df['Deg_x_Laps'] = df['Tire_Degradation_Factor_per_Lap'] * df['Laps']\n    df['Pit_x_Deg'] = df['Pit_Stop_Duration_Seconds'] * df['Tire_Degradation_Factor_per_Lap']\n    df['Temp_x_Deg'] = df['Temp_Diff'] * df['Tire_Degradation_Factor_per_Lap']\n    df['Laps_x_Temp'] = df['Laps'] * df['Track_Temperature_Celsius']\n    df['Pit_Deg_Temp'] = df['Pit_Per_Lap'] * df['Temp_Diff'] * df['Tire_Degradation_Factor_per_Lap']\n    # Additional features\n    df['Temp_Ratio'] = df['Track_Temperature_Celsius'] / (df['Ambient_Temperature_Celsius'] + 1)\n    df['PitSquared'] = df['Pit_Stop_Duration_Seconds'] ** 2\n    df['DegSquared'] = df['Tire_Degradation_Factor_per_Lap'] ** 2\n    df['LapsSquared'] = df['Laps'] ** 2\n\n# Log-transform target\ny_train = np.log1p(train_small['Lap_Time_Seconds'])\nX_train = train_small.drop(['Lap_Time_Seconds'], axis=1)\ny_val = np.log1p(val['Lap_Time_Seconds'])\nX_val = val.drop(['Lap_Time_Seconds'], axis=1)\n\n# Categorical handling for LightGBM\nfor col in X_train.columns:\n    if X_train[col].dtype == 'object':\n        X_train[col] = X_train[col].astype('category')\n        X_val[col] = X_val[col].astype('category')\n        test_features[col] = test_features[col].astype('category')\n\ncat_cols = X_train.select_dtypes(include='category').columns.tolist()\n\n# LightGBM Dataset\nlgb_train = lgb.Dataset(X_train, label=y_train, categorical_feature=cat_cols)\nlgb_val = lgb.Dataset(X_val, label=y_val, categorical_feature=cat_cols, reference=lgb_train)\n\n# Hyperparameters (maxed for small dataset)\nparams = {\n    'objective': 'regression',\n    'metric': 'rmse',\n    'learning_rate': 0.005,\n    'num_leaves': 300,\n    'min_data_in_leaf': 10,\n    'feature_fraction': 0.95,\n    'bagging_fraction': 0.9,\n    'bagging_freq': 3,\n    'lambda_l1': 5.0,\n    'lambda_l2': 5.0,\n    'max_bin': 1023,\n    'verbose': -1\n}\n\nmodel = lgb.train(\n    params,\n    lgb_train,\n    valid_sets=[lgb_val],\n    num_boost_round=20000,\n    callbacks=[early_stopping(stopping_rounds=400)]\n)\n\n# Evaluate (inverse log transform)\nlgb_preds = model.predict(X_val, num_iteration=model.best_iteration)\nlgb_preds_actual = np.expm1(lgb_preds)\ny_val_actual = np.expm1(y_val)\nlgb_rmse = np.sqrt(mean_squared_error(y_val_actual, lgb_preds_actual))\nprint(f'LightGBM Validation RMSE: {lgb_rmse:.4f}')\n\n# Feature Importance\nlgb.plot_importance(model, max_num_features=20, importance_type='gain')\nplt.show()\n\n# Predict on test set\ntest_preds = model.predict(test_features.drop(columns=['Unique ID']), num_iteration=model.best_iteration)\ntest_preds_actual = np.expm1(test_preds)\n\n# Prepare submission\nsubmission = pd.DataFrame({\n    'Unique ID': test['Unique ID'],\n    \n    'Lap_Time_Seconds': test_preds_actual\n})\nsubmission.to_csv('submission_v3.csv', index=False)\nprint(\"Submission file created successfully!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-14T15:43:26.209630Z","iopub.execute_input":"2025-06-14T15:43:26.210175Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}