{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":64733,"databundleVersionId":8171035,"sourceType":"competition"}],"dockerImageVersionId":30674,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Introduction\n\nIn this notebook, a quickstart method will be presented in order to make predictions on most common species in each region with XGBoost.\n\nWe won't use satellite images, time series and presence-only data in this notebook, in order to provide a quickstart only for these challenge.\n\nWe will follow these different steps :\n\n* [Import and merge data files](#import-data)\n* [Data Preparation](#data-preparation)\n    - [Filter regions and rarest species](#filter-data)\n    - [Regroup all species by survey](#regroup-species)\n    - [Preprocess NaN, inf, data type](#preprocess)\n* [Models training and predict on test](#train-predict)\n* [Submission](#submission)\n\nCredits to @debain, @thuymytrg, @nicolaspedrosa and @ruskakeouda for working with me on this challenge. ","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd \nimport os\nimport gc\n\nfrom sklearn.preprocessing import MultiLabelBinarizer\nfrom xgboost import XGBClassifier\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-04-15T19:56:04.614168Z","iopub.execute_input":"2024-04-15T19:56:04.61522Z","iopub.status.idle":"2024-04-15T19:56:04.623128Z","shell.execute_reply.started":"2024-04-15T19:56:04.615165Z","shell.execute_reply":"2024-04-15T19:56:04.621797Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"import-data\"></a>\n# Import Data ","metadata":{}},{"cell_type":"code","source":"path = \"/kaggle/input/geolifeclef-2024/\"\n\ntrain = pd.read_csv(path +\"GLC24_PA_metadata_train.csv\")\ntest = pd.read_csv(path+\"GLC24_PA_metadata_test.csv\")\n\nelevation_train = pd.read_csv(path+\"EnvironmentalRasters/EnvironmentalRasters/Elevation/GLC24-PA-train-elevation.csv\")\nelevation_test = pd.read_csv(path+\"EnvironmentalRasters/EnvironmentalRasters/Elevation/GLC24-PA-test-elevation.csv\")\n\nhuman_footprint_train = pd.read_csv(path+\"EnvironmentalRasters/EnvironmentalRasters/Human Footprint/GLC24-PA-train-human_footprint.csv\")\nhuman_footprint_test = pd.read_csv(path+\"EnvironmentalRasters/EnvironmentalRasters/Human Footprint/GLC24-PA-test-human_footprint.csv\")\n\nlandcover_test = pd.read_csv(path+\"EnvironmentalRasters/EnvironmentalRasters/LandCover/GLC24-PA-test-landcover.csv\")\nlandcover_train = pd.read_csv(path+\"EnvironmentalRasters/EnvironmentalRasters/LandCover/GLC24-PA-train-landcover.csv\")\n\nsoilgrids_test = pd.read_csv(path+\"EnvironmentalRasters/EnvironmentalRasters/SoilGrids/GLC24-PA-test-soilgrids.csv\")\nsoilgrids_train = pd.read_csv(path+\"EnvironmentalRasters/EnvironmentalRasters/SoilGrids/GLC24-PA-train-soilgrids.csv\")\n\nprint(train.shape)\nfor dataset in [elevation_train, human_footprint_train, landcover_train, soilgrids_train]:\n    train = pd.merge(train, dataset, how = \"left\", left_on = \"surveyId\", right_on = \"surveyId\")\n    print(train.shape)\n    del dataset\n    \nprint(test.shape)\nfor dataset in [elevation_test, human_footprint_test, landcover_test, soilgrids_test]:\n    test = pd.merge(test, dataset, how = \"left\", left_on = \"surveyId\", right_on = \"surveyId\")\n    print(test.shape)\n    del dataset\n    \n\n_ = gc.collect()","metadata":{"execution":{"iopub.status.busy":"2024-04-15T20:00:18.350541Z","iopub.execute_input":"2024-04-15T20:00:18.351117Z","iopub.status.idle":"2024-04-15T20:00:22.126818Z","shell.execute_reply.started":"2024-04-15T20:00:18.351076Z","shell.execute_reply":"2024-04-15T20:00:22.125655Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"data-preparation\"></a>\n# Data Preparation","metadata":{}},{"cell_type":"markdown","source":"<a id=\"filter-data\"></a>\n## Filter regions and rarest species","metadata":{}},{"cell_type":"code","source":"#If the region is not in test, we drop it\nprint(train.shape)\ntrain = train[train[\"region\"].isin(test[\"region\"].unique())]\nprint(train.shape)","metadata":{"execution":{"iopub.status.busy":"2024-04-15T20:00:22.129233Z","iopub.execute_input":"2024-04-15T20:00:22.129902Z","iopub.status.idle":"2024-04-15T20:00:22.459837Z","shell.execute_reply.started":"2024-04-15T20:00:22.129859Z","shell.execute_reply":"2024-04-15T20:00:22.458357Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Filter ","metadata":{}},{"cell_type":"code","source":"NB_SPECIES_TO_KEEP = 1000 # Choose the number of most present species you want to keep in each region\n\nprint(train.shape)\nspecies_to_keep = {}\n\nfor region in train[\"region\"].unique():\n    species_to_keep[region] = list(train[train[\"region\"] == region][\"speciesId\"].value_counts().index[:NB_SPECIES_TO_KEEP])\n    \ntrain = train[train.apply(lambda row: row['speciesId'] in species_to_keep[row['region']], axis=1)]\nprint(train.shape)","metadata":{"execution":{"iopub.status.busy":"2024-04-15T20:00:22.461589Z","iopub.execute_input":"2024-04-15T20:00:22.462062Z","iopub.status.idle":"2024-04-15T20:00:54.895196Z","shell.execute_reply.started":"2024-04-15T20:00:22.462018Z","shell.execute_reply":"2024-04-15T20:00:54.893914Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"regroup-species\"></a>\n## Regroup all species by survey","metadata":{}},{"cell_type":"code","source":"dict_groupby = {k:[\"first\"] for k in train.columns.drop([\"speciesId\", \"surveyId\"])} \ndict_groupby[\"speciesId\"] = [list]\n\ntrain[\"speciesId\"] = train[\"speciesId\"].astype(int)\ntrain = train.groupby(\"surveyId\").agg(dict_groupby).reset_index()\ntrain.columns = [x[0] for x in train.columns]\nprint(train.shape)\n\ntrain[\"speciesId\"] = train[\"speciesId\"].apply(lambda x : list(set(x)))\ntrain.head(2)","metadata":{"execution":{"iopub.status.busy":"2024-04-15T20:00:54.898081Z","iopub.execute_input":"2024-04-15T20:00:54.89847Z","iopub.status.idle":"2024-04-15T20:00:57.548738Z","shell.execute_reply.started":"2024-04-15T20:00:54.898439Z","shell.execute_reply":"2024-04-15T20:00:57.547488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"preprocess\"></a>\n## Preprocess NaN, inf, data type","metadata":{}},{"cell_type":"code","source":"pd.set_option('mode.use_inf_as_na', True)\n\ndef preprocess(df_to_preprocess:pd.DataFrame) -> pd.DataFrame:\n\n    df = df_to_preprocess.copy()\n    df['geoUncertaintyInM']  = df['geoUncertaintyInM'].fillna(df['geoUncertaintyInM'].mode()[0])\n    df['areaInM2'] = df['areaInM2'].fillna(df['areaInM2'].mean())\n    df['Elevation'] = df['Elevation'].fillna(df['Elevation'].mode()[0])\n\n    for column in df.filter(regex='HumanFootprint').columns:\n        df[column] = df[column].fillna(df[column].mean())\n\n    for column in df.filter(regex='Soilgrid').columns:\n        df[column] = df[column].fillna(df[column].mode()[0])\n\n    columns_to_convert =['Elevation','geoUncertaintyInM','HumanFootprint-Pasture1993', 'HumanFootprint-Pasture2009']\n\n    df[columns_to_convert] = df[columns_to_convert].astype(int)\n\n    for name,values in df.filter(regex='Soilgrid').items():\n        df[name] = df[name].astype(int)\n    \n    df[\"surveyId\"]=df[\"surveyId\"].astype(int).astype(str)\n    \n    df.drop(\"country\", axis = 1, inplace = True)\n    \n    df.fillna(0, inplace = True)\n        \n    return df\n\n\ntrain = preprocess(train)\ntest = preprocess(test)","metadata":{"execution":{"iopub.status.busy":"2024-04-15T20:00:57.562838Z","iopub.execute_input":"2024-04-15T20:00:57.563634Z","iopub.status.idle":"2024-04-15T20:00:57.632542Z","shell.execute_reply.started":"2024-04-15T20:00:57.563591Z","shell.execute_reply":"2024-04-15T20:00:57.631317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"train-predict\"></a>\n# Models training and predict on test\n\nTraining one model for each region, and predicting top K number of species, K being the mean number of species observed in each region.","metadata":{}},{"cell_type":"code","source":"%%time\n\nsubmission = pd.DataFrame()\n\n# Train one model per region\nfor region in train[\"region\"].unique():\n    \n    print(f\"Training model for region {region}\")\n\n    # Select train and test data corresponding to the current region\n    X_train = train[train[\"region\"] == region].copy().set_index(\"surveyId\")\n    nb_mean_species = int(np.round(X_train[\"speciesId\"].apply(lambda x : len(x)).mean(),0))\n    print(\"Train set size :\",X_train.shape)\n    print(\"Number of species to predict :\",nb_mean_species)\n\n    X_test = test[test[\"region\"] == region].copy().set_index(\"surveyId\")\n    X_test.drop(\"region\", axis =1, inplace = True)\n    \n    #Label encoding\n    mlb = MultiLabelBinarizer()\n\n    y_train = pd.DataFrame(mlb.fit_transform(X_train[\"speciesId\"]),\n                       columns=mlb.classes_,\n                       index=X_train.index)\n\n    X_train.drop([\"speciesId\", \"region\"], axis = 1, inplace = True)\n    X_test = X_test[X_train.columns]\n    \n    #Hyperparameters could be optimized depending on the region\n    xgb_params = {\n        'objective' : 'binary:logistic',\n        'eval_metric' : 'logloss',\n        'colsample_bytree': 0.8,\n        'learning_rate': 0.1,\n        'max_depth': 9,\n        'n_estimators': 1000,\n        'reg_alpha': 0.2,\n        'reg_lambda': 0.8,\n        'tree_method':'hist',\n        'device' : 'gpu:0' #comment this line if not using GPU, or select good GPU\n    }\n\n    model = XGBClassifier(**xgb_params)\n\n    %time model.fit(X_train, y_train)  \n    \n    # Predict probabilities to select top-k species\n    proba_predictions = model.predict_proba(X_test)\n    classes = mlb.classes_\n\n    top_k_species = pd.DataFrame(data=proba_predictions,\n                                  index=X_test.index,\n                                  columns=classes).apply(lambda x: pd.Series(x.nlargest(nb_mean_species).index), axis=1)\n    \n    # Add predictions to submission dataframe\n    submission = pd.concat([submission, top_k_species])\n\n\n    # Free memory\n    del model\n    del X_train, X_test, y_train, top_k_species, proba_predictions\n\n    _ = gc.collect()\n    \n    print(\"_\"*25)\n    print(\"\\n\")","metadata":{"execution":{"iopub.status.busy":"2024-04-15T20:00:57.634507Z","iopub.execute_input":"2024-04-15T20:00:57.634975Z","iopub.status.idle":"2024-04-15T20:01:21.331759Z","shell.execute_reply.started":"2024-04-15T20:00:57.634925Z","shell.execute_reply":"2024-04-15T20:01:21.330621Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"submission\"></a>\n# Submission","metadata":{}},{"cell_type":"code","source":"#Submit predictions with good format\n\nsubmission[\"predictions\"] = submission.apply(lambda row : \" \".join([str(x)[:-2] if str(x) != \"nan\" else \"\" for x in row[submission.columns]] ), axis = 1)\nsubmission[\"predictions\"].to_csv(\"submission.csv\", index = True)","metadata":{"execution":{"iopub.status.busy":"2024-04-15T20:01:21.333257Z","iopub.execute_input":"2024-04-15T20:01:21.333696Z","iopub.status.idle":"2024-04-15T20:01:22.163056Z","shell.execute_reply.started":"2024-04-15T20:01:21.333666Z","shell.execute_reply":"2024-04-15T20:01:22.161858Z"},"trusted":true},"execution_count":null,"outputs":[]}]}