{"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":31192,"isInternetEnabled":false,"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,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.395765Z","iopub.execute_input":"2025-12-13T09:45:59.396120Z","iopub.status.idle":"2025-12-13T09:45:59.417007Z","shell.execute_reply.started":"2025-12-13T09:45:59.396089Z","shell.execute_reply":"2025-12-13T09:45:59.416302Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\ntrain_df = pd.read_csv(\"/kaggle/input/csiro-biomass/train.csv\")\ntrain_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.417718Z","iopub.execute_input":"2025-12-13T09:45:59.418067Z","iopub.status.idle":"2025-12-13T09:45:59.434730Z","shell.execute_reply.started":"2025-12-13T09:45:59.418035Z","shell.execute_reply":"2025-12-13T09:45:59.434005Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.435702Z","iopub.execute_input":"2025-12-13T09:45:59.436019Z","iopub.status.idle":"2025-12-13T09:45:59.441104Z","shell.execute_reply.started":"2025-12-13T09:45:59.435996Z","shell.execute_reply":"2025-12-13T09:45:59.440210Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.columns","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.442007Z","iopub.execute_input":"2025-12-13T09:45:59.442224Z","iopub.status.idle":"2025-12-13T09:45:59.453463Z","shell.execute_reply.started":"2025-12-13T09:45:59.442207Z","shell.execute_reply":"2025-12-13T09:45:59.452710Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.454147Z","iopub.execute_input":"2025-12-13T09:45:59.455187Z","iopub.status.idle":"2025-12-13T09:45:59.470734Z","shell.execute_reply.started":"2025-12-13T09:45:59.455166Z","shell.execute_reply":"2025-12-13T09:45:59.469894Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df['target_name'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.471436Z","iopub.execute_input":"2025-12-13T09:45:59.471623Z","iopub.status.idle":"2025-12-13T09:45:59.485634Z","shell.execute_reply.started":"2025-12-13T09:45:59.471608Z","shell.execute_reply":"2025-12-13T09:45:59.484685Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df['image_path'].nunique(), len(train_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.486511Z","iopub.execute_input":"2025-12-13T09:45:59.487410Z","iopub.status.idle":"2025-12-13T09:45:59.497377Z","shell.execute_reply.started":"2025-12-13T09:45:59.487387Z","shell.execute_reply":"2025-12-13T09:45:59.496617Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df.groupby(\"image_path\")[\"target\"].count().value_counts()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.498235Z","iopub.execute_input":"2025-12-13T09:45:59.498513Z","iopub.status.idle":"2025-12-13T09:45:59.511006Z","shell.execute_reply.started":"2025-12-13T09:45:59.498487Z","shell.execute_reply":"2025-12-13T09:45:59.510225Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"total_df = train_df[train_df[\"target_name\"] == \"Dry_Total_g\"]\ntotal_df[\"target\"].describe()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.511973Z","iopub.execute_input":"2025-12-13T09:45:59.512209Z","iopub.status.idle":"2025-12-13T09:45:59.526860Z","shell.execute_reply.started":"2025-12-13T09:45:59.512190Z","shell.execute_reply":"2025-12-13T09:45:59.525968Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# One row per image metadata (used for all targets)\nimg_meta = (\n    train_df[[\"image_path\", \"Height_Ave_cm\", \"Pre_GSHH_NDVI\", \"Species\", \"State\"]]\n    .drop_duplicates(\"image_path\")\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.527713Z","iopub.execute_input":"2025-12-13T09:45:59.527964Z","iopub.status.idle":"2025-12-13T09:45:59.537677Z","shell.execute_reply.started":"2025-12-13T09:45:59.527933Z","shell.execute_reply":"2025-12-13T09:45:59.536780Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.hist(total_df[\"target\"], bins=30)\nplt.title(\"Dry_Total_g Distribution\")\nplt.xlabel(\"Biomass (g)\")\nplt.ylabel(\"Count\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.538625Z","iopub.execute_input":"2025-12-13T09:45:59.538894Z","iopub.status.idle":"2025-12-13T09:45:59.732706Z","shell.execute_reply.started":"2025-12-13T09:45:59.538874Z","shell.execute_reply":"2025-12-13T09:45:59.731902Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"total_df = train_df[train_df[\"target_name\"] == \"Dry_Total_g\"]\n\ntotal_df[[\"target\", \"Height_Ave_cm\", \"Pre_GSHH_NDVI\"]].corr()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.733698Z","iopub.execute_input":"2025-12-13T09:45:59.734423Z","iopub.status.idle":"2025-12-13T09:45:59.744892Z","shell.execute_reply.started":"2025-12-13T09:45:59.734397Z","shell.execute_reply":"2025-12-13T09:45:59.744187Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.scatter(total_df[\"Height_Ave_cm\"], total_df[\"target\"])\nplt.xlabel(\"Height (cm)\")\nplt.ylabel(\"Dry_Total_g\")\nplt.title(\"Height vs Dry_Total_g\")\nplt.show()\n\nplt.scatter(total_df[\"Pre_GSHH_NDVI\"], total_df[\"target\"])\nplt.xlabel(\"NDVI\")\nplt.ylabel(\"Dry_Total_g\")\nplt.title(\"NDVI vs Dry_Total_g\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:45:59.745844Z","iopub.execute_input":"2025-12-13T09:45:59.746619Z","iopub.status.idle":"2025-12-13T09:46:00.085795Z","shell.execute_reply.started":"2025-12-13T09:45:59.746566Z","shell.execute_reply":"2025-12-13T09:46:00.084886Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from PIL import Image\nimport matplotlib.pyplot as plt\n\n# pick the first Dry_Total_g image\nsample_row = total_df.iloc[0]\nimg_path = \"/kaggle/input/csiro-biomass/\" + sample_row[\"image_path\"]\n\nimg = Image.open(img_path)\nplt.imshow(img)\nplt.axis(\"off\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:00.087104Z","iopub.execute_input":"2025-12-13T09:46:00.087380Z","iopub.status.idle":"2025-12-13T09:46:00.538641Z","shell.execute_reply.started":"2025-12-13T09:46:00.087348Z","shell.execute_reply":"2025-12-13T09:46:00.537599Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# low biomass image\nlow_row = total_df.loc[total_df[\"target\"].idxmin()]\nlow_img = Image.open(\"/kaggle/input/csiro-biomass/\" + low_row[\"image_path\"])\nplt.imshow(low_img)\nplt.title(f\"Low biomass: {low_row['target']} g\")\nplt.axis(\"off\")\nplt.show()\n\n# high biomass image\nhigh_row = total_df.loc[total_df[\"target\"].idxmax()]\nhigh_img = Image.open(\"/kaggle/input/csiro-biomass/\" + high_row[\"image_path\"])\nplt.imshow(high_img)\nplt.title(f\"High biomass: {high_row['target']} g\")\nplt.axis(\"off\")\nplt.show()\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:00.539599Z","iopub.execute_input":"2025-12-13T09:46:00.539818Z","iopub.status.idle":"2025-12-13T09:46:01.293483Z","shell.execute_reply.started":"2025-12-13T09:46:00.539799Z","shell.execute_reply":"2025-12-13T09:46:01.292328Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"total_df = train_df[train_df[\"target_name\"] == \"Dry_Total_g\"]\n\n# Select only the columns we need\nbaseline_df = total_df[[\"Height_Ave_cm\", \"Pre_GSHH_NDVI\", \"target\"]]\nbaseline_df.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:01.294338Z","iopub.execute_input":"2025-12-13T09:46:01.294587Z","iopub.status.idle":"2025-12-13T09:46:01.305953Z","shell.execute_reply.started":"2025-12-13T09:46:01.294565Z","shell.execute_reply":"2025-12-13T09:46:01.305270Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nX = baseline_df[[\"Height_Ave_cm\", \"Pre_GSHH_NDVI\"]]\ny = baseline_df[\"target\"]\n\nX_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-13T09:46:01.306769Z","iopub.execute_input":"2025-12-13T09:46:01.307018Z","iopub.status.idle":"2025-12-13T09:46:01.318559Z","shell.execute_reply.started":"2025-12-13T09:46:01.307000Z","shell.execute_reply":"2025-12-13T09:46:01.317747Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.linear_model import LinearRegression\n\nlr = LinearRegression()\nlr.fit(X_train, y_train)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:01.319485Z","iopub.execute_input":"2025-12-13T09:46:01.320163Z","iopub.status.idle":"2025-12-13T09:46:01.335000Z","shell.execute_reply.started":"2025-12-13T09:46:01.320144Z","shell.execute_reply":"2025-12-13T09:46:01.334223Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import mean_squared_error\nimport numpy as np\n\npreds = lr.predict(X_val)\nrmse = np.sqrt(mean_squared_error(y_val, preds))\nrmse","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:01.335857Z","iopub.execute_input":"2025-12-13T09:46:01.336097Z","iopub.status.idle":"2025-12-13T09:46:01.349084Z","shell.execute_reply.started":"2025-12-13T09:46:01.336078Z","shell.execute_reply":"2025-12-13T09:46:01.348355Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.ensemble import RandomForestRegressor\n\nrf = RandomForestRegressor(\n    n_estimators=300,\n    random_state=42,\n    n_jobs=-1\n)\n\nrf.fit(X_train, y_train)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:01.350020Z","iopub.execute_input":"2025-12-13T09:46:01.350318Z","iopub.status.idle":"2025-12-13T09:46:01.891510Z","shell.execute_reply.started":"2025-12-13T09:46:01.350297Z","shell.execute_reply":"2025-12-13T09:46:01.890722Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"rf_preds = rf.predict(X_val)\nrf_rmse = np.sqrt(mean_squared_error(y_val, rf_preds))\nrf_rmse\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:01.892346Z","iopub.execute_input":"2025-12-13T09:46:01.892576Z","iopub.status.idle":"2025-12-13T09:46:01.956517Z","shell.execute_reply.started":"2025-12-13T09:46:01.892558Z","shell.execute_reply":"2025-12-13T09:46:01.955783Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#CNN\nfrom PIL import Image\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# take one image\nrow = total_df.iloc[0]\nimg = Image.open(\"/kaggle/input/csiro-biomass/\" + row[\"image_path\"])\n\n# resize\nimg_resized = img.resize((224, 224))\n\nplt.imshow(img_resized)\nplt.axis(\"off\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:01.957261Z","iopub.execute_input":"2025-12-13T09:46:01.957503Z","iopub.status.idle":"2025-12-13T09:46:02.160864Z","shell.execute_reply.started":"2025-12-13T09:46:01.957481Z","shell.execute_reply":"2025-12-13T09:46:02.159906Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img_array = np.array(img_resized)\n\nimg_array.shape\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.161796Z","iopub.execute_input":"2025-12-13T09:46:02.162433Z","iopub.status.idle":"2025-12-13T09:46:02.167915Z","shell.execute_reply.started":"2025-12-13T09:46:02.162404Z","shell.execute_reply":"2025-12-13T09:46:02.167191Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img_array = img_array / 255.0\n\nimg_array.min(), img_array.max()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.168739Z","iopub.execute_input":"2025-12-13T09:46:02.168994Z","iopub.status.idle":"2025-12-13T09:46:02.181517Z","shell.execute_reply.started":"2025-12-13T09:46:02.168975Z","shell.execute_reply":"2025-12-13T09:46:02.180710Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"total_df = train_df[train_df[\"target_name\"] == \"Dry_Total_g\"]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.182423Z","iopub.execute_input":"2025-12-13T09:46:02.182648Z","iopub.status.idle":"2025-12-13T09:46:02.192916Z","shell.execute_reply.started":"2025-12-13T09:46:02.182621Z","shell.execute_reply":"2025-12-13T09:46:02.192134Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from PIL import Image\nimport numpy as np\n\ndef load_image(path, size=(224, 224)):\n    img = Image.open(path).convert(\"RGB\")\n    img = img.resize(size)\n    return np.array(img) / 255.0\n\n# try loading first 10 images\nX_imgs = []\ny_vals = []\n\nfor _, row in total_df.head(10).iterrows():\n    img_path = \"/kaggle/input/csiro-biomass/\" + row[\"image_path\"]\n    X_imgs.append(load_image(img_path))\n    y_vals.append(row[\"target\"])\n\nX_imgs = np.array(X_imgs)\ny_vals = np.array(y_vals)\n\nX_imgs.shape, y_vals.shape\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.193658Z","iopub.execute_input":"2025-12-13T09:46:02.193912Z","iopub.status.idle":"2025-12-13T09:46:02.855451Z","shell.execute_reply.started":"2025-12-13T09:46:02.193885Z","shell.execute_reply":"2025-12-13T09:46:02.854668Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Using a pretrained cnn model\n# import torch\n# import torchvision.models as models\n# import torchvision.transforms as transforms\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.863206Z","iopub.execute_input":"2025-12-13T09:46:02.863441Z","iopub.status.idle":"2025-12-13T09:46:02.867016Z","shell.execute_reply.started":"2025-12-13T09:46:02.863421Z","shell.execute_reply":"2025-12-13T09:46:02.866186Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# resnet = models.resnet18(pretrained=True)\n# resnet.eval()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.867807Z","iopub.execute_input":"2025-12-13T09:46:02.868101Z","iopub.status.idle":"2025-12-13T09:46:02.879594Z","shell.execute_reply.started":"2025-12-13T09:46:02.868075Z","shell.execute_reply":"2025-12-13T09:46:02.878629Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# feature_extractor = torch.nn.Sequential(\n#     *list(resnet.children())[:-1]\n# )\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.880451Z","iopub.execute_input":"2025-12-13T09:46:02.880683Z","iopub.status.idle":"2025-12-13T09:46:02.893010Z","shell.execute_reply.started":"2025-12-13T09:46:02.880666Z","shell.execute_reply":"2025-12-13T09:46:02.892129Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# transform = transforms.Compose([\n#     transforms.Resize((224, 224)),\n#     transforms.ToTensor(),\n#     transforms.Normalize(\n#         mean=[0.485, 0.456, 0.406],\n#         std=[0.229, 0.224, 0.225]\n#     )\n# ])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.893860Z","iopub.execute_input":"2025-12-13T09:46:02.894093Z","iopub.status.idle":"2025-12-13T09:46:02.904814Z","shell.execute_reply.started":"2025-12-13T09:46:02.894072Z","shell.execute_reply":"2025-12-13T09:46:02.904032Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# from PIL import Image\n\n# row = total_df.iloc[0]\n# img = Image.open(\"/kaggle/input/csiro-biomass/\" + row[\"image_path\"]).convert(\"RGB\")\n\n# img_tensor = transform(img).unsqueeze(0)  # shape: (1, 3, 224, 224)\n\n# with torch.no_grad():\n#     features = feature_extractor(img_tensor)\n\n# features.shape\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.906318Z","iopub.execute_input":"2025-12-13T09:46:02.906572Z","iopub.status.idle":"2025-12-13T09:46:02.916555Z","shell.execute_reply.started":"2025-12-13T09:46:02.906554Z","shell.execute_reply":"2025-12-13T09:46:02.915686Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# features = features.view(512)\n# features.shape\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.917462Z","iopub.execute_input":"2025-12-13T09:46:02.917716Z","iopub.status.idle":"2025-12-13T09:46:02.927483Z","shell.execute_reply.started":"2025-12-13T09:46:02.917691Z","shell.execute_reply":"2025-12-13T09:46:02.926743Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import numpy as np\n# import torch\n# from PIL import Image\n\n# # (Assumes you already created: feature_extractor, transform, total_df)\n\n# def extract_resnet_features(image_path: str) -> np.ndarray:\n#     img = Image.open(image_path).convert(\"RGB\")\n#     x = transform(img).unsqueeze(0)  # (1, 3, 224, 224)\n#     with torch.no_grad():\n#         feat = feature_extractor(x)  # (1, 512, 1, 1)\n#     feat = feat.view(-1).cpu().numpy()  # (512,)\n#     return feat\n\n# X_feat = []\n# y = []\n\n# for _, row in total_df.iterrows():\n#     full_path = \"/kaggle/input/csiro-biomass/\" + row[\"image_path\"]\n#     X_feat.append(extract_resnet_features(full_path))\n#     y.append(row[\"target\"])\n\n# X_feat = np.vstack(X_feat)  # (357, 512)\n# y = np.array(y)             # (357,)\n\n# X_feat.shape, y.shape\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.928472Z","iopub.execute_input":"2025-12-13T09:46:02.928753Z","iopub.status.idle":"2025-12-13T09:46:02.940048Z","shell.execute_reply.started":"2025-12-13T09:46:02.928727Z","shell.execute_reply":"2025-12-13T09:46:02.939380Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# from sklearn.model_selection import train_test_split\n# from sklearn.linear_model import Ridge\n# from sklearn.metrics import mean_squared_error\n\n# X_train, X_val, y_train, y_val = train_test_split(\n#     X_feat, y, test_size=0.2, random_state=42\n# )\n\n# model = Ridge(alpha=1.0)  # Ridge is a safer default than plain LinearRegression with many features\n# model.fit(X_train, y_train)\n\n# preds = model.predict(X_val)\n# rmse = np.sqrt(mean_squared_error(y_val, preds))\n# rmse\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.940973Z","iopub.execute_input":"2025-12-13T09:46:02.941310Z","iopub.status.idle":"2025-12-13T09:46:02.954331Z","shell.execute_reply.started":"2025-12-13T09:46:02.941267Z","shell.execute_reply":"2025-12-13T09:46:02.953468Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import numpy as np\n# from sklearn.model_selection import train_test_split\n# from sklearn.pipeline import Pipeline\n# from sklearn.preprocessing import StandardScaler\n# from sklearn.linear_model import Ridge\n# from sklearn.metrics import mean_squared_error\n\n# # 1) Build metadata matrix aligned with total_df rows (same order as your X_feat + y loop)\n# X_meta = total_df[[\"Height_Ave_cm\", \"Pre_GSHH_NDVI\"]].to_numpy()\n\n# # 2) Concatenate: (357, 512) + (357, 2) -> (357, 514)\n# X_hybrid = np.hstack([X_feat, X_meta])\n\n# # 3) Split\n# X_train, X_val, y_train, y_val = train_test_split(\n#     X_hybrid, y, test_size=0.2, random_state=42\n# )\n\n# # 4) Scale + Ridge (scaling helps because metadata and CNN features live on different scales)\n# model = Pipeline([\n#     (\"scaler\", StandardScaler()),\n#     (\"ridge\", Ridge(alpha=10.0))\n# ])\n\n# model.fit(X_train, y_train)\n# preds = model.predict(X_val)\n\n# rmse = np.sqrt(mean_squared_error(y_val, preds))\n# rmse\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.955361Z","iopub.execute_input":"2025-12-13T09:46:02.955906Z","iopub.status.idle":"2025-12-13T09:46:02.966018Z","shell.execute_reply.started":"2025-12-13T09:46:02.955876Z","shell.execute_reply":"2025-12-13T09:46:02.965193Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Implement a Grouped Validation Split (by State)\n# from sklearn.model_selection import GroupShuffleSplit\n\n# total_df = train_df[train_df[\"target_name\"] == \"Dry_Total_g\"]\n\n# X = total_df[[\"Height_Ave_cm\", \"Pre_GSHH_NDVI\"]]\n# y = total_df[\"target\"]\n# groups = total_df[\"State\"]\n\n# gss = GroupShuffleSplit(\n#     n_splits=1,\n#     test_size=0.2,\n#     random_state=42\n# )\n\n# train_idx, val_idx = next(gss.split(X, y, groups))\n\n# X_train, X_val = X.iloc[train_idx], X.iloc[val_idx]\n# y_train, y_val = y.iloc[train_idx], y.iloc[val_idx]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.967002Z","iopub.execute_input":"2025-12-13T09:46:02.967217Z","iopub.status.idle":"2025-12-13T09:46:02.979084Z","shell.execute_reply.started":"2025-12-13T09:46:02.967193Z","shell.execute_reply":"2025-12-13T09:46:02.978272Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# from sklearn.linear_model import LinearRegression\n# from sklearn.metrics import mean_squared_error\n# import numpy as np\n\n# lr = LinearRegression()\n# lr.fit(X_train, y_train)\n\n# preds = lr.predict(X_val)\n# rmse = np.sqrt(mean_squared_error(y_val, preds))\n# rmse\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.979890Z","iopub.execute_input":"2025-12-13T09:46:02.980211Z","iopub.status.idle":"2025-12-13T09:46:02.990106Z","shell.execute_reply.started":"2025-12-13T09:46:02.980172Z","shell.execute_reply":"2025-12-13T09:46:02.989335Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Adding species\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.linear_model import Ridge\nfrom sklearn.metrics import mean_squared_error\nfrom sklearn.model_selection import GroupShuffleSplit\nimport numpy as np\n\ntotal_df = train_df[train_df[\"target_name\"] == \"Dry_Total_g\"]\n\nX = total_df[[\"Height_Ave_cm\", \"Pre_GSHH_NDVI\", \"Species\"]]\ny = total_df[\"target\"]\ngroups = total_df[\"State\"]\n\npreprocess = ColumnTransformer(\n    transformers=[\n        (\"num\", \"passthrough\", [\"Height_Ave_cm\", \"Pre_GSHH_NDVI\"]),\n        (\"cat\", OneHotEncoder(handle_unknown=\"ignore\"), [\"Species\"]),\n    ]\n)\n\nmodel = Pipeline([\n    (\"prep\", preprocess),\n    (\"ridge\", Ridge(alpha=10.0, solver=\"lsqr\"))\n])\n\ngss = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=42)\ntrain_idx, val_idx = next(gss.split(X, y, groups))\n\nmodel.fit(X.iloc[train_idx], y.iloc[train_idx])\npreds = model.predict(X.iloc[val_idx])\n\nrmse = np.sqrt(mean_squared_error(y.iloc[val_idx], preds))\nrmse\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:02.990737Z","iopub.execute_input":"2025-12-13T09:46:02.990997Z","iopub.status.idle":"2025-12-13T09:46:03.019945Z","shell.execute_reply.started":"2025-12-13T09:46:02.990979Z","shell.execute_reply":"2025-12-13T09:46:03.019171Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Add State\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.linear_model import Ridge\nfrom sklearn.metrics import mean_squared_error\nfrom sklearn.model_selection import GroupShuffleSplit\nimport numpy as np\n\ntotal_df = train_df[train_df[\"target_name\"] == \"Dry_Total_g\"]\n\nX = total_df[[\"Height_Ave_cm\", \"Pre_GSHH_NDVI\", \"Species\", \"State\"]]\ny = total_df[\"target\"]\ngroups = total_df[\"State\"]\n\npreprocess = ColumnTransformer(\n    transformers=[\n        (\"num\", \"passthrough\", [\"Height_Ave_cm\", \"Pre_GSHH_NDVI\"]),\n        (\"cat\", OneHotEncoder(handle_unknown=\"ignore\"), [\"Species\", \"State\"]),\n    ]\n)\n\nmodel = Pipeline([\n    (\"prep\", preprocess),\n    (\"ridge\", Ridge(alpha=10.0, solver=\"lsqr\"))\n])\n\ngss = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=42)\ntrain_idx, val_idx = next(gss.split(X, y, groups))\n\nmodel.fit(X.iloc[train_idx], y.iloc[train_idx])\npreds = model.predict(X.iloc[val_idx])\n\nrmse = np.sqrt(mean_squared_error(y.iloc[val_idx], preds))\nrmse\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:03.020731Z","iopub.execute_input":"2025-12-13T09:46:03.021242Z","iopub.status.idle":"2025-12-13T09:46:03.046119Z","shell.execute_reply.started":"2025-12-13T09:46:03.021208Z","shell.execute_reply":"2025-12-13T09:46:03.045351Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Train with a log target\nimport numpy as np\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.linear_model import Ridge\nfrom sklearn.metrics import mean_squared_error\nfrom sklearn.model_selection import GroupShuffleSplit\n\ntotal_df = train_df[train_df[\"target_name\"] == \"Dry_Total_g\"]\n\nX = total_df[[\"Height_Ave_cm\", \"Pre_GSHH_NDVI\", \"Species\", \"State\"]]\ny = total_df[\"target\"]\ny_log = np.log1p(y)  # log(target + 1)\ngroups = total_df[\"State\"]\n\npreprocess = ColumnTransformer(\n    transformers=[\n        (\"num\", \"passthrough\", [\"Height_Ave_cm\", \"Pre_GSHH_NDVI\"]),\n        (\"cat\", OneHotEncoder(handle_unknown=\"ignore\"), [\"Species\", \"State\"]),\n    ]\n)\n\nmodel = Pipeline([\n    (\"prep\", preprocess),\n    (\"ridge\", Ridge(alpha=10.0, solver=\"lsqr\"))\n])\n\ngss = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=42)\ntrain_idx, val_idx = next(gss.split(X, y_log, groups))\n\nmodel.fit(X.iloc[train_idx], y_log.iloc[train_idx])\n\n# predict in log-space\npreds_log = model.predict(X.iloc[val_idx])\n\n# convert back to grams\npreds = np.expm1(preds_log)\n\nrmse = np.sqrt(mean_squared_error(y.iloc[val_idx], preds))\nrmse\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:03.046953Z","iopub.execute_input":"2025-12-13T09:46:03.047154Z","iopub.status.idle":"2025-12-13T09:46:03.072695Z","shell.execute_reply.started":"2025-12-13T09:46:03.047137Z","shell.execute_reply":"2025-12-13T09:46:03.071982Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Gradient boosting on tabular data\nimport numpy as np\nfrom sklearn.model_selection import GroupShuffleSplit\nfrom sklearn.preprocessing import OrdinalEncoder\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.metrics import mean_squared_error\nfrom sklearn.ensemble import HistGradientBoostingRegressor\n\ntotal_df = train_df[train_df[\"target_name\"] == \"Dry_Total_g\"]\n\nX = total_df[[\"Height_Ave_cm\", \"Pre_GSHH_NDVI\", \"Species\", \"State\"]]\ny = total_df[\"target\"]\ngroups = total_df[\"State\"]\n\npreprocess = ColumnTransformer(\n    transformers=[\n        (\"num\", \"passthrough\", [\"Height_Ave_cm\", \"Pre_GSHH_NDVI\"]),\n        (\"cat\", OrdinalEncoder(handle_unknown=\"use_encoded_value\", unknown_value=-1),\n         [\"Species\", \"State\"]),\n    ]\n)\n\nmodel = Pipeline([\n    (\"prep\", preprocess),\n    (\"gb\", HistGradientBoostingRegressor(\n        max_depth=6,\n        learning_rate=0.05,\n        max_iter=500,\n        random_state=42\n    ))\n])\n\ngss = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=42)\ntrain_idx, val_idx = next(gss.split(X, y, groups))\n\nmodel.fit(X.iloc[train_idx], y.iloc[train_idx])\npreds = model.predict(X.iloc[val_idx])\n\nrmse = np.sqrt(mean_squared_error(y.iloc[val_idx], preds))\nrmse\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:03.073546Z","iopub.execute_input":"2025-12-13T09:46:03.074282Z","iopub.status.idle":"2025-12-13T09:46:03.651658Z","shell.execute_reply.started":"2025-12-13T09:46:03.074225Z","shell.execute_reply":"2025-12-13T09:46:03.651039Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df = pd.read_csv(\"/kaggle/input/csiro-biomass/test.csv\")\ntest_df.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:03.652201Z","iopub.execute_input":"2025-12-13T09:46:03.652406Z","iopub.status.idle":"2025-12-13T09:46:03.662709Z","shell.execute_reply.started":"2025-12-13T09:46:03.652386Z","shell.execute_reply":"2025-12-13T09:46:03.662128Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# sub = pd.read_csv(\"/kaggle/input/csiro-biomass/sample_submission.csv\")\n# sub.head(), sub.shape\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:03.663155Z","iopub.execute_input":"2025-12-13T09:46:03.663361Z","iopub.status.idle":"2025-12-13T09:46:03.672540Z","shell.execute_reply.started":"2025-12-13T09:46:03.663343Z","shell.execute_reply":"2025-12-13T09:46:03.671759Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.compose import ColumnTransformer\nfrom sklearn.preprocessing import OrdinalEncoder\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.ensemble import HistGradientBoostingRegressor\n\n# training data\ntrain_total = train_df[train_df[\"target_name\"] == \"Dry_Total_g\"]\n\nX_train = train_total[[\"Height_Ave_cm\", \"Pre_GSHH_NDVI\", \"Species\", \"State\"]]\ny_train = train_total[\"target\"]\n\npreprocess = ColumnTransformer(\n    transformers=[\n        (\"num\", \"passthrough\", [\"Height_Ave_cm\", \"Pre_GSHH_NDVI\"]),\n        (\"cat\", OrdinalEncoder(handle_unknown=\"use_encoded_value\", unknown_value=-1),\n         [\"Species\", \"State\"]),\n    ]\n)\n\nfinal_model = Pipeline([\n    (\"prep\", preprocess),\n    (\"gb\", HistGradientBoostingRegressor(\n        max_depth=6,\n        learning_rate=0.05,\n        max_iter=500,\n        random_state=42\n    ))\n])\n\nfinal_model.fit(X_train, y_train)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:03.672964Z","iopub.execute_input":"2025-12-13T09:46:03.673807Z","iopub.status.idle":"2025-12-13T09:46:04.262787Z","shell.execute_reply.started":"2025-12-13T09:46:03.673786Z","shell.execute_reply":"2025-12-13T09:46:04.261907Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# test data\ntest_df = pd.read_csv(\"/kaggle/input/csiro-biomass/test.csv\")\n\ntest_total = test_df[test_df[\"target_name\"] == \"Dry_Total_g\"]\n\nX_test = test_total.merge(\n    train_total[[\"image_path\", \"Height_Ave_cm\", \"Pre_GSHH_NDVI\", \"Species\", \"State\"]],\n    on=\"image_path\",\n    how=\"left\"\n)[[\"Height_Ave_cm\", \"Pre_GSHH_NDVI\", \"Species\", \"State\"]]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:04.263793Z","iopub.execute_input":"2025-12-13T09:46:04.264091Z","iopub.status.idle":"2025-12-13T09:46:04.274393Z","shell.execute_reply.started":"2025-12-13T09:46:04.264051Z","shell.execute_reply":"2025-12-13T09:46:04.273513Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dry_total_preds = final_model.predict(X_test)\n\ndry_total_map = dict(zip(test_total[\"image_path\"], dry_total_preds))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:04.275376Z","iopub.execute_input":"2025-12-13T09:46:04.275740Z","iopub.status.idle":"2025-12-13T09:46:04.302728Z","shell.execute_reply.started":"2025-12-13T09:46:04.275712Z","shell.execute_reply":"2025-12-13T09:46:04.302022Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================\n# Train GDM_g model\n# ============================\n\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.preprocessing import OrdinalEncoder\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.ensemble import HistGradientBoostingRegressor\n\ntrain_gdm = train_df[train_df[\"target_name\"] == \"GDM_g\"].copy()\n\nX_train_gdm = train_gdm[[\"Height_Ave_cm\", \"Pre_GSHH_NDVI\", \"Species\", \"State\"]]\ny_train_gdm = train_gdm[\"target\"]\n\npreprocess_gdm = ColumnTransformer(\n    transformers=[\n        (\"num\", \"passthrough\", [\"Height_Ave_cm\", \"Pre_GSHH_NDVI\"]),\n        (\"cat\", OrdinalEncoder(handle_unknown=\"use_encoded_value\", unknown_value=-1), [\"Species\", \"State\"]),\n    ]\n)\n\ngdm_model = Pipeline([\n    (\"prep\", preprocess_gdm),\n    (\"gb\", HistGradientBoostingRegressor(\n        max_depth=6,\n        learning_rate=0.05,\n        max_iter=500,\n        random_state=42\n    ))\n])\n\ngdm_model.fit(X_train_gdm, y_train_gdm)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:04.303591Z","iopub.execute_input":"2025-12-13T09:46:04.304552Z","iopub.status.idle":"2025-12-13T09:46:05.039288Z","shell.execute_reply.started":"2025-12-13T09:46:04.304522Z","shell.execute_reply":"2025-12-13T09:46:05.038585Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================\n# Predict GDM_g on test\n# ============================\n\ntest_gdm = test_df[test_df[\"target_name\"] == \"GDM_g\"].merge(img_meta, on=\"image_path\", how=\"left\")\nX_test_gdm = test_gdm[[\"Height_Ave_cm\", \"Pre_GSHH_NDVI\", \"Species\", \"State\"]]\n\ngdm_preds = gdm_model.predict(X_test_gdm)\ngdm_pred_map = dict(zip(test_gdm[\"sample_id\"], gdm_preds))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:05.039863Z","iopub.execute_input":"2025-12-13T09:46:05.040147Z","iopub.status.idle":"2025-12-13T09:46:05.062234Z","shell.execute_reply.started":"2025-12-13T09:46:05.040128Z","shell.execute_reply":"2025-12-13T09:46:05.061748Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def fill_target(row):\n    total = dry_total_map[row[\"image_path\"]]\n    name = row[\"target_name\"]\n\n    if name == \"Dry_Total_g\":\n        return total\n    elif name == \"Dry_Green_g\":\n        return total * 0.6\n    elif name == \"Dry_Dead_g\":\n        return total * 0.3\n    elif name == \"Dry_Clover_g\":\n        return total * 0.1\n    elif name == \"GDM_g\":\n        return gdm_pred_map[row[\"sample_id\"]]\n    else:\n        return 0.0\n\nsubmission = test_df.copy()\nsubmission[\"target\"] = submission.apply(fill_target, axis=1)\n\nsubmission = submission[[\"sample_id\", \"target\"]]\nsubmission.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:05.062650Z","iopub.execute_input":"2025-12-13T09:46:05.062816Z","iopub.status.idle":"2025-12-13T09:46:05.074690Z","shell.execute_reply.started":"2025-12-13T09:46:05.062801Z","shell.execute_reply":"2025-12-13T09:46:05.074126Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(dry_total_map), len(gdm_pred_map)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:05.075666Z","iopub.execute_input":"2025-12-13T09:46:05.076237Z","iopub.status.idle":"2025-12-13T09:46:05.086339Z","shell.execute_reply.started":"2025-12-13T09:46:05.076200Z","shell.execute_reply":"2025-12-13T09:46:05.085449Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Local validation","metadata":{}},{"cell_type":"code","source":"# from sklearn.model_selection import GroupShuffleSplit\n# from sklearn.metrics import r2_score\n# from sklearn.compose import ColumnTransformer\n# from sklearn.preprocessing import OrdinalEncoder\n# from sklearn.pipeline import Pipeline\n# from sklearn.ensemble import HistGradientBoostingRegressor\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:05.087043Z","iopub.execute_input":"2025-12-13T09:46:05.087238Z","iopub.status.idle":"2025-12-13T09:46:05.095779Z","shell.execute_reply.started":"2025-12-13T09:46:05.087217Z","shell.execute_reply":"2025-12-13T09:46:05.094782Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Split by image (no leakage)\n# gss = GroupShuffleSplit(n_splits=1, test_size=0.2, random_state=42)\n# train_idx, val_idx = next(\n#     gss.split(train_df, groups=train_df[\"image_path\"])\n# )\n\n# train_split = train_df.iloc[train_idx]\n# val_split   = train_df.iloc[val_idx]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:05.096642Z","iopub.execute_input":"2025-12-13T09:46:05.096877Z","iopub.status.idle":"2025-12-13T09:46:05.111722Z","shell.execute_reply.started":"2025-12-13T09:46:05.096856Z","shell.execute_reply":"2025-12-13T09:46:05.110914Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# FEATURES = [\"Height_Ave_cm\", \"Pre_GSHH_NDVI\", \"Species\", \"State\"]\n\n# def train_and_predict(train_df, val_df, target_name):\n#     train_t = train_df[train_df[\"target_name\"] == target_name]\n#     val_t   = val_df[val_df[\"target_name\"] == target_name]\n\n#     X_train = train_t[FEATURES]\n#     y_train = train_t[\"target\"]\n#     X_val   = val_t[FEATURES]\n#     y_val   = val_t[\"target\"]\n\n#     preprocess = ColumnTransformer(\n#         transformers=[\n#             (\"num\", \"passthrough\", [\"Height_Ave_cm\", \"Pre_GSHH_NDVI\"]),\n#             (\"cat\", OrdinalEncoder(handle_unknown=\"use_encoded_value\", unknown_value=-1),\n#              [\"Species\", \"State\"]),\n#         ]\n#     )\n\n#     model = Pipeline([\n#         (\"prep\", preprocess),\n#         (\"gb\", HistGradientBoostingRegressor(\n#             max_depth=6,\n#             learning_rate=0.05,\n#             max_iter=500,\n#             random_state=42\n#         ))\n#     ])\n\n#     model.fit(X_train, y_train)\n#     preds = model.predict(X_val)\n\n#     return y_val.values, preds\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:05.112604Z","iopub.execute_input":"2025-12-13T09:46:05.112881Z","iopub.status.idle":"2025-12-13T09:46:05.119774Z","shell.execute_reply.started":"2025-12-13T09:46:05.112851Z","shell.execute_reply":"2025-12-13T09:46:05.118897Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# weights = {\n#     \"Dry_Total_g\": 0.5,\n#     \"GDM_g\": 0.2,\n#     \"Dry_Green_g\": 0.1,\n#     \"Dry_Dead_g\": 0.1,\n#     \"Dry_Clover_g\": 0.1,\n# }\n\n# r2_per_target = {}\n# weighted_r2 = 0.0\n\n# for target, w in weights.items():\n#     y_true, y_pred = train_and_predict(train_split, val_split, target)\n#     r2 = r2_score(y_true, y_pred)\n#     r2_per_target[target] = r2\n#     weighted_r2 += w * r2\n\n# r2_per_target, weighted_r2\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:05.120475Z","iopub.execute_input":"2025-12-13T09:46:05.120711Z","iopub.status.idle":"2025-12-13T09:46:05.131121Z","shell.execute_reply.started":"2025-12-13T09:46:05.120677Z","shell.execute_reply":"2025-12-13T09:46:05.130445Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission.to_csv(\"submission.csv\", index=False)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-13T09:46:05.131810Z","iopub.execute_input":"2025-12-13T09:46:05.132076Z","iopub.status.idle":"2025-12-13T09:46:05.143877Z","shell.execute_reply.started":"2025-12-13T09:46:05.132051Z","shell.execute_reply":"2025-12-13T09:46:05.143236Z"}},"outputs":[],"execution_count":null}]}