{"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":"none","dataSources":[{"sourceId":112509,"databundleVersionId":14254895,"sourceType":"competition"}],"dockerImageVersionId":31153,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"This notebook demonstrates a complete baseline pipeline for the CSIRO Image2Biomass Prediction competition.\nThe goal of this challenge is to predict pasture biomass (in grams) across five key vegetation components using images and associated metadata.\n\n**Objective**\nBuild a model that estimates:\n\n* Dry green vegetation (excluding clover)\n* Dry dead material\n* Dry clover biomass\n* Green dry matter (GDM)\n* Total dry biomass\n\n**This Notebook Includes**\n\n1. Environment setup and data loading\n2. Metadata preprocessing (dates, categories, NDVI, etc.)\n3. Baseline model training using Random Forest\n4. Local validation using R² score\n5. Test prediction and submission.csv creation\n\n**Model Approach**\n\nWe start with a simple tabular baseline using only numeric and categorical features.\nLater stages will extend this to a CNN + metadata hybrid model leveraging EfficientNet image embeddings.\n\n\n","metadata":{}},{"cell_type":"code","source":"# =========================================================\n# 1️⃣ Setup and Imports\n# =========================================================\nimport os\nimport pandas as pd\nimport numpy as np\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.metrics import r2_score\n\n# Kaggle dataset path (automatically mounted in environment)\nBASE_PATH = \"/kaggle/input/csiro-biomass\"\n\nprint(\"Available files:\", os.listdir(BASE_PATH))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-30T07:34:56.556298Z","iopub.execute_input":"2025-10-30T07:34:56.556684Z","iopub.status.idle":"2025-10-30T07:34:56.567089Z","shell.execute_reply.started":"2025-10-30T07:34:56.556650Z","shell.execute_reply":"2025-10-30T07:34:56.565720Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =========================================================\n# 2️⃣ Load CSV Files\n# =========================================================\ntrain = pd.read_csv(f\"{BASE_PATH}/train.csv\")\ntest = pd.read_csv(f\"{BASE_PATH}/test.csv\")\nsample_sub = pd.read_csv(f\"{BASE_PATH}/sample_submission.csv\")\n\nprint(\"Train shape:\", train.shape)\nprint(\"Test shape:\", test.shape)\ntrain.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-30T07:34:56.569075Z","iopub.execute_input":"2025-10-30T07:34:56.569408Z","iopub.status.idle":"2025-10-30T07:34:56.665332Z","shell.execute_reply.started":"2025-10-30T07:34:56.569384Z","shell.execute_reply":"2025-10-30T07:34:56.664146Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =========================================================\n# 3️⃣ Data Preprocessing\n# =========================================================\n\n# Handle Sampling_Date if exists\nif \"Sampling_Date\" in train.columns:\n    train[\"Sampling_Date\"] = pd.to_datetime(train[\"Sampling_Date\"], errors=\"coerce\")\n    train[\"year\"] = train[\"Sampling_Date\"].dt.year\n    train[\"month\"] = train[\"Sampling_Date\"].dt.month\n    train[\"day\"] = train[\"Sampling_Date\"].dt.day\nelse:\n    train[\"year\"] = train[\"month\"] = train[\"day\"] = 0\n\nif \"Sampling_Date\" in test.columns:\n    test[\"Sampling_Date\"] = pd.to_datetime(test[\"Sampling_Date\"], errors=\"coerce\")\n    test[\"year\"] = test[\"Sampling_Date\"].dt.year\n    test[\"month\"] = test[\"Sampling_Date\"].dt.month\n    test[\"day\"] = test[\"Sampling_Date\"].dt.day\nelse:\n    test[\"year\"] = test[\"month\"] = test[\"day\"] = 0\n\n# Encode categorical columns\nfor col in [\"State\", \"Species\", \"target_name\"]:\n    le = LabelEncoder()\n    le.fit(pd.concat([train[col].astype(str), test.get(col, pd.Series([])).astype(str)]))\n    train[col] = le.transform(train[col].astype(str))\n    if col in test.columns:\n        test[col] = le.transform(test[col].astype(str))\n    else:\n        test[col] = 0\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-30T07:34:56.666210Z","iopub.execute_input":"2025-10-30T07:34:56.666531Z","iopub.status.idle":"2025-10-30T07:34:56.787070Z","shell.execute_reply.started":"2025-10-30T07:34:56.666507Z","shell.execute_reply":"2025-10-30T07:34:56.785751Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =========================================================\n# 4️⃣ Prepare Features\n# =========================================================\nfeature_cols = [\"State\", \"Species\", \"Pre_GSHH_NDVI\", \"Height_Ave_cm\", \"year\", \"month\", \"day\", \"target_name\"]\n\n# Make sure all columns exist\nfor col in feature_cols:\n    if col not in test.columns:\n        test[col] = 0\n    if col not in train.columns:\n        train[col] = 0\n\nX = train[feature_cols].copy()\ny = train[\"target\"].copy()\n\nX_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2, random_state=42)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-30T07:34:56.788266Z","iopub.execute_input":"2025-10-30T07:34:56.788645Z","iopub.status.idle":"2025-10-30T07:34:56.809871Z","shell.execute_reply.started":"2025-10-30T07:34:56.788591Z","shell.execute_reply":"2025-10-30T07:34:56.808024Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =========================================================\n# 5️⃣ Train Baseline Model\n# =========================================================\nmodel = RandomForestRegressor(\n    n_estimators=400,\n    max_depth=12,\n    random_state=42,\n    n_jobs=-1\n)\nmodel.fit(X_train, y_train)\n\n# Validate\ny_pred = model.predict(X_valid)\nr2 = r2_score(y_valid, y_pred)\nprint(\"Validation R²:\", round(r2, 4))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-30T07:34:56.812450Z","iopub.execute_input":"2025-10-30T07:34:56.813760Z","iopub.status.idle":"2025-10-30T07:34:58.456932Z","shell.execute_reply.started":"2025-10-30T07:34:56.813712Z","shell.execute_reply":"2025-10-30T07:34:58.455542Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =========================================================\n# 6️⃣ Generate Predictions and Submission\n# =========================================================\ntest_features = test[feature_cols]\ntest[\"target\"] = model.predict(test_features)\n\nsubmission = test[[\"sample_id\", \"target\"]].copy()\nsubmission.to_csv(\"/kaggle/working/submission.csv\", index=False)\nprint(\"✅ submission.csv created successfully!\")\nsubmission.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-30T07:34:58.458417Z","iopub.execute_input":"2025-10-30T07:34:58.458847Z","iopub.status.idle":"2025-10-30T07:34:58.578668Z","shell.execute_reply.started":"2025-10-30T07:34:58.458813Z","shell.execute_reply":"2025-10-30T07:34:58.577691Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Show path of final submission file\n!ls -lh /kaggle/working/\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-30T07:34:58.579518Z","iopub.execute_input":"2025-10-30T07:34:58.579871Z","iopub.status.idle":"2025-10-30T07:34:58.715198Z","shell.execute_reply.started":"2025-10-30T07:34:58.579843Z","shell.execute_reply":"2025-10-30T07:34:58.713694Z"}},"outputs":[],"execution_count":null}]}