{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"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"},{"sourceId":12166272,"sourceType":"datasetVersion","datasetId":7662580}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom sklearn.ensemble import RandomForestRegressor # Our machine learning model\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nprint(\"Listing files in Kaggle input directory:\")\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\"\n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session\n\nprint(\"\\n--- Starting MotoGP Data Analytics Solution Generation ---\")\n\n# --- 1. Load Datasets ---\n# Okay, this is where we tell Python where to find our actual data files on Kaggle.\n# Based on common Kaggle setups and your previous error, the files should be\n# in '../input/moto-gp/' and named 'train.csv', 'test.csv', etc.\ntry:\n    train_df = pd.read_csv('../input/moto-gp/train.csv')\n    test_df = pd.read_csv('../input/moto-gp/test.csv')\n    sample_submission_df = pd.read_csv('../input/moto-gp/sample_submission.csv')\n    val_df = pd.read_csv('../input/moto-gp/val.csv') # Loading val.csv as it's present\n\n    print(\"\\nGot all the datasets loaded up! Looking good:\")\n    print(f\"  Train data rows/cols: {train_df.shape}\")\n    print(f\"  Test data rows/cols: {test_df.shape}\")\n    print(f\"  Sample Submission rows/cols: {sample_submission_df.shape}\")\n    print(f\"  Validation data rows/cols: {val_df.shape}\") # Just for context!\nexcept FileNotFoundError as e:\n    print(f\"UH OH! Can't find one of the files. Double-check your directory and filenames: {e}\")\n    # If we can't load the core files, no point in going on.\n    exit()\nexcept Exception as e:\n    print(f\"CRITICAL ERROR during data loading! Something went wrong: {e}\")\n    exit()\n\n# --- 2. Preprocessing ---\nprint(\"\\n--- Time to Clean and Prep the Data! ---\")\n\n# Keeping track of original dataset sizes. Handy for splitting later.\ntrain_len = len(train_df)\ntest_len = len(test_df)\n\n# Our main goal is to predict 'Lap_Time_Seconds', so let's pull that out as our target.\ny_train = train_df['Lap_Time_Seconds']\ntrain_df_processed = train_df.drop(columns=['Lap_Time_Seconds'])\n\n# Super important: We need to remember the 'Unique ID's from the original test set.\n# This ensures we can match our predictions back correctly to the submission format.\noriginal_test_ids = test_df['Unique ID']\n\n# Okay, combining train and test data. This is a common trick to make sure\n# we apply the same cleaning and encoding steps uniformly across both.\n# First, let's make sure they both have the exact same columns.\n# Sometimes a column might be in one but not the other, which breaks things.\nmissing_in_test = set(train_df_processed.columns) - set(test_df.columns)\nmissing_in_train = set(test_df.columns) - set(train_df_processed.columns)\n\nfor col in missing_in_test:\n    # Adding any missing columns to the test_df. Defaulting to NaN for now.\n    test_df[col] = np.nan\n    print(f\"  Heads up: Added column '{col}' to test_df. It was missing there.\")\nfor col in missing_in_train:\n    # Same for the training data.\n    train_df_processed[col] = np.nan\n    print(f\"  Heads up: Added column '{col}' to train_df_processed. It was missing here.\")\n\n# Now, let's line up the columns perfectly before sticking them together.\ntest_df = test_df[train_df_processed.columns] # Reorder test_df columns to match train_df_processed\n\n# Alright, combine 'em!\ncombined_df = pd.concat([train_df_processed, test_df], ignore_index=True)\n\n# Handling those pesky missing values in the combined data\n# 'Penalty' column: If it's empty, let's just assume 'No Penalty'. Makes sense, right?\nif 'Penalty' in combined_df.columns:\n    combined_df['Penalty'].fillna('No Penalty', inplace=True)\n    print(\"  Filled empty 'Penalty' spots with 'No Penalty'.\")\n\n# 'team_name' column: If we don't know the team, let's call it 'Unknown Team'. Simple.\nif 'team_name' in combined_df.columns:\n    combined_df['team_name'].fillna('Unknown Team', inplace=True)\n    print(\"  Filled missing 'team_name' values with 'Unknown Team'.\")\n\n# Time for One-Hot Encoding!\n# This takes text categories (like 'Dry', 'Wet' for track conditions) and turns them into numbers\n# so our machine learning model can understand them.\ncategorical_cols = combined_df.select_dtypes(include='object').columns\nprint(f\"  Found {len(categorical_cols)} text-based columns to encode: {list(categorical_cols)}\")\ncombined_df_encoded = pd.get_dummies(combined_df, columns=categorical_cols, dummy_na=False)\nprint(\"  All text columns are now numbers! Nice.\")\n\n# Phew! Data's prepped. Now, let's split it back to our training and testing feature sets.\n# And toss out the 'Unique ID' column from the features because it's just an identifier, not data.\nX_train_model = combined_df_encoded.iloc[:train_len].drop(columns=['Unique ID'])\nX_test_model = combined_df_encoded.iloc[train_len:].drop(columns=['Unique ID'])\n\nprint(\"--- Data Preprocessing DONE! ---\")\nprint(f\"  Ready for training: X_train_model shape {X_train_model.shape}\")\nprint(f\"  Ready for prediction: X_test_model shape {X_test_model.shape}\")\n\n# --- 3. Model Selection & Training ---\nprint(\"\\n--- Now, let's teach our model! ---\")\n# Going with RandomForestRegressor. It's a solid choice for tabular data like this,\n# usually performs well, and handles diverse features without too much fuss.\n# n_estimators=100 is a good default, random_state makes results repeatable,\n# and n_jobs=-1 tells it to use all your computer's power (cores).\nrf_model = RandomForestRegressor(n_estimators=100, random_state=42, n_jobs=-1)\n\n# Training time! This is where the model learns from our prepared training data.\nrf_model.fit(X_train_model, y_train)\nprint(\"--- Model's all trained up! ---\")\n\n# --- 4. Prediction ---\nprint(\"\\n--- Time to get some predictions! ---\")\n# Using our trained model to guess the lap times for the test data.\npredictions_test_df = rf_model.predict(X_test_model)\nprint(\"--- Predictions calculated! ---\")\n\n# --- 5. Final Submission File Construction ---\nprint(\"\\n--- Putting together the final submission file... ---\")\n\n# Let's create a temporary table with our predictions linked to their original IDs.\npredicted_values_df = pd.DataFrame({\n    'Unique ID': original_test_ids,\n    'Lap_Time_Seconds_Predicted': predictions_test_df\n})\n\n# This is key! We merge our predictions with the sample_submission_df.\n# Why? Because the competition wants SPECIFIC 'Unique ID's in a SPECIFIC order.\n# 'how='left'' makes sure we keep ALL the IDs from the sample submission file.\nfinal_submission_df = sample_submission_df[['Unique ID']].merge(\n    predicted_values_df,\n    on='Unique ID',\n    how='left'\n)\n\n# A little safety check: What if the sample submission has IDs our test set didn't?\n# (This shouldn't happen in well-structured contests, but it's good to be safe!)\n# If there are any missing predictions after the merge, we'll fill them with the\n# average of all our other predictions. Better than an empty spot!\nmean_predicted_lap_time = predicted_values_df['Lap_Time_Seconds_Predicted'].mean()\nif final_submission_df['Lap_Time_Seconds_Predicted'].isnull().any():\n    print(f\"  Whoops! Found some missing predictions. Filling them with the average lap time: {mean_predicted_lap_time:.2f}\")\n    final_submission_df['Lap_Time_Seconds_Predicted'].fillna(mean_predicted_lap_time, inplace=True)\nelse:\n    print(\"  All good! Every required ID got a prediction. No need to fill blanks.\")\n\n\n# Last step: Rename our prediction column to 'Lap_Time_Seconds' to match what they expect.\nfinal_submission_df.rename(columns={'Lap_Time_Seconds_Predicted': 'Lap_Time_Seconds'}, inplace=True)\n\n# And finally, save it! This is our 'solution.csv' ready for submission.\nsubmission_file_name = 'solution.csv'\nfinal_submission_df.to_csv(submission_file_name, index=False)\n\nprint(f\"\\n--- SUCCESS! Your final submission file '{submission_file_name}' is ready! ---\")\nprint(f\"  It has exactly {len(final_submission_df)} rows, just like they asked!\")\nprint(\"\\n--- Sneak peek at the beginning of your solution ---\")\nprint(final_submission_df.head())\nprint(\"\\n--- And a look at the end ---\")\nprint(final_submission_df.tail())\n\nprint(\"\\n--- All done! Good luck with the challenge! ---\")\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-06-14T16:43:50.036419Z","iopub.execute_input":"2025-06-14T16:43:50.0368Z","iopub.status.idle":"2025-06-14T16:43:55.040646Z","shell.execute_reply.started":"2025-06-14T16:43:50.036769Z","shell.execute_reply":"2025-06-14T16:43:55.038902Z"}},"outputs":[],"execution_count":null}]}