{"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":31239,"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)\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\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","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 🌱 CSIRO Image2Biomass Prediction – Baseline Notebook\n\nThis notebook builds a baseline model to predict pasture biomass\nfrom images and associated tabular data.\n\nTargets:\n- Dry_Green_g\n- Dry_Dead_g\n- Dry_Clover_g\n- GDM_g\n- Dry_Total_g\n\n","metadata":{}},{"cell_type":"code","source":"#Import Libraries\nimport os\nimport numpy as np\nimport pandas as pd\nimport cv2\n\nfrom tqdm import tqdm\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.multioutput import MultiOutputRegressor\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.metrics import r2_score\n\nimport matplotlib.pyplot as plt\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# List everything inside the dataset\nos.listdir(\"/kaggle/input\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:00:00.101532Z","iopub.execute_input":"2025-12-29T20:00:00.101907Z","iopub.status.idle":"2025-12-29T20:00:00.108886Z","shell.execute_reply.started":"2025-12-29T20:00:00.101881Z","shell.execute_reply":"2025-12-29T20:00:00.107665Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BASE_PATH = \"/kaggle/input/csiro-biomass\"\nos.listdir(BASE_PATH)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:00:05.461229Z","iopub.execute_input":"2025-12-29T20:00:05.461570Z","iopub.status.idle":"2025-12-29T20:00:05.498062Z","shell.execute_reply.started":"2025-12-29T20:00:05.461537Z","shell.execute_reply":"2025-12-29T20:00:05.496959Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df = pd.read_csv(os.path.join(BASE_PATH, \"train.csv\"))\ntest_df  = pd.read_csv(os.path.join(BASE_PATH, \"test.csv\"))\n\ntrain_df.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:00:09.536181Z","iopub.execute_input":"2025-12-29T20:00:09.536517Z","iopub.status.idle":"2025-12-29T20:00:09.560389Z","shell.execute_reply.started":"2025-12-29T20:00:09.536494Z","shell.execute_reply":"2025-12-29T20:00:09.559358Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(train_df.columns.tolist())\n\n# In this competition, image id is always the first column\nimage_col = train_df.columns[0]\nprint(\"Using image column:\", image_col)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:00:13.241395Z","iopub.execute_input":"2025-12-29T20:00:13.241758Z","iopub.status.idle":"2025-12-29T20:00:13.246544Z","shell.execute_reply.started":"2025-12-29T20:00:13.241733Z","shell.execute_reply":"2025-12-29T20:00:13.245562Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_img_path = None\ntest_img_path = None\n\nfor root, dirs, files in os.walk(BASE_PATH):\n    jpgs = [f for f in files if f.lower().endswith(\".jpg\")]\n    if jpgs:\n        if \"train\" in root.lower():\n            train_img_path = root\n        elif \"test\" in root.lower():\n            test_img_path = root\n\nprint(\"Train image path:\", train_img_path)\nprint(\"Test image path :\", test_img_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:00:16.336405Z","iopub.execute_input":"2025-12-29T20:00:16.336741Z","iopub.status.idle":"2025-12-29T20:00:16.735312Z","shell.execute_reply.started":"2025-12-29T20:00:16.336714Z","shell.execute_reply":"2025-12-29T20:00:16.734444Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TRAIN_IMG_PATH = train_img_path\nTEST_IMG_PATH = test_img_path\n\nprint(\"Train images:\", len(os.listdir(TRAIN_IMG_PATH)))\nprint(\"Test images :\", len(os.listdir(TEST_IMG_PATH)) if TEST_IMG_PATH else \"Hidden\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:00:20.161454Z","iopub.execute_input":"2025-12-29T20:00:20.162218Z","iopub.status.idle":"2025-12-29T20:00:20.169699Z","shell.execute_reply.started":"2025-12-29T20:00:20.162190Z","shell.execute_reply":"2025-12-29T20:00:20.168770Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pivot_df = train_df.pivot_table(\n    index=\"image_path\",\n    columns=\"target_name\",\n    values=\"target\"\n).reset_index()\n\npivot_df.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:00:23.701466Z","iopub.execute_input":"2025-12-29T20:00:23.701774Z","iopub.status.idle":"2025-12-29T20:00:23.720467Z","shell.execute_reply.started":"2025-12-29T20:00:23.701753Z","shell.execute_reply":"2025-12-29T20:00:23.719566Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TARGETS = [\n    \"Dry_Green_g\",\n    \"Dry_Dead_g\",\n    \"Dry_Clover_g\",\n    \"GDM_g\",\n    \"Dry_Total_g\"\n]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:00:29.876234Z","iopub.execute_input":"2025-12-29T20:00:29.877104Z","iopub.status.idle":"2025-12-29T20:00:29.881162Z","shell.execute_reply.started":"2025-12-29T20:00:29.877076Z","shell.execute_reply":"2025-12-29T20:00:29.880254Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def extract_image_features(image_path):\n    img = cv2.imread(image_path)\n    img = cv2.resize(img, (128, 128))\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n    return [\n        img.mean(),\n        img.std(),\n        img[:,:,0].mean(),\n        img[:,:,1].mean(),\n        img[:,:,2].mean()\n    ]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:00:44.141651Z","iopub.execute_input":"2025-12-29T20:00:44.141997Z","iopub.status.idle":"2025-12-29T20:00:44.147443Z","shell.execute_reply.started":"2025-12-29T20:00:44.141975Z","shell.execute_reply":"2025-12-29T20:00:44.146627Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X = []\ny = []\nskipped = 0\n\nfor _, row in tqdm(pivot_df.iterrows(), total=len(pivot_df)):\n    # image_path already contains correct relative path\n    img_path = os.path.join(BASE_PATH, row[\"image_path\"])\n\n    if not os.path.exists(img_path):\n        skipped += 1\n        continue\n\n    img = cv2.imread(img_path)\n    if img is None:\n        skipped += 1\n        continue\n\n    X.append(extract_image_features(img_path))\n    y.append(row[TARGETS].values.astype(float))\n\nX = np.array(X)\ny = np.array(y)\n\nprint(\"X shape:\", X.shape)\nprint(\"y shape:\", y.shape)\nprint(\"Skipped images:\", skipped)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:00:48.606293Z","iopub.execute_input":"2025-12-29T20:00:48.606603Z","iopub.status.idle":"2025-12-29T20:01:34.194675Z","shell.execute_reply.started":"2025-12-29T20:00:48.606583Z","shell.execute_reply":"2025-12-29T20:01:34.193737Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X_train, X_val, y_train, y_val = train_test_split(\n    X, y, test_size=0.2, random_state=42\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:01:50.586289Z","iopub.execute_input":"2025-12-29T20:01:50.586619Z","iopub.status.idle":"2025-12-29T20:01:50.592274Z","shell.execute_reply.started":"2025-12-29T20:01:50.586597Z","shell.execute_reply":"2025-12-29T20:01:50.591247Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = MultiOutputRegressor(\n    RandomForestRegressor(\n        n_estimators=300,\n        max_depth=18,\n        random_state=42,\n        n_jobs=-1\n    )\n)\n\nmodel.fit(X_train, y_train)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:01:56.421744Z","iopub.execute_input":"2025-12-29T20:01:56.423045Z","iopub.status.idle":"2025-12-29T20:01:59.915981Z","shell.execute_reply.started":"2025-12-29T20:01:56.423005Z","shell.execute_reply":"2025-12-29T20:01:59.915008Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"preds = model.predict(X_val)\n\nfor i, t in enumerate(TARGETS):\n    print(f\"{t} R²:\", round(r2_score(y_val[:, i], preds[:, i]), 4))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:02:24.526703Z","iopub.execute_input":"2025-12-29T20:02:24.527376Z","iopub.status.idle":"2025-12-29T20:02:24.875460Z","shell.execute_reply.started":"2025-12-29T20:02:24.527348Z","shell.execute_reply":"2025-12-29T20:02:24.874425Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Get unique test images\ntest_images = test_df[\"image_path\"].unique()\nlen(test_images)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:04:24.836729Z","iopub.execute_input":"2025-12-29T20:04:24.837628Z","iopub.status.idle":"2025-12-29T20:04:24.844077Z","shell.execute_reply.started":"2025-12-29T20:04:24.837586Z","shell.execute_reply":"2025-12-29T20:04:24.843247Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X_test = []\n\nfor img_path in test_images:\n    full_path = os.path.join(BASE_PATH, img_path)\n\n    if os.path.exists(full_path):\n        X_test.append(extract_image_features(full_path))\n    else:\n        X_test.append(np.zeros(5))\n\nX_test = np.array(X_test)\nprint(\"X_test shape:\", X_test.shape)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:04:53.802069Z","iopub.execute_input":"2025-12-29T20:04:53.802380Z","iopub.status.idle":"2025-12-29T20:04:53.909798Z","shell.execute_reply.started":"2025-12-29T20:04:53.802359Z","shell.execute_reply":"2025-12-29T20:04:53.908908Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_preds = model.predict(X_test)\nprint(\"Predictions shape:\", test_preds.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:05:07.522626Z","iopub.execute_input":"2025-12-29T20:05:07.522989Z","iopub.status.idle":"2025-12-29T20:05:07.813337Z","shell.execute_reply.started":"2025-12-29T20:05:07.522966Z","shell.execute_reply":"2025-12-29T20:05:07.812521Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"rows = []\n\nfor i, img_path in enumerate(test_images):\n    img_id = img_path.split(\"/\")[-1].replace(\".jpg\", \"\")\n\n    for j, t in enumerate(TARGETS):\n        rows.append({\n            \"sample_id\": f\"{img_id}__{t}\",\n            \"target\": float(test_preds[i, j])\n        })\n\nsubmission = pd.DataFrame(rows)\nsubmission.to_csv(\"submission.csv\", index=False)\n\nsubmission.head(10)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T20:05:23.461538Z","iopub.execute_input":"2025-12-29T20:05:23.461875Z","iopub.status.idle":"2025-12-29T20:05:23.484783Z","shell.execute_reply.started":"2025-12-29T20:05:23.461832Z","shell.execute_reply":"2025-12-29T20:05:23.483722Z"}},"outputs":[],"execution_count":null}]}