{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "provenance": [], "collapsed_sections": [ "luqH7PMl80hy", "BT1Fp01I-ISr", "n8yGi7OABaei", "v-SpYmGFEBRr", "kI_5u0llep1G", "1RzdTyHNFnel" ] }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" } }, "cells": [ { "cell_type": "markdown", "source": [ "# Import Library" ], "metadata": { "id": "DMzp0DiY2e9T" } }, { "cell_type": "code", "source": [ "!pip install category_encoders\n", "!pip install scikit-optimize\n", "\n", "!pip install lightgbm\n", "!pip install catboost" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "p3O5kze8B5mY", "outputId": "a948a59e-ef3c-4842-ffd8-ef5d0563d3fd" }, "execution_count": 45, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Requirement already satisfied: category_encoders in /usr/local/lib/python3.11/dist-packages (2.8.1)\n", "Requirement already satisfied: numpy>=1.14.0 in /usr/local/lib/python3.11/dist-packages (from category_encoders) (2.0.2)\n", "Requirement already satisfied: pandas>=1.0.5 in /usr/local/lib/python3.11/dist-packages (from category_encoders) (2.2.2)\n", "Requirement already satisfied: patsy>=0.5.1 in /usr/local/lib/python3.11/dist-packages (from category_encoders) (1.0.1)\n", "Requirement already satisfied: scikit-learn>=1.6.0 in /usr/local/lib/python3.11/dist-packages (from category_encoders) (1.6.1)\n", "Requirement already satisfied: scipy>=1.0.0 in /usr/local/lib/python3.11/dist-packages (from category_encoders) (1.15.3)\n", "Requirement already satisfied: statsmodels>=0.9.0 in /usr/local/lib/python3.11/dist-packages (from category_encoders) (0.14.4)\n", "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/dist-packages (from pandas>=1.0.5->category_encoders) (2.9.0.post0)\n", "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas>=1.0.5->category_encoders) (2025.2)\n", "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas>=1.0.5->category_encoders) (2025.2)\n", "Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.6.0->category_encoders) (1.5.1)\n", "Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.6.0->category_encoders) (3.6.0)\n", "Requirement already satisfied: packaging>=21.3 in /usr/local/lib/python3.11/dist-packages (from statsmodels>=0.9.0->category_encoders) (24.2)\n", "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.8.2->pandas>=1.0.5->category_encoders) (1.17.0)\n", "Requirement already satisfied: scikit-optimize in /usr/local/lib/python3.11/dist-packages (0.10.2)\n", "Requirement already satisfied: joblib>=0.11 in /usr/local/lib/python3.11/dist-packages (from scikit-optimize) (1.5.1)\n", "Requirement already satisfied: pyaml>=16.9 in /usr/local/lib/python3.11/dist-packages (from scikit-optimize) (25.5.0)\n", "Requirement already satisfied: numpy>=1.20.3 in /usr/local/lib/python3.11/dist-packages (from scikit-optimize) (2.0.2)\n", "Requirement already satisfied: scipy>=1.1.0 in /usr/local/lib/python3.11/dist-packages (from scikit-optimize) (1.15.3)\n", "Requirement already satisfied: scikit-learn>=1.0.0 in /usr/local/lib/python3.11/dist-packages (from scikit-optimize) (1.6.1)\n", "Requirement already satisfied: packaging>=21.3 in /usr/local/lib/python3.11/dist-packages (from scikit-optimize) (24.2)\n", "Requirement already satisfied: PyYAML in /usr/local/lib/python3.11/dist-packages (from pyaml>=16.9->scikit-optimize) (6.0.2)\n", "Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.11/dist-packages (from scikit-learn>=1.0.0->scikit-optimize) (3.6.0)\n", "Requirement already satisfied: lightgbm in /usr/local/lib/python3.11/dist-packages (4.5.0)\n", "Requirement already satisfied: numpy>=1.17.0 in /usr/local/lib/python3.11/dist-packages (from lightgbm) (2.0.2)\n", "Requirement already satisfied: scipy in /usr/local/lib/python3.11/dist-packages (from lightgbm) (1.15.3)\n", "Requirement already satisfied: catboost in /usr/local/lib/python3.11/dist-packages (1.2.8)\n", "Requirement already satisfied: graphviz in /usr/local/lib/python3.11/dist-packages (from catboost) (0.20.3)\n", "Requirement already satisfied: matplotlib in /usr/local/lib/python3.11/dist-packages (from catboost) (3.10.0)\n", "Requirement already satisfied: numpy<3.0,>=1.16.0 in /usr/local/lib/python3.11/dist-packages (from catboost) (2.0.2)\n", "Requirement already satisfied: pandas>=0.24 in /usr/local/lib/python3.11/dist-packages (from catboost) (2.2.2)\n", "Requirement already satisfied: scipy in /usr/local/lib/python3.11/dist-packages (from catboost) (1.15.3)\n", "Requirement already satisfied: plotly in /usr/local/lib/python3.11/dist-packages (from catboost) (5.24.1)\n", "Requirement already satisfied: six in /usr/local/lib/python3.11/dist-packages (from catboost) (1.17.0)\n", "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/dist-packages (from pandas>=0.24->catboost) (2.9.0.post0)\n", "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas>=0.24->catboost) (2025.2)\n", "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas>=0.24->catboost) (2025.2)\n", "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib->catboost) (1.3.2)\n", "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib->catboost) (0.12.1)\n", "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib->catboost) (4.58.1)\n", "Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib->catboost) (1.4.8)\n", "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib->catboost) (24.2)\n", "Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.11/dist-packages (from matplotlib->catboost) (11.2.1)\n", "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib->catboost) (3.2.3)\n", "Requirement already satisfied: tenacity>=6.2.0 in /usr/local/lib/python3.11/dist-packages (from plotly->catboost) (9.1.2)\n" ] } ] }, { "cell_type": "code", "source": [ "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "\n", "import category_encoders as ce\n", "from sklearn.model_selection import train_test_split\n", "from sklearn.preprocessing import StandardScaler\n", "from sklearn.ensemble import RandomForestRegressor\n", "from sklearn.ensemble import GradientBoostingRegressor\n", "from xgboost import XGBRegressor\n", "import lightgbm as lgb\n", "from catboost import CatBoostRegressor\n", "from sklearn.svm import SVR\n", "from sklearn.ensemble import AdaBoostRegressor\n", "from sklearn.neighbors import KNeighborsRegressor\n", "\n", "from sklearn.preprocessing import LabelEncoder\n", "from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score\n", "from skopt import BayesSearchCV\n", "from skopt.space import Real, Integer\n", "import joblib" ], "metadata": { "id": "enMiSc242hlY" }, "execution_count": 46, "outputs": [] }, { "cell_type": "markdown", "source": [ "# Gathering Data" ], "metadata": { "id": "77Qqz6Uw2ffy" } }, { "cell_type": "code", "execution_count": 47, "metadata": { "id": "TKZq2Wp80Zzl", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "1f908b04-559c-4229-bbf5-3d274626c7d8" }, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ ":1: DtypeWarning: Columns (15) have mixed types. Specify dtype option on import or set low_memory=False.\n", " df = pd.read_csv('/content/cleaned_df.csv')\n" ] } ], "source": [ "df = pd.read_csv('/content/cleaned_df.csv')" ] }, { "cell_type": "code", "source": [ "df.info()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "DyV8gEY4JRrw", "outputId": "b492e865-c2ba-42a0-e253-97b16b5fd288" }, "execution_count": 48, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "RangeIndex: 50464 entries, 0 to 50463\n", "Data columns (total 62 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 description 50246 non-null object \n", " 1 facilities 29363 non-null object \n", " 2 monthly_installment_info 50464 non-null int64 \n", " 3 location 50464 non-null object \n", " 4 nearby_points_of_interest 17037 non-null object \n", " 5 posted_by 50464 non-null object \n", " 6 price_display 50464 non-null object \n", " 7 price_numeric 50464 non-null float64\n", " 8 property_type 50464 non-null object \n", " 9 estimated_savings 50464 non-null float64\n", " 10 specifications 50464 non-null object \n", " 11 title 50460 non-null object \n", " 12 updatedAt 50464 non-null object \n", " 13 source_url 50464 non-null object \n", " 14 error 0 non-null float64\n", " 15 facility_lapangan_bola 1 non-null object \n", " 16 f_taman 50464 non-null int64 \n", " 17 f_jogging_track 50464 non-null int64 \n", " 18 f_cctv 50464 non-null int64 \n", " 19 f_lapangan_voli 50464 non-null int64 \n", " 20 f_lapangan_bola 50464 non-null int64 \n", " 21 f_lapangan_basket 50464 non-null int64 \n", " 22 f_lapangan_bulu_tangkis 50464 non-null int64 \n", " 23 f_tempat_jemuran 50464 non-null int64 \n", " 24 f_kulkas 50464 non-null int64 \n", " 25 f_telepon 50464 non-null int64 \n", " 26 f_tempat_cuci 50464 non-null int64 \n", " 27 f_laundry 50464 non-null int64 \n", " 28 f_masjid 50464 non-null int64 \n", " 29 f_taman_bermain 50464 non-null int64 \n", " 30 f_kolam_renang 50464 non-null int64 \n", " 31 f_mesin_cuci 50464 non-null int64 \n", " 32 f_kompor 50464 non-null int64 \n", " 33 f_keamanan_24_jam 50464 non-null int64 \n", " 34 f_kolam_ikan 50464 non-null int64 \n", " 35 f_backyard 50464 non-null int64 \n", " 36 f_kitchen_set 50464 non-null int64 \n", " 37 f_teras 50464 non-null int64 \n", " 38 f_wastafel 50464 non-null int64 \n", " 39 f_akses_parkir 50464 non-null int64 \n", " 40 f_lapangan_tenis 50464 non-null int64 \n", " 41 f_tempat_gym 50464 non-null int64 \n", " 42 f_ac 50464 non-null int64 \n", " 43 f_water_heater 50464 non-null int64 \n", " 44 f_one_gate_system 50464 non-null int64 \n", " 45 s_carport 33885 non-null float64\n", " 46 s_daya_listrik 50318 non-null object \n", " 47 s_garasi 20564 non-null float64\n", " 48 s_jumlah_lantai 47902 non-null float64\n", " 49 s_kamar_mandi 49387 non-null float64\n", " 50 s_kamar_mandi_pembantu 20957 non-null float64\n", " 51 s_kamar_tidur 49389 non-null float64\n", " 52 s_kamar_tidur_pembantu 22488 non-null float64\n", " 53 s_kondisi_properti 46223 non-null object \n", " 54 s_luas_bangunan 50373 non-null float64\n", " 55 s_luas_tanah 50445 non-null float64\n", " 56 s_sertifikat 50464 non-null object \n", " 57 poi_perbelanjaan 50464 non-null int64 \n", " 58 poi_sekolah 50464 non-null int64 \n", " 59 poi_transportasi 50464 non-null int64 \n", " 60 kabupaten 50464 non-null object \n", " 61 kabupaten_encoded 50464 non-null int64 \n", "dtypes: float64(12), int64(34), object(16)\n", "memory usage: 23.9+ MB\n" ] } ] }, { "cell_type": "code", "source": [ "df['kabupaten'].unique()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "h1jQyx2lV1I5", "outputId": "aa2746ec-fcf2-4293-b5a5-afa9e886d280" }, "execution_count": 49, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "array(['jakarta selatan', 'jakarta timur', 'jakarta utara',\n", " 'jakarta barat', 'jakarta pusat'], dtype=object)" ] }, "metadata": {}, "execution_count": 49 } ] }, { "cell_type": "markdown", "source": [ "# Pre-Processing Data" ], "metadata": { "id": "Nn9Mqu9J3R46" } }, { "cell_type": "markdown", "source": [ "Encode" ], "metadata": { "id": "D7PvZPCW3KbC" } }, { "cell_type": "code", "source": [ "# Di bagian Pre-Processing Data\n", "\n", "df['kabupaten'] = df['kabupaten'].astype(str).str.lower().str.strip()\n", "df['s_sertifikat'] = df['s_sertifikat'].astype(str).str.lower().str.strip()\n", "\n", "# --- Latih LabelEncoder TERPISAH untuk setiap kolom ---\n", "le_kabupaten = LabelEncoder()\n", "df['kabupaten_encoded'] = le_kabupaten.fit_transform(df['kabupaten'])\n", "\n", "le_sertifikat = LabelEncoder()\n", "df['s_sertifikat_encoded'] = le_sertifikat.fit_transform(df['s_sertifikat'])\n", "\n", "# --- Simpan kedua encoder ---\n", "joblib.dump(le_kabupaten, 'le_kabupaten.joblib')\n", "print(\"LabelEncoder for 'kabupaten' saved as le_kabupaten.joblib\")\n", "joblib.dump(le_sertifikat, 'le_sertifikat.joblib')\n", "print(\"LabelEncoder for 's_sertifikat' saved as le_sertifikat.joblib\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "MAQJFYaioKRQ", "outputId": "97a4d0f5-9dc4-4398-9b34-48c413888b52" }, "execution_count": 50, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "LabelEncoder for 'kabupaten' saved as le_kabupaten.joblib\n", "LabelEncoder for 's_sertifikat' saved as le_sertifikat.joblib\n" ] } ] }, { "cell_type": "markdown", "source": [ "Menghapus kolom yang tidak digunakan model machine learning" ], "metadata": { "id": "TjbB-A7c2XDh" } }, { "cell_type": "code", "source": [ "# Daftar kolom yang ingin dihapus untuk modelling\n", "columns_to_drop = [\n", " 'description',\n", " 'monthly_installment_info',\n", " 'location',\n", " 'nearby_points_of_interest',\n", " 'posted_by',\n", " 'price_display',\n", " 'property_type',\n", " 'estimated_savings',\n", " 'kabupaten', # Menghapus kolom asli setelah encoding\n", " 's_sertifikat', # Menghapus kolom asli setelah encoding\n", " 'specifications',\n", " 'title',\n", " 'source_url'\n", " 's_daya_listrik',\n", " 's_carport',\n", " 's_garasi',\n", " 's_kamar_mandi_pembantu',\n", " 's_kamar_tidur_pembantu',\n", " 's_kondisi_properti',\n", " 'error',\n", " 'updatedAt',\n", " 'facility_lapangan_bola',\n", " 'facilities',\n", " 'source_url',\n", " 's_daya_listrik'\n", "]\n", "\n", "# Hapus kolom dari DataFrame df\n", "# axis=1 menunjukkan kita menghapus kolom\n", "# errors='ignore' akan mencegah error jika salah satu kolom tidak ada\n", "df_new = df.drop(columns=columns_to_drop, errors='ignore')" ], "metadata": { "id": "Lj4PUVubqHcW" }, "execution_count": 51, "outputs": [] }, { "cell_type": "code", "source": [ "df_new.columns" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "hYh2vElLT72s", "outputId": "35d44ad3-6a46-4f5d-db43-02fab51c0e2c" }, "execution_count": 52, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "Index(['price_numeric', 'f_taman', 'f_jogging_track', 'f_cctv',\n", " 'f_lapangan_voli', 'f_lapangan_bola', 'f_lapangan_basket',\n", " 'f_lapangan_bulu_tangkis', 'f_tempat_jemuran', 'f_kulkas', 'f_telepon',\n", " 'f_tempat_cuci', 'f_laundry', 'f_masjid', 'f_taman_bermain',\n", " 'f_kolam_renang', 'f_mesin_cuci', 'f_kompor', 'f_keamanan_24_jam',\n", " 'f_kolam_ikan', 'f_backyard', 'f_kitchen_set', 'f_teras', 'f_wastafel',\n", " 'f_akses_parkir', 'f_lapangan_tenis', 'f_tempat_gym', 'f_ac',\n", " 'f_water_heater', 'f_one_gate_system', 's_jumlah_lantai',\n", " 's_kamar_mandi', 's_kamar_tidur', 's_luas_bangunan', 's_luas_tanah',\n", " 'poi_perbelanjaan', 'poi_sekolah', 'poi_transportasi',\n", " 'kabupaten_encoded', 's_sertifikat_encoded'],\n", " dtype='object')" ] }, "metadata": {}, "execution_count": 52 } ] }, { "cell_type": "markdown", "source": [ "Menghapus data yang memiliki harga diatas 4 Milliar dan dibawah 200 juta" ], "metadata": { "id": "qx_Zt2ho5rDX" } }, { "cell_type": "code", "source": [ "# Remove rows where 'price_numeric' is above 4 billion\n", "df_new = df_new[(df_new['price_numeric'] >= 200_000_000) & (df_new['price_numeric'] <= 4_000_000_000)]" ], "metadata": { "id": "jE5nG22s4zhh" }, "execution_count": 53, "outputs": [] }, { "cell_type": "markdown", "source": [ "Menhapus Data Null" ], "metadata": { "id": "zPbPul5X5JCY" } }, { "cell_type": "code", "source": [ "# Menghapus baris yang memiliki nilai null di DataFrame df_new\n", "df_new.dropna(inplace=True)" ], "metadata": { "id": "dBDB7srZ26Lu", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "6de8ff52-1275-4d9c-ce0d-1064a279372a" }, "execution_count": 54, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ ":2: SettingWithCopyWarning: \n", "A value is trying to be set on a copy of a slice from a DataFrame\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", " df_new.dropna(inplace=True)\n" ] } ] }, { "cell_type": "code", "source": [ "df_new.info()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "_PqicNuvicg2", "outputId": "356c54ec-f277-4d97-96bc-17cd91b1cd57" }, "execution_count": 55, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Index: 21094 entries, 1 to 50459\n", "Data columns (total 40 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 price_numeric 21094 non-null float64\n", " 1 f_taman 21094 non-null int64 \n", " 2 f_jogging_track 21094 non-null int64 \n", " 3 f_cctv 21094 non-null int64 \n", " 4 f_lapangan_voli 21094 non-null int64 \n", " 5 f_lapangan_bola 21094 non-null int64 \n", " 6 f_lapangan_basket 21094 non-null int64 \n", " 7 f_lapangan_bulu_tangkis 21094 non-null int64 \n", " 8 f_tempat_jemuran 21094 non-null int64 \n", " 9 f_kulkas 21094 non-null int64 \n", " 10 f_telepon 21094 non-null int64 \n", " 11 f_tempat_cuci 21094 non-null int64 \n", " 12 f_laundry 21094 non-null int64 \n", " 13 f_masjid 21094 non-null int64 \n", " 14 f_taman_bermain 21094 non-null int64 \n", " 15 f_kolam_renang 21094 non-null int64 \n", " 16 f_mesin_cuci 21094 non-null int64 \n", " 17 f_kompor 21094 non-null int64 \n", " 18 f_keamanan_24_jam 21094 non-null int64 \n", " 19 f_kolam_ikan 21094 non-null int64 \n", " 20 f_backyard 21094 non-null int64 \n", " 21 f_kitchen_set 21094 non-null int64 \n", " 22 f_teras 21094 non-null int64 \n", " 23 f_wastafel 21094 non-null int64 \n", " 24 f_akses_parkir 21094 non-null int64 \n", " 25 f_lapangan_tenis 21094 non-null int64 \n", " 26 f_tempat_gym 21094 non-null int64 \n", " 27 f_ac 21094 non-null int64 \n", " 28 f_water_heater 21094 non-null int64 \n", " 29 f_one_gate_system 21094 non-null int64 \n", " 30 s_jumlah_lantai 21094 non-null float64\n", " 31 s_kamar_mandi 21094 non-null float64\n", " 32 s_kamar_tidur 21094 non-null float64\n", " 33 s_luas_bangunan 21094 non-null float64\n", " 34 s_luas_tanah 21094 non-null float64\n", " 35 poi_perbelanjaan 21094 non-null int64 \n", " 36 poi_sekolah 21094 non-null int64 \n", " 37 poi_transportasi 21094 non-null int64 \n", " 38 kabupaten_encoded 21094 non-null int64 \n", " 39 s_sertifikat_encoded 21094 non-null int64 \n", "dtypes: float64(6), int64(34)\n", "memory usage: 6.6 MB\n" ] } ] }, { "cell_type": "markdown", "source": [ "## Semua Fasilitas (df_new)" ], "metadata": { "id": "ahzP_R-47qoL" } }, { "cell_type": "code", "source": [ "# Memisahkan fitur (X) dan target (Y)\n", "X = df_new.drop('price_numeric', axis=1) # X adalah semua kolom kecuali 'price_numeric'\n", "y = df_new['price_numeric'] # y adalah kolom 'price_numeric'\n", "\n", "print(\"\\nShape of X:\", X.shape)\n", "print(\"Shape of y:\", y.shape)\n", "\n", "# Inisialisasi StandardScaler\n", "scaler = StandardScaler()\n", "\n", "# Melakukan standarisasi pada fitur X\n", "X_scaled = scaler.fit_transform(X)\n", "\n", "# Konversi kembali ke DataFrame (opsional, tapi berguna untuk melihat hasil)\n", "X_scaled_df = pd.DataFrame(X_scaled, columns=X.columns, index=X.index)\n", "\n", "print(\"\\nShape of X_scaled:\", X_scaled.shape)\n", "print(\"\\nFitur setelah Standarisasi (beberapa baris pertama):\")\n", "display(X_scaled_df.head())\n", "\n", "# Melakukan train-test split\n", "# test_size=0.20 artinya 20% data akan menjadi data uji, 80% data latih\n", "# random_state=42 adalah seed untuk memastikan hasil split konsisten setiap kali kode dijalankan\n", "X_train, X_test, y_train, y_test = train_test_split(X_scaled_df, y, test_size=0.20, random_state=42)" ], "metadata": { "id": "8TlY0t6D6X82", "colab": { "base_uri": "https://localhost:8080/", "height": 377 }, "outputId": "3aaf695e-0904-41da-99f6-60755768be62" }, "execution_count": 56, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Shape of X: (21094, 39)\n", "Shape of y: (21094,)\n", "\n", "Shape of X_scaled: (21094, 39)\n", "\n", "Fitur setelah Standarisasi (beberapa baris pertama):\n" ] }, { "output_type": "display_data", "data": { "text/plain": [ " f_taman f_jogging_track f_cctv f_lapangan_voli f_lapangan_bola \\\n", "1 1.313918 -0.303953 -0.472811 -0.006885 -0.006885 \n", "7 1.313918 -0.303953 2.115012 -0.006885 -0.006885 \n", "13 -0.761083 -0.303953 -0.472811 -0.006885 -0.006885 \n", "14 1.313918 -0.303953 -0.472811 -0.006885 -0.006885 \n", "19 -0.761083 -0.303953 -0.472811 -0.006885 -0.006885 \n", "\n", " f_lapangan_basket f_lapangan_bulu_tangkis f_tempat_jemuran f_kulkas \\\n", "1 -0.011926 -0.009738 1.165640 -0.184719 \n", "7 -0.011926 -0.009738 1.165640 -0.184719 \n", "13 -0.011926 -0.009738 -0.857898 -0.184719 \n", "14 -0.011926 -0.009738 1.165640 -0.184719 \n", "19 -0.011926 -0.009738 -0.857898 -0.184719 \n", "\n", " f_telepon ... s_jumlah_lantai s_kamar_mandi s_kamar_tidur \\\n", "1 2.016685 ... -0.004739 0.859599 0.275481 \n", "7 -0.495863 ... -0.004739 0.157229 -0.298105 \n", "13 -0.495863 ... 0.965748 0.157229 -0.298105 \n", "14 -0.495863 ... 0.965748 0.859599 0.275481 \n", "19 -0.495863 ... -0.004739 0.157229 0.275481 \n", "\n", " s_luas_bangunan s_luas_tanah poi_perbelanjaan poi_sekolah \\\n", "1 0.183812 0.069123 -0.442345 -0.469280 \n", "7 -0.294524 0.239247 -0.442345 -0.469280 \n", "13 0.274165 -0.173911 -0.442345 -0.469280 \n", "14 0.236961 0.810377 -0.442345 -0.469280 \n", "19 0.003107 0.020517 -0.442345 2.130926 \n", "\n", " poi_transportasi kabupaten_encoded s_sertifikat_encoded \n", "1 -0.581036 0.048017 0.332158 \n", "7 -0.581036 0.048017 0.332158 \n", "13 -0.581036 0.048017 0.332158 \n", "14 -0.581036 0.048017 0.332158 \n", "19 1.721063 0.048017 0.332158 \n", "\n", "[5 rows x 39 columns]" ], "text/html": [ "\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
f_tamanf_jogging_trackf_cctvf_lapangan_volif_lapangan_bolaf_lapangan_basketf_lapangan_bulu_tangkisf_tempat_jemuranf_kulkasf_telepon...s_jumlah_lantais_kamar_mandis_kamar_tidurs_luas_bangunans_luas_tanahpoi_perbelanjaanpoi_sekolahpoi_transportasikabupaten_encodeds_sertifikat_encoded
11.313918-0.303953-0.472811-0.006885-0.006885-0.011926-0.0097381.165640-0.1847192.016685...-0.0047390.8595990.2754810.1838120.069123-0.442345-0.469280-0.5810360.0480170.332158
71.313918-0.3039532.115012-0.006885-0.006885-0.011926-0.0097381.165640-0.184719-0.495863...-0.0047390.157229-0.298105-0.2945240.239247-0.442345-0.469280-0.5810360.0480170.332158
13-0.761083-0.303953-0.472811-0.006885-0.006885-0.011926-0.009738-0.857898-0.184719-0.495863...0.9657480.157229-0.2981050.274165-0.173911-0.442345-0.469280-0.5810360.0480170.332158
141.313918-0.303953-0.472811-0.006885-0.006885-0.011926-0.0097381.165640-0.184719-0.495863...0.9657480.8595990.2754810.2369610.810377-0.442345-0.469280-0.5810360.0480170.332158
19-0.761083-0.303953-0.472811-0.006885-0.006885-0.011926-0.009738-0.857898-0.184719-0.495863...-0.0047390.1572290.2754810.0031070.020517-0.4423452.1309261.7210630.0480170.332158
\n", "

5 rows × 39 columns

\n", "
\n", "
\n", "\n", "
\n", " \n", "\n", " \n", "\n", " \n", "
\n", "\n", "\n", "
\n", " \n", "\n", "\n", "\n", " \n", "
\n", "\n", "
\n", "
\n" ], "application/vnd.google.colaboratory.intrinsic+json": { "type": "dataframe" } }, "metadata": {} } ] }, { "cell_type": "markdown", "source": [ "## Fasilias Tertentu (df_new2)" ], "metadata": { "id": "luqH7PMl80hy" } }, { "cell_type": "code", "source": [ "# Daftar kolom yang ingin dipertahankan untuk df_new2\n", "columns_to_keep_df_new2 = [\n", " 'price_numeric', # Kolom target\n", " 'f_one_gate_system',\n", " 'f_kompor',\n", " 'f_water_heater',\n", " 'f_kulkas',\n", " 'f_kitchen_set',\n", " 's_jumlah_lantai',\n", " 's_kamar_mandi',\n", " 's_kamar_tidur',\n", " 's_luas_bangunan',\n", " 's_luas_tanah',\n", " 'poi_transportasi',\n", " 'kabupaten_encoded', # Kolom yang sudah di-encoded\n", " 's_sertifikat_encoded', # Kolom yang sudah di-encoded\n", "]\n", "\n", "# Buat df_new2 baru dengan hanya menyertakan kolom yang diinginkan dari df_new\n", "# Menggunakan .copy() untuk menghindari SettingWithCopyWarning\n", "df_new2 = df_new[columns_to_keep_df_new2].copy()\n", "\n", "# Tampilkan informasi DataFrame setelah pemilihan kolom untuk verifikasi\n", "print(\"\\nDataFrame df_new2 setelah pemilihan kolom:\")\n", "df_new2.info()\n", "\n", "# Menampilkan beberapa baris pertama dari df_new2\n", "display(df_new2.head())" ], "metadata": { "id": "uZh4kp0b70bb", "colab": { "base_uri": "https://localhost:8080/", "height": 0 }, "outputId": "12c41c35-dcc0-4a69-8587-003d8dc101f7" }, "execution_count": 58, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "DataFrame df_new2 setelah pemilihan kolom:\n", "\n", "Index: 21094 entries, 1 to 50459\n", "Data columns (total 14 columns):\n", " # Column Non-Null Count Dtype \n", "--- ------ -------------- ----- \n", " 0 price_numeric 21094 non-null float64\n", " 1 f_one_gate_system 21094 non-null int64 \n", " 2 f_kompor 21094 non-null int64 \n", " 3 f_water_heater 21094 non-null int64 \n", " 4 f_kulkas 21094 non-null int64 \n", " 5 f_kitchen_set 21094 non-null int64 \n", " 6 s_jumlah_lantai 21094 non-null float64\n", " 7 s_kamar_mandi 21094 non-null float64\n", " 8 s_kamar_tidur 21094 non-null float64\n", " 9 s_luas_bangunan 21094 non-null float64\n", " 10 s_luas_tanah 21094 non-null float64\n", " 11 poi_transportasi 21094 non-null int64 \n", " 12 kabupaten_encoded 21094 non-null int64 \n", " 13 s_sertifikat_encoded 21094 non-null int64 \n", "dtypes: float64(6), int64(8)\n", "memory usage: 2.4 MB\n" ] }, { "output_type": "display_data", "data": { "text/plain": [ " price_numeric f_one_gate_system f_kompor f_water_heater f_kulkas \\\n", "1 3.150000e+09 0 0 0 0 \n", "7 2.000000e+09 1 0 0 0 \n", "13 3.200000e+09 0 0 0 0 \n", "14 3.720000e+09 1 0 0 0 \n", "19 2.700000e+09 0 0 0 0 \n", "\n", " f_kitchen_set s_jumlah_lantai s_kamar_mandi s_kamar_tidur \\\n", "1 0 2.0 4.0 4.0 \n", "7 0 2.0 3.0 3.0 \n", "13 0 3.0 3.0 3.0 \n", "14 0 3.0 4.0 4.0 \n", "19 0 2.0 3.0 4.0 \n", "\n", " s_luas_bangunan s_luas_tanah poi_transportasi kabupaten_encoded \\\n", "1 190.0 128.0 0 2 \n", "7 100.0 156.0 0 2 \n", "13 207.0 88.0 0 2 \n", "14 200.0 250.0 0 2 \n", "19 156.0 120.0 1 2 \n", "\n", " s_sertifikat_encoded \n", "1 8 \n", "7 8 \n", "13 8 \n", "14 8 \n", "19 8 " ], "text/html": [ "\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
price_numericf_one_gate_systemf_komporf_water_heaterf_kulkasf_kitchen_sets_jumlah_lantais_kamar_mandis_kamar_tidurs_luas_bangunans_luas_tanahpoi_transportasikabupaten_encodeds_sertifikat_encoded
13.150000e+09000002.04.04.0190.0128.0028
72.000000e+09100002.03.03.0100.0156.0028
133.200000e+09000003.03.03.0207.088.0028
143.720000e+09100003.04.04.0200.0250.0028
192.700000e+09000002.03.04.0156.0120.0128
\n", "
\n", "
\n", "\n", "
\n", " \n", "\n", " \n", "\n", " \n", "
\n", "\n", "\n", "
\n", " \n", "\n", "\n", "\n", " \n", "
\n", "\n", "
\n", "
\n" ], "application/vnd.google.colaboratory.intrinsic+json": { "type": "dataframe", "summary": "{\n \"name\": \"display(df_new2\",\n \"rows\": 5,\n \"fields\": [\n {\n \"column\": \"price_numeric\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 644267025.3862135,\n \"min\": 2000000000.0,\n \"max\": 3720000000.0,\n \"num_unique_values\": 5,\n \"samples\": [\n 2000000000.0,\n 2700000000.0,\n 3200000000.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"f_one_gate_system\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 1,\n \"num_unique_values\": 2,\n \"samples\": [\n 1,\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"f_kompor\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 0,\n \"num_unique_values\": 1,\n \"samples\": [\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"f_water_heater\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 0,\n \"num_unique_values\": 1,\n \"samples\": [\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"f_kulkas\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 0,\n \"num_unique_values\": 1,\n \"samples\": [\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"f_kitchen_set\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 0,\n \"num_unique_values\": 1,\n \"samples\": [\n 0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"s_jumlah_lantai\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.5477225575051661,\n \"min\": 2.0,\n \"max\": 3.0,\n \"num_unique_values\": 2,\n \"samples\": [\n 3.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"s_kamar_mandi\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.5477225575051661,\n \"min\": 3.0,\n \"max\": 4.0,\n \"num_unique_values\": 2,\n \"samples\": [\n 3.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"s_kamar_tidur\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.5477225575051661,\n \"min\": 3.0,\n \"max\": 4.0,\n \"num_unique_values\": 2,\n \"samples\": [\n 3.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"s_luas_bangunan\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 44.05451168722677,\n \"min\": 100.0,\n \"max\": 207.0,\n \"num_unique_values\": 5,\n \"samples\": [\n 100.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"s_luas_tanah\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 61.74787445734468,\n \"min\": 88.0,\n \"max\": 250.0,\n \"num_unique_values\": 5,\n \"samples\": [\n 156.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"poi_transportasi\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 0,\n \"max\": 1,\n \"num_unique_values\": 2,\n \"samples\": [\n 1\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"kabupaten_encoded\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 2,\n \"max\": 2,\n \"num_unique_values\": 1,\n \"samples\": [\n 2\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"s_sertifikat_encoded\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": 8,\n \"max\": 8,\n \"num_unique_values\": 1,\n \"samples\": [\n 8\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" } }, "metadata": {} } ] }, { "cell_type": "code", "source": [ "# Memisahkan fitur (X) dan target (Y) untuk df_new2\n", "X2 = df_new2.drop('price_numeric', axis=1) # X2 adalah semua kolom kecuali 'price_numeric'\n", "y2 = df_new2['price_numeric'] # y2 adalah kolom 'price_numeric'\n", "\n", "print(\"\\nShape of X2:\", X2.shape)\n", "print(\"Shape of y2:\", y2.shape)\n", "\n", "# Inisialisasi StandardScaler\n", "scaler2 = StandardScaler()\n", "\n", "# Melakukan standarisasi pada fitur X2\n", "X_scaled2 = scaler2.fit_transform(X2)\n", "\n", "# Konversi kembali ke DataFrame (opsional)\n", "X_scaled_df2 = pd.DataFrame(X_scaled2, columns=X2.columns, index=X2.index)\n", "\n", "print(\"\\nShape of X_scaled2:\", X_scaled2.shape)\n", "print(\"\\nFitur setelah Standarisasi (df_new2, beberapa baris pertama):\")\n", "display(X_scaled_df2.head())\n", "\n", "# Melakukan train-test split untuk data tanpa fasilitas\n", "# test_size=0.20 artinya 20% data akan menjadi data uji, 80% data latih\n", "# random_state=42 adalah seed untuk memastikan hasil split konsisten\n", "X_train2, X_test2, y_train2, y_test2 = train_test_split(X_scaled_df2, y2, test_size=0.20, random_state=42)\n", "\n", "print(\"\\nShape of X_train2:\", X_train2.shape)\n", "print(\"Shape of X_test2:\", X_test2.shape)\n", "print(\"Shape of y_train2:\", y_train2.shape)\n", "print(\"Shape of y_test2:\", y_test2.shape)" ], "metadata": { "id": "AJEIHifn9CfP", "colab": { "base_uri": "https://localhost:8080/", "height": 0 }, "outputId": "a3a57028-8f42-4d90-da4d-1143ae0c5cdb" }, "execution_count": 59, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Shape of X2: (21094, 13)\n", "Shape of y2: (21094,)\n", "\n", "Shape of X_scaled2: (21094, 13)\n", "\n", "Fitur setelah Standarisasi (df_new2, beberapa baris pertama):\n" ] }, { "output_type": "display_data", "data": { "text/plain": [ " f_one_gate_system f_kompor f_water_heater f_kulkas f_kitchen_set \\\n", "1 -0.567022 -0.223317 -0.289386 -0.184719 -0.460608 \n", "7 1.763601 -0.223317 -0.289386 -0.184719 -0.460608 \n", "13 -0.567022 -0.223317 -0.289386 -0.184719 -0.460608 \n", "14 1.763601 -0.223317 -0.289386 -0.184719 -0.460608 \n", "19 -0.567022 -0.223317 -0.289386 -0.184719 -0.460608 \n", "\n", " s_jumlah_lantai s_kamar_mandi s_kamar_tidur s_luas_bangunan \\\n", "1 -0.004739 0.859599 0.275481 0.183812 \n", "7 -0.004739 0.157229 -0.298105 -0.294524 \n", "13 0.965748 0.157229 -0.298105 0.274165 \n", "14 0.965748 0.859599 0.275481 0.236961 \n", "19 -0.004739 0.157229 0.275481 0.003107 \n", "\n", " s_luas_tanah poi_transportasi kabupaten_encoded s_sertifikat_encoded \n", "1 0.069123 -0.581036 0.048017 0.332158 \n", "7 0.239247 -0.581036 0.048017 0.332158 \n", "13 -0.173911 -0.581036 0.048017 0.332158 \n", "14 0.810377 -0.581036 0.048017 0.332158 \n", "19 0.020517 1.721063 0.048017 0.332158 " ], "text/html": [ "\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
f_one_gate_systemf_komporf_water_heaterf_kulkasf_kitchen_sets_jumlah_lantais_kamar_mandis_kamar_tidurs_luas_bangunans_luas_tanahpoi_transportasikabupaten_encodeds_sertifikat_encoded
1-0.567022-0.223317-0.289386-0.184719-0.460608-0.0047390.8595990.2754810.1838120.069123-0.5810360.0480170.332158
71.763601-0.223317-0.289386-0.184719-0.460608-0.0047390.157229-0.298105-0.2945240.239247-0.5810360.0480170.332158
13-0.567022-0.223317-0.289386-0.184719-0.4606080.9657480.157229-0.2981050.274165-0.173911-0.5810360.0480170.332158
141.763601-0.223317-0.289386-0.184719-0.4606080.9657480.8595990.2754810.2369610.810377-0.5810360.0480170.332158
19-0.567022-0.223317-0.289386-0.184719-0.460608-0.0047390.1572290.2754810.0031070.0205171.7210630.0480170.332158
\n", "
\n", "
\n", "\n", "
\n", " \n", "\n", " \n", "\n", " \n", "
\n", "\n", "\n", "
\n", " \n", "\n", "\n", "\n", " \n", "
\n", "\n", "
\n", "
\n" ], "application/vnd.google.colaboratory.intrinsic+json": { "type": "dataframe", "summary": "{\n \"name\": \"print(\\\"Shape of y_test2:\\\", y_test2\",\n \"rows\": 5,\n \"fields\": [\n {\n \"column\": \"f_one_gate_system\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1.2765346036886203,\n \"min\": -0.5670216881104466,\n \"max\": 1.7636009714768024,\n \"num_unique_values\": 2,\n \"samples\": [\n 1.7636009714768024,\n -0.5670216881104466\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"f_kompor\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.0,\n \"min\": -0.2233172524947317,\n \"max\": -0.2233172524947317,\n \"num_unique_values\": 1,\n \"samples\": [\n -0.2233172524947317\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"f_water_heater\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.0,\n \"min\": -0.28938615817087043,\n \"max\": -0.28938615817087043,\n \"num_unique_values\": 1,\n \"samples\": [\n -0.28938615817087043\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"f_kulkas\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.0,\n \"min\": -0.18471868409595865,\n \"max\": -0.18471868409595865,\n \"num_unique_values\": 1,\n \"samples\": [\n -0.18471868409595865\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"f_kitchen_set\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.0,\n \"min\": -0.4606077744611299,\n \"max\": -0.4606077744611299,\n \"num_unique_values\": 1,\n \"samples\": [\n -0.4606077744611299\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"s_jumlah_lantai\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.5315572542736046,\n \"min\": -0.004738792638259008,\n \"max\": 0.9657475365989496,\n \"num_unique_values\": 2,\n \"samples\": [\n 0.9657475365989496\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"s_kamar_mandi\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.38470386646423277,\n \"min\": 0.15722911319280142,\n \"max\": 0.8595990652658531,\n \"num_unique_values\": 2,\n \"samples\": [\n 0.15722911319280142\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"s_kamar_tidur\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.3141660650677855,\n \"min\": -0.29810490201624346,\n \"max\": 0.27548123345129627,\n \"num_unique_values\": 2,\n \"samples\": [\n -0.29810490201624346\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"s_luas_bangunan\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.23414309249026252,\n \"min\": -0.294524137535907,\n \"max\": 0.2741647421486245,\n \"num_unique_values\": 5,\n \"samples\": [\n -0.294524137535907\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"s_luas_tanah\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.37517061347948727,\n \"min\": -0.1739105237611903,\n \"max\": 0.8103766264898199,\n \"num_unique_values\": 5,\n \"samples\": [\n 0.2392470454799745\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"poi_transportasi\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1.0295301497584646,\n \"min\": -0.581036181105758,\n \"max\": 1.7210632186397077,\n \"num_unique_values\": 2,\n \"samples\": [\n 1.7210632186397077\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"kabupaten_encoded\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.0,\n \"min\": 0.048016712133161804,\n \"max\": 0.048016712133161804,\n \"num_unique_values\": 1,\n \"samples\": [\n 0.048016712133161804\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"s_sertifikat_encoded\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.0,\n \"min\": 0.3321577309003089,\n \"max\": 0.3321577309003089,\n \"num_unique_values\": 1,\n \"samples\": [\n 0.3321577309003089\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" } }, "metadata": {} }, { "output_type": "stream", "name": "stdout", "text": [ "\n", "Shape of X_train2: (16875, 13)\n", "Shape of X_test2: (4219, 13)\n", "Shape of y_train2: (16875,)\n", "Shape of y_test2: (4219,)\n" ] } ] }, { "cell_type": "code", "source": [ "a= 2" ], "metadata": { "id": "4O2fNQyC3l8p" }, "execution_count": 60, "outputs": [] }, { "cell_type": "markdown", "source": [ "# Model" ], "metadata": { "id": "B1EKGEKA2qZM" } }, { "cell_type": "markdown", "source": [ "### Semua Fasilitas" ], "metadata": { "id": "BT1Fp01I-ISr" } }, { "cell_type": "markdown", "source": [ "Random Forest" ], "metadata": { "id": "QHwUGW1oAx5e" } }, { "cell_type": "code", "source": [ "# Inisialisasi model Random Forest Regressor\n", "# n_estimators=100 adalah jumlah pohon dalam forest\n", "# random_state=42 untuk hasil yang konsisten\n", "model_rf = RandomForestRegressor(random_state=42, n_estimators=100)\n", "\n", "# Melatih model menggunakan data latih\n", "model_rf.fit(X_train, y_train)\n", "\n", "# Melakukan prediksi pada data uji\n", "y_pred_rf = model_rf.predict(X_test)\n", "\n", "# # Evaluasi Model Random Forest\n", "\n", "# Fungsi untuk menghitung MAPE\n", "def mean_absolute_percentage_error(y_true, y_pred):\n", " # Menghindari pembagian dengan nol dengan mengganti nilai 0 pada y_true dengan nilai yang sangat kecil (misalnya 1e-9)\n", " # Atau bisa juga dengan hanya menghitung MAPE pada baris di mana y_true bukan nol\n", " y_true, y_pred = np.array(y_true), np.array(y_pred)\n", " # Hanya hitung MAPE untuk nilai y_true yang tidak nol\n", " non_zero_indices = y_true != 0\n", " return np.mean(np.abs((y_true[non_zero_indices] - y_pred[non_zero_indices]) / y_true[non_zero_indices])) * 100\n", "\n", "# Menghitung metrik evaluasi\n", "mae_rf = mean_absolute_error(y_test, y_pred_rf)\n", "mse_rf = mean_squared_error(y_test, y_pred_rf)\n", "rmse_rf = np.sqrt(mse_rf)\n", "r2_rf = r2_score(y_test, y_pred_rf)\n", "mape_rf = mean_absolute_percentage_error(y_test, y_pred_rf)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"Evaluasi Model Random Forest\")\n", "print(f\"Mean Absolute Error (MAE): {mae_rf:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_rf:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_rf:.2f}\")\n", "print(f\"R-squared (R2): {r2_rf:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_rf:.2f}%\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "Muo77A4dZkPo", "outputId": "ef619d5a-ebfe-459b-d5e2-0762e16fe7fa" }, "execution_count": 61, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Evaluasi Model Random Forest\n", "Mean Absolute Error (MAE): 340591445.36\n", "Mean Squared Error (MSE): 231001733762805536.00\n", "Root Mean Squared Error (RMSE): 480626397.28\n", "R-squared (R2): 0.72\n", "Mean Absolute Percentage Error (MAPE): 16.47%\n" ] } ] }, { "cell_type": "markdown", "source": [ "Gradient Boosting" ], "metadata": { "id": "gqG3L_GzAt8R" } }, { "cell_type": "code", "source": [ "model_gb = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1, max_depth=3, random_state=42)\n", "\n", "# Melatih model menggunakan data latih\n", "print(\"\\nMelatih model Gradient Boosting...\")\n", "model_gb.fit(X_train, y_train)\n", "print(\"Model Gradient Boosting selesai dilatih.\")\n", "\n", "# Melakukan prediksi pada data uji\n", "y_pred_gb = model_gb.predict(X_test)\n", "\n", "# # Evaluasi Model Gradient Boosting\n", "\n", "# Menghitung metrik evaluasi\n", "mae_gb = mean_absolute_error(y_test, y_pred_gb)\n", "mse_gb = mean_squared_error(y_test, y_pred_gb)\n", "rmse_gb = np.sqrt(mse_gb)\n", "r2_gb = r2_score(y_test, y_pred_gb)\n", "mape_gb = mean_absolute_percentage_error(y_test, y_pred_gb)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"\\nEvaluasi Model Gradient Boosting\")\n", "print(f\"Mean Absolute Error (MAE): {mae_gb:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_gb:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_gb:.2f}\")\n", "print(f\"R-squared (R2): {r2_gb:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_gb:.2f}%\")" ], "metadata": { "id": "B3Zh5FavAl0a", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "afa5ee0a-ceed-49ff-928a-238b949be6e2" }, "execution_count": 69, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Melatih model Gradient Boosting...\n", "Model Gradient Boosting selesai dilatih.\n", "\n", "Evaluasi Model Gradient Boosting\n", "Mean Absolute Error (MAE): 418700931.06\n", "Mean Squared Error (MSE): 290482649647068288.00\n", "Root Mean Squared Error (RMSE): 538964423.36\n", "R-squared (R2): 0.65\n", "Mean Absolute Percentage Error (MAPE): 20.61%\n" ] } ] }, { "cell_type": "markdown", "source": [ "XGBoost" ], "metadata": { "id": "B8LN7-ZqA1mj" } }, { "cell_type": "code", "source": [ "model_xgb = XGBRegressor(objective='reg:squarederror', # objective untuk regresi\n", " n_estimators=100,\n", " learning_rate=0.1,\n", " max_depth=5, # Umumnya sedikit lebih dalam dari GB\n", " random_state=42,\n", " n_jobs=-1) # Menggunakan semua core CPU yang tersedia\n", "\n", "model_xgb.fit(X_train, y_train) # Fit the model using the training data\n", "\n", "# Melakukan prediksi pada data uji\n", "y_pred_xgb = model_xgb.predict(X_test)\n", "\n", "# # Evaluasi Model XGBoost\n", "\n", "# Menghitung metrik evaluasi\n", "mae_xgb = mean_absolute_error(y_test, y_pred_xgb)\n", "mse_xgb = mean_squared_error(y_test, y_pred_xgb)\n", "rmse_xgb = np.sqrt(mse_xgb)\n", "r2_xgb = r2_score(y_test, y_pred_xgb)\n", "mape_xgb = mean_absolute_percentage_error(y_test, y_pred_xgb)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"\\nEvaluasi Model XGBoost\")\n", "print(f\"Mean Absolute Error (MAE): {mae_xgb:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_xgb:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_xgb:.2f}\")\n", "print(f\"R-squared (R2): {r2_xgb:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_xgb:.2f}%\")" ], "metadata": { "id": "Iue4SXX9A-yF", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "4fc5c4be-7ad1-45b3-c9f8-cd4a9f01cd97" }, "execution_count": 70, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Evaluasi Model XGBoost\n", "Mean Absolute Error (MAE): 397052713.54\n", "Mean Squared Error (MSE): 267103514658796320.00\n", "Root Mean Squared Error (RMSE): 516820582.66\n", "R-squared (R2): 0.67\n", "Mean Absolute Percentage Error (MAPE): 19.36%\n" ] } ] }, { "cell_type": "code", "source": [ "model_cb = CatBoostRegressor(iterations=100, # Mirip n_estimators\n", " learning_rate=0.1,\n", " depth=6, # Mirip max_depth\n", " loss_function='RMSE', # Metrik loss\n", " random_state=42,\n", " verbose=0) # Set verbose=True jika ingin melihat progress\n", "\n", "# Melatih model menggunakan data latih\n", "print(\"\\nMelatih model CatBoost...\")\n", "model_cb.fit(X_train, y_train)\n", "print(\"Model CatBoost selesai dilatih.\")\n", "\n", "# Melakukan prediksi pada data uji\n", "y_pred_cb = model_cb.predict(X_test)\n", "\n", "# # Evaluasi Model CatBoost\n", "\n", "# Menghitung metrik evaluasi\n", "mae_cb = mean_absolute_error(y_test, y_pred_cb)\n", "mse_cb = mean_squared_error(y_test, y_pred_cb)\n", "rmse_cb = np.sqrt(mse_cb)\n", "r2_cb = r2_score(y_test, y_pred_cb)\n", "mape_cb = mean_absolute_percentage_error(y_test, y_pred_cb)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"\\nEvaluasi Model CatBoost\")\n", "print(f\"Mean Absolute Error (MAE): {mae_cb:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_cb:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_cb:.2f}\")\n", "print(f\"R-squared (R2): {r2_cb:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_cb:.2f}%\")" ], "metadata": { "id": "N3Z2NwihsJ6n", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "dd226520-7041-4729-d585-721684c6acd5" }, "execution_count": 71, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Melatih model CatBoost...\n", "Model CatBoost selesai dilatih.\n", "\n", "Evaluasi Model CatBoost\n", "Mean Absolute Error (MAE): 409382988.70\n", "Mean Squared Error (MSE): 280091241391207424.00\n", "Root Mean Squared Error (RMSE): 529236470.20\n", "R-squared (R2): 0.66\n", "Mean Absolute Percentage Error (MAPE): 20.03%\n" ] } ] }, { "cell_type": "markdown", "source": [ "LightGBM" ], "metadata": { "id": "BK5xx8uvtQbe" } }, { "cell_type": "code", "source": [ "model_lgbm = lgb.LGBMRegressor(objective='regression',\n", " metric='rmse',\n", " n_estimators=100,\n", " learning_rate=0.1,\n", " num_leaves=31, # Default\n", " random_state=42,\n", " n_jobs=-1) # Menggunakan semua core CPU\n", "\n", "# Melatih model menggunakan data latih (df_new)\n", "model_lgbm.fit(X_train, y_train)\n", "\n", "# Melakukan prediksi pada data uji (df_new)\n", "y_pred_lgbm = model_lgbm.predict(X_test)\n", "\n", "# # Evaluasi Model LightGBM (df_new)\n", "\n", "# Menghitung metrik evaluasi\n", "mae_lgbm = mean_absolute_error(y_test, y_pred_lgbm)\n", "mse_lgbm = mean_squared_error(y_test, y_pred_lgbm)\n", "rmse_lgbm = np.sqrt(mse_lgbm)\n", "r2_lgbm = r2_score(y_test, y_pred_lgbm)\n", "mape_lgbm = mean_absolute_percentage_error(y_test, y_pred_lgbm)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"\\nEvaluasi Model LightGBM (df_new)\")\n", "print(f\"Mean Absolute Error (MAE): {mae_lgbm:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_lgbm:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_lgbm:.2f}\")\n", "print(f\"R-squared (R2): {r2_lgbm:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_lgbm:.2f}%\")" ], "metadata": { "id": "LQLTZMQYs1gS", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "2c5b7591-0a5c-4989-f1d7-6a911e85514d" }, "execution_count": 72, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.007337 seconds.\n", "You can set `force_row_wise=true` to remove the overhead.\n", "And if memory is not enough, you can set `force_col_wise=true`.\n", "[LightGBM] [Info] Total Bins 660\n", "[LightGBM] [Info] Number of data points in the train set: 16875, number of used features: 33\n", "[LightGBM] [Info] Start training from score 2383061810.145659\n", "\n", "Evaluasi Model LightGBM (df_new)\n", "Mean Absolute Error (MAE): 389476379.68\n", "Mean Squared Error (MSE): 258408876860365696.00\n", "Root Mean Squared Error (RMSE): 508339332.40\n", "R-squared (R2): 0.69\n", "Mean Absolute Percentage Error (MAPE): 18.97%\n" ] } ] }, { "cell_type": "markdown", "source": [ "### Fasilias Tertentu" ], "metadata": { "id": "n8yGi7OABaei" } }, { "cell_type": "code", "source": [ "model_rf2 = RandomForestRegressor(n_estimators=100, random_state=42)\n", "\n", "# Melatih model menggunakan data latih dari df_new2\n", "model_rf2.fit(X_train2, y_train2)\n", "\n", "# Melakukan prediksi pada data uji dari df_new2\n", "y_pred_rf2 = model_rf2.predict(X_test2)\n", "\n", "# # Evaluasi Model Random Forest untuk df_new2\n", "\n", "# Menghitung metrik evaluasi\n", "mae_rf2 = mean_absolute_error(y_test2, y_pred_rf2)\n", "mse_rf2 = mean_squared_error(y_test2, y_pred_rf2)\n", "rmse_rf2 = np.sqrt(mse_rf2)\n", "r2_rf2 = r2_score(y_test2, y_pred_rf2)\n", "mape_rf2 = mean_absolute_percentage_error(y_test2, y_pred_rf2)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"\\nEvaluasi Model Random Forest (df_new2)\")\n", "print(f\"Mean Absolute Error (MAE): {mae_rf2:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_rf2:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_rf2:.2f}\")\n", "print(f\"R-squared (R2): {r2_rf2:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_rf2:.2f}%\")" ], "metadata": { "id": "55kPFPq6BX5F", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "74345262-c452-43ff-e82f-e1ca3091d358" }, "execution_count": 73, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Evaluasi Model Random Forest (df_new2)\n", "Mean Absolute Error (MAE): 339994351.55\n", "Mean Squared Error (MSE): 238970969089081728.00\n", "Root Mean Squared Error (RMSE): 488846570.09\n", "R-squared (R2): 0.71\n", "Mean Absolute Percentage Error (MAPE): 16.49%\n" ] } ] }, { "cell_type": "markdown", "source": [ "Gradient Boosting" ], "metadata": { "id": "P3ofSMCStpfA" } }, { "cell_type": "code", "source": [ "# Inisialisasi model Gradient Boosting Regressor\n", "# Sesuaikan parameter seperti n_estimators, learning_rate, max_depth sesuai kebutuhan\n", "model_gb2 = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1, max_depth=3, random_state=42)\n", "\n", "# Melatih model menggunakan data latih dari df_new2\n", "model_gb2.fit(X_train2, y_train2)\n", "\n", "# Melakukan prediksi pada data uji dari df_new2\n", "y_pred_gb2 = model_gb2.predict(X_test2)\n", "\n", "# # Evaluasi Model Gradient Boosting untuk df_new2\n", "\n", "# Menghitung metrik evaluasi\n", "mae_gb2 = mean_absolute_error(y_test2, y_pred_gb2)\n", "mse_gb2 = mean_squared_error(y_test2, y_pred_gb2)\n", "rmse_gb2 = np.sqrt(mse_gb2)\n", "r2_gb2 = r2_score(y_test2, y_pred_gb2)\n", "mape_gb2 = mean_absolute_percentage_error(y_test2, y_pred_gb2)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"\\nEvaluasi Model Gradient Boosting (df_new2)\")\n", "print(f\"Mean Absolute Error (MAE): {mae_gb2:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_gb2:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_gb2:.2f}\")\n", "print(f\"R-squared (R2): {r2_gb2:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_gb2:.2f}%\")" ], "metadata": { "id": "xUu9fVXPCEeP", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "19bdc02c-b84d-4943-f84b-2faf943a3b72" }, "execution_count": 74, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Evaluasi Model Gradient Boosting (df_new2)\n", "Mean Absolute Error (MAE): 421427023.73\n", "Mean Squared Error (MSE): 293391967803029952.00\n", "Root Mean Squared Error (RMSE): 541656688.14\n", "R-squared (R2): 0.64\n", "Mean Absolute Percentage Error (MAPE): 20.75%\n" ] } ] }, { "cell_type": "markdown", "source": [ "XGBoost" ], "metadata": { "id": "UnXk2jkVtjtw" } }, { "cell_type": "code", "source": [ "model_xgb2 = XGBRegressor(objective='reg:squarederror',\n", " n_estimators=100,\n", " learning_rate=0.1,\n", " max_depth=5,\n", " random_state=42,\n", " n_jobs=-1)\n", "\n", "# Melatih model menggunakan data latih dari df_new2\n", "model_xgb2.fit(X_train2, y_train2)\n", "\n", "# Melakukan prediksi pada data uji dari df_new2\n", "y_pred_xgb2 = model_xgb2.predict(X_test2)\n", "\n", "# # Evaluasi Model XGBoost untuk df_new2\n", "\n", "# Menghitung metrik evaluasi\n", "mae_xgb2 = mean_absolute_error(y_test2, y_pred_xgb2)\n", "mse_xgb2 = mean_squared_error(y_test2, y_pred_xgb2)\n", "rmse_xgb2 = np.sqrt(mse_xgb2)\n", "r2_xgb2 = r2_score(y_test2, y_pred_xgb2)\n", "mape_xgb2 = mean_absolute_percentage_error(y_test2, y_pred_xgb2)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"\\nEvaluasi Model XGBoost (df_new2)\")\n", "print(f\"Mean Absolute Error (MAE): {mae_xgb2:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_xgb2:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_xgb2:.2f}\")\n", "print(f\"R-squared (R2): {r2_xgb2:.2f}\")\n" ], "metadata": { "id": "ISIajdvvCN1C", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "9a9b2076-d2f3-4372-9bee-ac62d289ebfb" }, "execution_count": 75, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Evaluasi Model XGBoost (df_new2)\n", "Mean Absolute Error (MAE): 405544248.31\n", "Mean Squared Error (MSE): 277747114339317472.00\n", "Root Mean Squared Error (RMSE): 527017186.00\n", "R-squared (R2): 0.66\n" ] } ] }, { "cell_type": "markdown", "source": [ "CatBoost" ], "metadata": { "id": "0CTrcP-9tbvs" } }, { "cell_type": "code", "source": [ "# verbose=0 untuk menghilangkan output training yang terlalu banyak\n", "model_cb2 = CatBoostRegressor(iterations=100, # Jumlah boosting iterations (estimators)\n", " learning_rate=0.1,\n", " depth=6, # Kedalaman pohon\n", " l2_leaf_reg=3, # Regularization\n", " loss_function='RMSE', # Loss function untuk regresi\n", " random_state=42,\n", " verbose=0) # Mengurangi verbosity\n", "\n", "# Melatih model menggunakan data latih dari df_new2\n", "# Menggunakan pool jika ada data kategori, tapi di sini kita sudah encode\n", "model_cb2.fit(X_train2, y_train2,\n", " eval_set=(X_test2, y_test2), # Data validasi untuk early stopping\n", " early_stopping_rounds=10, # Stop jika validasi tidak membaik selama 10 iterasi\n", " verbose=False) # Matikan verbose selama training untuk output yang lebih bersih\n", "\n", "# Melakukan prediksi pada data uji dari df_new2\n", "y_pred_cb2 = model_cb2.predict(X_test2)\n", "\n", "# # Evaluasi Model CatBoost untuk df_new2\n", "\n", "# Menghitung metrik evaluasi\n", "mae_cb2 = mean_absolute_error(y_test2, y_pred_cb2)\n", "mse_cb2 = mean_squared_error(y_test2, y_pred_cb2)\n", "rmse_cb2 = np.sqrt(mse_cb2)\n", "r2_cb2 = r2_score(y_test2, y_pred_cb2)\n", "mape_cb2 = mean_absolute_percentage_error(y_test2, y_pred_cb2)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"\\nEvaluasi Model CatBoost (df_new2)\")\n", "print(f\"Mean Absolute Error (MAE): {mae_cb2:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_cb2:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_cb2:.2f}\")\n", "print(f\"R-squared (R2): {r2_cb2:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_cb2:.2f}%\")" ], "metadata": { "id": "y33kDe9rrpyC", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "f26dcddc-f8ae-4bd6-b7e4-49c2e0500fbd" }, "execution_count": 76, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Evaluasi Model CatBoost (df_new2)\n", "Mean Absolute Error (MAE): 417138162.66\n", "Mean Squared Error (MSE): 288506045478334464.00\n", "Root Mean Squared Error (RMSE): 537127587.71\n", "R-squared (R2): 0.65\n", "Mean Absolute Percentage Error (MAPE): 20.48%\n" ] } ] }, { "cell_type": "markdown", "source": [ "LightGBM" ], "metadata": { "id": "xYuGYS6LtvZU" } }, { "cell_type": "code", "source": [ "model_lgb2 = lgb.LGBMRegressor(objective='regression',\n", " metric='rmse',\n", " n_estimators=100,\n", " learning_rate=0.1,\n", " random_state=42,\n", " n_jobs=-1)\n", "\n", "# Melatih model menggunakan data latih dari df_new2\n", "# Menggunakan early_stopping_rounds untuk menghentikan training jika validasi tidak membaik\n", "model_lgb2.fit(X_train2, y_train2,\n", " eval_set=[(X_test2, y_test2)], # Data validasi\n", " eval_metric='rmse', # Metrik evaluasi pada data validasi\n", " callbacks=[lgb.early_stopping(10, verbose=False)]) # Stop jika validasi tidak membaik selama 10 iterasi\n", "\n", "# Melakukan prediksi pada data uji dari df_new2\n", "y_pred_lgb2 = model_lgb2.predict(X_test2)\n", "\n", "# # Evaluasi Model LightGBM untuk df_new2\n", "\n", "# Menghitung metrik evaluasi\n", "mae_lgb2 = mean_absolute_error(y_test2, y_pred_lgb2)\n", "mse_lgb2 = mean_squared_error(y_test2, y_pred_lgb2)\n", "rmse_lgb2 = np.sqrt(mse_lgb2)\n", "r2_lgb2 = r2_score(y_test2, y_pred_lgb2)\n", "mape_lgb2 = mean_absolute_percentage_error(y_test2, y_pred_lgb2)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"\\nEvaluasi Model LightGBM (df_new2)\")\n", "print(f\"Mean Absolute Error (MAE): {mae_lgb2:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_lgb2:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_lgb2:.2f}\")\n", "print(f\"R-squared (R2): {r2_lgb2:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_lgb2:.2f}%\")" ], "metadata": { "id": "rrSoBw-CrzfW", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "93b504af-0ec7-471f-f9aa-be838a5cd663" }, "execution_count": 77, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.167803 seconds.\n", "You can set `force_row_wise=true` to remove the overhead.\n", "And if memory is not enough, you can set `force_col_wise=true`.\n", "[LightGBM] [Info] Total Bins 600\n", "[LightGBM] [Info] Number of data points in the train set: 16875, number of used features: 13\n", "[LightGBM] [Info] Start training from score 2383061810.145659\n", "\n", "Evaluasi Model LightGBM (df_new2)\n", "Mean Absolute Error (MAE): 395831028.18\n", "Mean Squared Error (MSE): 268234832053471520.00\n", "Root Mean Squared Error (RMSE): 517913923.40\n", "R-squared (R2): 0.67\n", "Mean Absolute Percentage Error (MAPE): 19.45%\n" ] } ] }, { "cell_type": "markdown", "source": [ "## Melakukan tuning dengan bayesian search" ], "metadata": { "id": "v-SpYmGFEBRr" } }, { "cell_type": "markdown", "source": [ "#### Tuning Random Forest Semua Faslitas" ], "metadata": { "id": "uP3vg6NOx7cP" } }, { "cell_type": "code", "source": [ "# Definisikan ruang pencarian hyperparameter untuk Random Forest\n", "# Sesuaikan rentang nilai berdasarkan pengetahuan domain atau percobaan awal\n", "param_space_rf = {\n", " 'n_estimators': Integer(1000, 2000), # Jumlah pohon dalam forest\n", " 'max_depth': Integer(10, 50), # Kedalaman maksimum pohon\n", " 'min_samples_split': Integer(2, 20), # Jumlah sampel minimum untuk memecah node internal\n", " 'min_samples_leaf': Integer(1, 10), # Jumlah sampel minimum yang diperlukan di node daun\n", " 'max_features': Real(0.5, 1.0, prior='uniform'), # Proporsi fitur yang dipertimbangkan untuk setiap split\n", " 'bootstrap': [True, False] # Apakah sampel bootstrap digunakan saat membangun pohon\n", "}\n", "\n", "# Karena skopt.BayesSearchCV mengoptimalkan fungsi tujuan yang ingin diminimalkan,\n", "# dan metrik default seperti 'neg_mean_absolute_error' sudah diminimalkan (lebih negatif lebih baik),\n", "# untuk MAPE, kita perlu mendefinisikan scorer kustom yang mengembalikan nilai negatif MAPE.\n", "# Scikit-learn scorers mengoptimalkan nilai yang lebih tinggi. Jadi, kita akan memaksimalkan (negatif MAPE).\n", "from sklearn.metrics import make_scorer\n", "\n", "# Fungsi untuk menghitung MAPE (diambil dari kode sebelumnya)\n", "def mean_absolute_percentage_error_scorer(y_true, y_pred):\n", " y_true, y_pred = np.array(y_true), np.array(y_pred)\n", " non_zero_indices = y_true != 0\n", " # Hitung MAPE hanya pada nilai non-zero y_true\n", " mape = np.mean(np.abs((y_true[non_zero_indices] - y_pred[non_zero_indices]) / y_true[non_zero_indices])) * 100\n", " return mape\n", "\n", "# Buat scorer kustom dari fungsi MAPE.\n", "# make_scorer akan mengembalikan objek scorer yang cocok untuk digunakan dalam tuning.\n", "# greater_is_better=False menunjukkan bahwa nilai yang lebih rendah lebih baik (kita ingin meminimalkan MAPE).\n", "mape_scorer = make_scorer(mean_absolute_percentage_error_scorer, greater_is_better=False)\n", "\n", "# Inisialisasi model Random Forest Regressor\n", "estimator_rf = RandomForestRegressor(random_state=42)\n", "\n", "# Inisialisasi BayesSearchCV\n", "# estimator: model yang akan dituning\n", "# search_spaces: ruang pencarian hyperparameter\n", "# n_iter: jumlah iterasi optimasi Bayesian (semakin besar semakin baik, tapi butuh waktu)\n", "# cv: jumlah lipatan untuk cross-validation\n", "# scoring: metrik evaluasi yang akan digunakan (kita gunakan scorer MAPE kustom)\n", "# n_jobs: jumlah core CPU yang akan digunakan (-1 berarti semua yang tersedia)\n", "# random_state: seed untuk hasil yang konsisten\n", "# verbose: tingkat verbositas output\n", "bayes_search_rf = BayesSearchCV(\n", " estimator=estimator_rf,\n", " search_spaces=param_space_rf,\n", " n_iter=50, # Jumlah iterasi optimasi, sesuaikan sesuai waktu yang Anda miliki\n", " cv=3, # Gunakan 3-Fold Cross-Validation\n", " scoring=mape_scorer, # Gunakan scorer MAPE kustom\n", " n_jobs=-1,\n", " random_state=42,\n", " verbose=2 # Tampilkan output progress\n", ")\n", "\n", "print(\"Memulai Bayesian Optimization untuk Random Forest (Mengoptimalkan MAPE)...\")\n", "# Lakukan pencarian optimasi\n", "# Ini akan melatih model berkali-kali dengan kombinasi parameter yang berbeda\n", "bayes_search_rf.fit(X_train, y_train)\n", "print(\"Bayesian Optimization selesai.\")\n", "\n", "# Dapatkan parameter terbaik dan skor terbaik\n", "print(\"\\nHasil Terbaik dari Bayesian Optimization:\")\n", "print(f\"Parameter Terbaik: {bayes_search_rf.best_params_}\")\n", "# best_score_ adalah skor validasi rata-rata dari cross-validation dengan parameter terbaik.\n", "# Karena kita menggunakan scorer MAPE kustom dengan greater_is_better=False,\n", "# nilai ini adalah NEGATIF dari rata-rata MAPE terbaik.\n", "print(f\"Rata-rata Negatif MAPE Terbaik (CV): {bayes_search_rf.best_score_}\")\n", "# Nilai MAPE sebenarnya adalah negatif dari best_score_\n", "print(f\"Rata-rata MAPE Terbaik (CV): {-bayes_search_rf.best_score_:.2f}%\")\n", "\n", "\n", "# Evaluasi model terbaik pada data uji terpisah (X_test, y_test)\n", "print(\"\\nEvaluasi Model Random Forest Terbaik pada Data Uji:\")\n", "best_rf_model = bayes_search_rf.best_estimator_\n", "y_pred_best_rf = best_rf_model.predict(X_test)\n", "\n", "# Hitung metrik evaluasi pada data uji menggunakan model terbaik\n", "mae_best_rf = mean_absolute_error(y_test, y_pred_best_rf)\n", "mse_best_rf = mean_squared_error(y_test, y_pred_best_rf)\n", "rmse_best_rf = np.sqrt(mse_best_rf)\n", "r2_best_rf = r2_score(y_test, y_pred_best_rf)\n", "mape_best_rf = mean_absolute_percentage_error_scorer(y_test, y_pred_best_rf) # Gunakan fungsi MAPE biasa\n", "\n", "# Tampilkan hasil evaluasi pada data uji\n", "print(f\"Mean Absolute Error (MAE): {mae_best_rf:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_best_rf:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_best_rf:.2f}\")\n", "print(f\"R-squared (R2): {r2_best_rf:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_best_rf:.2f}%\")\n", "\n", "# Anda bisa membandingkan nilai MAPE yang dihasilkan dengan target Anda (<10%).\n", "# Perlu diingat bahwa hasil pada data uji mungkin sedikit berbeda dari rata-rata CV." ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "k02iLzESyCG7", "outputId": "86f11dfc-900f-46ac-c0fb-8ae12daa2031" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Memulai Bayesian Optimization untuk Random Forest (Mengoptimalkan MAPE)...\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Bayesian Optimization selesai.\n", "\n", "Hasil Terbaik dari Bayesian Optimization:\n", "Parameter Terbaik: OrderedDict([('bootstrap', False), ('max_depth', 28), ('max_features', 0.5), ('min_samples_leaf', 1), ('min_samples_split', 2), ('n_estimators', 1704)])\n", "Rata-rata Negatif MAPE Terbaik (CV): -17.41335183283549\n", "Rata-rata MAPE Terbaik (CV): 17.41%\n", "\n", "Evaluasi Model Random Forest Terbaik pada Data Uji:\n", "Mean Absolute Error (MAE): 332753756.71\n", "Mean Squared Error (MSE): 232456813719354784.00\n", "Root Mean Squared Error (RMSE): 482137753.88\n", "R-squared (R2): 0.72\n", "Mean Absolute Percentage Error (MAPE): 16.27%\n" ] } ] }, { "cell_type": "markdown", "source": [ "Parameter Terbaik: OrderedDict([('bootstrap', False), ('max_depth', 28), ('max_features', 0.5), ('min_samples_leaf', 1), ('min_samples_split', 2), ('n_estimators', 1704)])" ], "metadata": { "id": "IiOHn4-zTsg6" } }, { "cell_type": "markdown", "source": [ "#### Tuning LightGBM Semua Faslitas" ], "metadata": { "id": "q6GBe5IbI3j4" } }, { "cell_type": "code", "source": [ "# Definisikan ruang pencarian hyperparameter untuk LightGBM\n", "param_space_lgbm = {\n", " 'n_estimators': Integer(1000, 2000), # Jumlah boosting rounds\n", " 'learning_rate': Real(0.01, 0.2, prior='log-uniform'), # Ukuran langkah shrinkase\n", " 'num_leaves': Integer(20, 100), # Jumlah daun maksimum per pohon\n", " 'max_depth': Integer(-1, 15), # Kedalaman maksimum pohon (-1 berarti tidak terbatas)\n", " 'min_child_samples': Integer(5, 50), # Jumlah sampel minimum di node daun\n", " 'subsample': Real(0.6, 1.0, prior='uniform'), # Rasio subsample dari data pelatihan\n", " 'colsample_bytree': Real(0.6, 1.0, prior='uniform'), # Rasio subsample kolom untuk setiap pohon\n", " 'reg_alpha': Real(1e-9, 100, prior='log-uniform'), # Regularisasi L1\n", " 'reg_lambda': Real(1e-9, 100, prior='log-uniform'), # Regularisasi L2\n", "}\n", "\n", "# Inisialisasi model LightGBM Regressor\n", "estimator_lgbm = lgb.LGBMRegressor(objective='regression',\n", " metric='rmse', # Metrik evaluasi untuk LightGBM, tapi BayesSearchCV akan pakai 'scoring'\n", " random_state=42,\n", " n_jobs=-1) # Menggunakan semua core CPU yang tersedia\n", "\n", "# Inisialisasi BayesSearchCV untuk LightGBM (df_new)\n", "bayes_search_lgbm = BayesSearchCV(\n", " estimator=estimator_lgbm,\n", " search_spaces=param_space_lgbm,\n", " n_iter=50, # Jumlah iterasi optimasi, sesuaikan sesuai waktu yang Anda miliki\n", " cv=3, # Gunakan 3-Fold Cross-Validation\n", " scoring=mape_scorer, # Gunakan scorer MAPE kustom (kita akan minimalkan MAPE)\n", " n_jobs=-1, # Gunakan semua core untuk paralelisme dalam pencarian\n", " random_state=42,\n", " verbose=2 # Tampilkan output progress\n", ")\n", "\n", "print(\"Memulai Bayesian Optimization untuk LightGBM (Mengoptimalkan MAPE) pada df_new...\")\n", "# Lakukan pencarian optimasi\n", "bayes_search_lgbm.fit(X_train, y_train)\n", "print(\"Bayesian Optimization pada df_new selesai.\")\n", "\n", "# Dapatkan parameter terbaik dan skor terbaik\n", "print(\"\\nHasil Terbaik dari Bayesian Optimization (LightGBM, df_new):\")\n", "print(f\"Parameter Terbaik: {bayes_search_lgbm.best_params_}\")\n", "# best_score_ adalah skor validasi rata-rata dari cross-validation dengan parameter terbaik.\n", "# Karena kita menggunakan scorer MAPE kustom dengan greater_is_better=False,\n", "# nilai ini adalah NEGATIF dari rata-rata MAPE terbaik.\n", "print(f\"Rata-rata Negatif MAPE Terbaik (CV): {bayes_search_lgbm.best_score_}\")\n", "# Nilai MAPE sebenarnya adalah negatif dari best_score_\n", "print(f\"Rata-rata MAPE Terbaik (CV): {-bayes_search_lgbm.best_score_:.2f}%\")\n", "\n", "\n", "# Evaluasi model terbaik pada data uji terpisah (X_test, y_test)\n", "print(\"\\nEvaluasi Model LightGBM Terbaik pada Data Uji (df_new):\")\n", "best_lgbm_model = bayes_search_lgbm.best_estimator_\n", "y_pred_best_lgbm = best_lgbm_model.predict(X_test)\n", "\n", "# Hitung metrik evaluasi pada data uji menggunakan model terbaik\n", "mae_best_lgbm = mean_absolute_error(y_test, y_pred_best_lgbm)\n", "mse_best_lgbm = mean_squared_error(y_test, y_pred_best_lgbm)\n", "rmse_best_lgbm = np.sqrt(mse_best_lgbm)\n", "r2_best_lgbm = r2_score(y_test, y_pred_best_lgbm)\n", "mape_best_lgbm = mean_absolute_percentage_error_scorer(y_test, y_pred_best_lgbm) # Gunakan fungsi MAPE biasa\n", "\n", "# Tampilkan hasil evaluasi pada data uji\n", "print(f\"Mean Absolute Error (MAE): {mae_best_lgbm:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_best_lgbm:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_best_lgbm:.2f}\")\n", "print(f\"R-squared (R2): {r2_best_lgbm:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_best_lgbm:.2f}%\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "KmkEm_bRIwRl", "outputId": "f6b2c6e6-28ee-4a44-8393-3cbc415acf08" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Memulai Bayesian Optimization untuk LightGBM (Mengoptimalkan MAPE) pada df_new...\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "[LightGBM] [Info] Auto-choosing col-wise multi-threading, the overhead of testing was 0.007979 seconds.\n", "You can set `force_col_wise=true` to remove the overhead.\n", "[LightGBM] [Info] Total Bins 660\n", "[LightGBM] [Info] Number of data points in the train set: 16781, number of used features: 33\n", "[LightGBM] [Info] Start training from score 2390080749.018533\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "Bayesian Optimization pada df_new selesai.\n", "\n", "Hasil Terbaik dari Bayesian Optimization (LightGBM, df_new):\n", "Parameter Terbaik: OrderedDict([('colsample_bytree', 0.7830145038177853), ('learning_rate', 0.037147275427667034), ('max_depth', 15), ('min_child_samples', 5), ('n_estimators', 2000), ('num_leaves', 100), ('reg_alpha', 1e-09), ('reg_lambda', 1e-09), ('subsample', 1.0)])\n", "Rata-rata Negatif MAPE Terbaik (CV): -17.517984130011488\n", "Rata-rata MAPE Terbaik (CV): 17.52%\n", "\n", "Evaluasi Model LightGBM Terbaik pada Data Uji (df_new):\n", "Mean Absolute Error (MAE): 341784485.78\n", "Mean Squared Error (MSE): 228333511854738592.00\n", "Root Mean Squared Error (RMSE): 477842559.69\n", "R-squared (R2): 0.72\n", "Mean Absolute Percentage Error (MAPE): 16.67%\n" ] } ] }, { "cell_type": "markdown", "source": [ "Parameter Terbaik: OrderedDict([('colsample_bytree', 0.7830145038177853), ('learning_rate', 0.037147275427667034), ('max_depth', 15), ('min_child_samples', 5), ('n_estimators', 2000), ('num_leaves', 100), ('reg_alpha', 1e-09), ('reg_lambda', 1e-09), ('subsample', 1.0)])" ], "metadata": { "id": "N8pZEV63T7ct" } }, { "cell_type": "markdown", "source": [ "#### Tuning Random Forest Faslitas Tertentu" ], "metadata": { "id": "M8_s4pDjIn-s" } }, { "cell_type": "code", "source": [ "# Definisikan ruang pencarian hyperparameter untuk Random Forest\n", "# Sama seperti sebelumnya, sesuaikan rentang jika perlu\n", "param_space_rf2 = {\n", " 'n_estimators': Integer(1000, 2000), # Jumlah pohon dalam forest\n", " 'max_depth': Integer(10, 50), # Kedalaman maksimum pohon\n", " 'min_samples_split': Integer(2, 20), # Jumlah sampel minimum untuk memecah node internal\n", " 'min_samples_leaf': Integer(1, 10), # Jumlah sampel minimum yang diperlukan di node daun\n", " 'max_features': Real(0.5, 1.0, prior='uniform'), # Proporsi fitur yang dipertimbangkan untuk setiap split\n", " 'bootstrap': [True, False] # Apakah sampel bootstrap digunakan saat membangun pohon\n", "}\n", "\n", "# Kita akan menggunakan scorer MAPE kustom yang sama seperti sebelumnya\n", "# Pastikan fungsi mean_absolute_percentage_error_scorer sudah didefinisikan di notebook Anda\n", "# from sklearn.metrics import make_scorer\n", "# def mean_absolute_percentage_error_scorer(y_true, y_pred): ... (kode fungsi)\n", "# mape_scorer = make_scorer(mean_absolute_percentage_error_scorer, greater_is_better=False)\n", "\n", "# Inisialisasi model Random Forest Regressor\n", "estimator_rf2 = RandomForestRegressor(random_state=42)\n", "\n", "# Inisialisasi BayesSearchCV untuk df_new2\n", "bayes_search_rf2 = BayesSearchCV(\n", " estimator=estimator_rf2,\n", " search_spaces=param_space_rf2,\n", " n_iter=50, # Jumlah iterasi optimasi, sesuaikan sesuai waktu yang Anda miliki\n", " cv=3, # Gunakan 3-Fold Cross-Validation\n", " scoring=mape_scorer, # Gunakan scorer MAPE kustom\n", " n_jobs=-1,\n", " random_state=42,\n", " verbose=2 # Tampilkan output progress\n", ")\n", "\n", "print(\"\\nMemulai Bayesian Optimization untuk Random Forest (Mengoptimalkan MAPE) pada df_new2...\")\n", "# Lakukan pencarian optimasi menggunakan data dari df_new2\n", "bayes_search_rf2.fit(X_train2, y_train2)\n", "print(\"Bayesian Optimization pada df_new2 selesai.\")\n", "\n", "# Dapatkan parameter terbaik dan skor terbaik untuk df_new2\n", "print(\"\\nHasil Terbaik dari Bayesian Optimization (df_new2):\")\n", "print(f\"Parameter Terbaik: {bayes_search_rf2.best_params_}\")\n", "print(f\"Rata-rata Negatif MAPE Terbaik (CV): {bayes_search_rf2.best_score_}\")\n", "print(f\"Rata-rata MAPE Terbaik (CV): {-bayes_search_rf2.best_score_:.2f}%\")\n", "\n", "\n", "# Evaluasi model terbaik pada data uji terpisah (X_test2, y_test2)\n", "print(\"\\nEvaluasi Model Random Forest Terbaik pada Data Uji (df_new2):\")\n", "best_rf_model2 = bayes_search_rf2.best_estimator_\n", "y_pred_best_rf2 = best_rf_model2.predict(X_test2)\n", "\n", "# Hitung metrik evaluasi pada data uji menggunakan model terbaik untuk df_new2\n", "mae_best_rf2 = mean_absolute_error(y_test2, y_pred_best_rf2)\n", "mse_best_rf2 = mean_squared_error(y_test2, y_pred_best_rf2)\n", "rmse_best_rf2 = np.sqrt(mse_best_rf2)\n", "r2_best_rf2 = r2_score(y_test2, y_pred_best_rf2)\n", "mape_best_rf2 = mean_absolute_percentage_error_scorer(y_test2, y_pred_best_rf2) # Gunakan fungsi MAPE biasa\n", "\n", "# Tampilkan hasil evaluasi pada data uji untuk df_new2\n", "print(f\"Mean Absolute Error (MAE): {mae_best_rf2:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_best_rf2:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_best_rf2:.2f}\")\n", "print(f\"R-squared (R2): {r2_best_rf2:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_best_rf2:.2f}%\")\n", "\n", "# Anda bisa membandingkan nilai MAPE yang dihasilkan dengan target Anda (<10%).\n", "# Perlu diingat bahwa hasil pada data uji mungkin sedikit berbeda dari rata-rata CV." ], "metadata": { "id": "uRgpgOGp0aYc", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "43416a62-46a5-452c-8c72-b4fe0c646bee" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Memulai Bayesian Optimization untuk Random Forest (Mengoptimalkan MAPE) pada df_new2...\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "/usr/local/lib/python3.11/dist-packages/joblib/externals/loky/process_executor.py:782: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.\n", " warnings.warn(\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "/usr/local/lib/python3.11/dist-packages/joblib/externals/loky/process_executor.py:782: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.\n", " warnings.warn(\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "/usr/local/lib/python3.11/dist-packages/joblib/externals/loky/process_executor.py:782: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.\n", " warnings.warn(\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "/usr/local/lib/python3.11/dist-packages/joblib/externals/loky/process_executor.py:782: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.\n", " warnings.warn(\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "/usr/local/lib/python3.11/dist-packages/joblib/externals/loky/process_executor.py:782: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.\n", " warnings.warn(\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Bayesian Optimization pada df_new2 selesai.\n", "\n", "Hasil Terbaik dari Bayesian Optimization (df_new2):\n", "Parameter Terbaik: OrderedDict([('bootstrap', False), ('max_depth', 34), ('max_features', 0.5), ('min_samples_leaf', 1), ('min_samples_split', 2), ('n_estimators', 2000)])\n", "Rata-rata Negatif MAPE Terbaik (CV): -17.440722256042932\n", "Rata-rata MAPE Terbaik (CV): 17.44%\n", "\n", "Evaluasi Model Random Forest Terbaik pada Data Uji (df_new2):\n", "Mean Absolute Error (MAE): 337560411.23\n", "Mean Squared Error (MSE): 250825742621526528.00\n", "Root Mean Squared Error (RMSE): 500825061.89\n", "R-squared (R2): 0.69\n", "Mean Absolute Percentage Error (MAPE): 16.49%\n" ] } ] }, { "cell_type": "markdown", "source": [ "Parameter Terbaik: OrderedDict([('bootstrap', False), ('max_depth', 34), ('max_features', 0.5), ('min_samples_leaf', 1), ('min_samples_split', 2), ('n_estimators', 2000)])" ], "metadata": { "id": "7JBYJWeFUCxg" } }, { "cell_type": "markdown", "source": [ "#### Tuning LightGBM Faslitas Tertentu" ], "metadata": { "id": "ZzIVlIHJJFtV" } }, { "cell_type": "code", "source": [ "# Definisikan ruang pencarian hyperparameter untuk LightGBM df_new2\n", "param_space_lgbm2 = {\n", " 'n_estimators': Integer(1000, 2000),\n", " 'learning_rate': Real(0.01, 0.2, prior='log-uniform'),\n", " 'num_leaves': Integer(20, 100),\n", " 'max_depth': Integer(-1, 15),\n", " 'min_child_samples': Integer(5, 50),\n", " 'subsample': Real(0.6, 1.0, prior='uniform'),\n", " 'colsample_bytree': Real(0.6, 1.0, prior='uniform'),\n", " 'reg_alpha': Real(1e-9, 100, prior='log-uniform'),\n", " 'reg_lambda': Real(1e-9, 100, prior='log-uniform'),\n", "}\n", "\n", "# Inisialisasi model LightGBM Regressor\n", "estimator_lgbm2 = lgb.LGBMRegressor(objective='regression',\n", " metric='rmse',\n", " random_state=42,\n", " n_jobs=-1)\n", "\n", "# Inisialisasi BayesSearchCV untuk LightGBM (df_new2)\n", "bayes_search_lgbm2 = BayesSearchCV(\n", " estimator=estimator_lgbm2,\n", " search_spaces=param_space_lgbm2,\n", " n_iter=50, # Jumlah iterasi optimasi, sesuaikan sesuai waktu yang Anda miliki\n", " cv=3, # Gunakan 3-Fold Cross-Validation\n", " scoring=mape_scorer, # Gunakan scorer MAPE kustom\n", " n_jobs=-1, # Gunakan semua core untuk paralelisme dalam pencarian\n", " random_state=42,\n", " verbose=2 # Tampilkan output progress\n", ")\n", "\n", "print(\"\\nMemulai Bayesian Optimization untuk LightGBM (Mengoptimalkan MAPE) pada df_new2...\")\n", "# Lakukan pencarian optimasi menggunakan data dari df_new2\n", "bayes_search_lgbm2.fit(X_train2, y_train2)\n", "print(\"Bayesian Optimization pada df_new2 selesai.\")\n", "\n", "# Dapatkan parameter terbaik dan skor terbaik untuk df_new2\n", "print(\"\\nHasil Terbaik dari Bayesian Optimization (LightGBM, df_new2):\")\n", "print(f\"Parameter Terbaik: {bayes_search_lgbm2.best_params_}\")\n", "print(f\"Rata-rata Negatif MAPE Terbaik (CV): {bayes_search_lgbm2.best_score_}\")\n", "print(f\"Rata-rata MAPE Terbaik (CV): {-bayes_search_lgbm2.best_score_:.2f}%\")\n", "\n", "\n", "# Evaluasi model terbaik pada data uji terpisah (X_test2, y_test2)\n", "print(\"\\nEvaluasi Model LightGBM Terbaik pada Data Uji (df_new2):\")\n", "best_lgbm_model2 = bayes_search_lgbm2.best_estimator_\n", "y_pred_best_lgbm2 = best_lgbm_model2.predict(X_test2)\n", "\n", "# Hitung metrik evaluasi pada data uji menggunakan model terbaik untuk df_new2\n", "mae_best_lgbm2 = mean_absolute_error(y_test2, y_pred_best_lgbm2)\n", "mse_best_lgbm2 = mean_squared_error(y_test2, y_pred_best_lgbm2)\n", "rmse_best_lgbm2 = np.sqrt(mse_best_lgbm2)\n", "r2_best_lgbm2 = r2_score(y_test2, y_pred_best_lgbm2)\n", "mape_best_lgbm2 = mean_absolute_percentage_error_scorer(y_test2, y_pred_best_lgbm2) # Gunakan fungsi MAPE biasa\n", "\n", "# Tampilkan hasil evaluasi pada data uji untuk df_new2\n", "print(f\"Mean Absolute Error (MAE): {mae_best_lgbm2:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_best_lgbm2:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_best_lgbm2:.2f}\")\n", "print(f\"R-squared (R2): {r2_best_lgbm2:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_best_lgbm2:.2f}%\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "7mvwOwpyIPuR", "outputId": "9e9b992e-308a-483e-8b8b-86e8fe605cd5" }, "execution_count": null, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Memulai Bayesian Optimization untuk LightGBM (Mengoptimalkan MAPE) pada df_new2...\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "Fitting 3 folds for each of 1 candidates, totalling 3 fits\n", "[LightGBM] [Info] Auto-choosing row-wise multi-threading, the overhead of testing was 0.001661 seconds.\n", "You can set `force_row_wise=true` to remove the overhead.\n", "And if memory is not enough, you can set `force_col_wise=true`.\n", "[LightGBM] [Info] Total Bins 600\n", "[LightGBM] [Info] Number of data points in the train set: 16781, number of used features: 13\n", "[LightGBM] [Info] Start training from score 2390080749.018533\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "[LightGBM] [Warning] No further splits with positive gain, best gain: -inf\n", "Bayesian Optimization pada df_new2 selesai.\n", "\n", "Hasil Terbaik dari Bayesian Optimization (LightGBM, df_new2):\n", "Parameter Terbaik: OrderedDict([('colsample_bytree', 1.0), ('learning_rate', 0.0557963963052729), ('max_depth', 14), ('min_child_samples', 5), ('n_estimators', 1570), ('num_leaves', 100), ('reg_alpha', 100.0), ('reg_lambda', 3.2996319298971227e-07), ('subsample', 0.6541752576377086)])\n", "Rata-rata Negatif MAPE Terbaik (CV): -18.049253739491775\n", "Rata-rata MAPE Terbaik (CV): 18.05%\n", "\n", "Evaluasi Model LightGBM Terbaik pada Data Uji (df_new2):\n", "Mean Absolute Error (MAE): 349262781.49\n", "Mean Squared Error (MSE): 246357945995794144.00\n", "Root Mean Squared Error (RMSE): 496344583.93\n", "R-squared (R2): 0.70\n", "Mean Absolute Percentage Error (MAPE): 17.20%\n" ] } ] }, { "cell_type": "markdown", "source": [ "Parameter Terbaik: OrderedDict([('colsample_bytree', 1.0), ('learning_rate', 0.0557963963052729), ('max_depth', 14), ('min_child_samples', 5), ('n_estimators', 1570), ('num_leaves', 100), ('reg_alpha', 100.0), ('reg_lambda', 3.2996319298971227e-07), ('subsample', 0.6541752576377086)])" ], "metadata": { "id": "A_WyPeQgUJIQ" } }, { "cell_type": "markdown", "source": [ "## Feature Selection" ], "metadata": { "id": "kI_5u0llep1G" } }, { "cell_type": "markdown", "source": [ "Membangun Model Menggunakan Parameter Terbaik dari Tuning" ], "metadata": { "id": "LvenUiH3Ps6i" } }, { "cell_type": "code", "source": [ "best_params_rf = {\n", " 'bootstrap': False,\n", " 'max_depth': 28,\n", " 'max_features': 0.5,\n", " 'min_samples_leaf': 1,\n", " 'min_samples_split': 2,\n", " 'n_estimators': 1704\n", "}\n", "\n", "model_rf_tuned = RandomForestRegressor(random_state=42, **best_params_rf)\n", "\n", "# Melatih model menggunakan data latih\n", "model_rf_tuned.fit(X_train, y_train)\n", "\n", "# Melakukan prediksi pada data uji\n", "y_pred_rf_tuned = model_rf_tuned.predict(X_test) # Renamed the prediction variable\n", "\n", "# # Evaluasi Model Random Forest\n", "\n", "# Menghitung metrik evaluasi\n", "# Make sure to use the new prediction variable name here as well\n", "mae_rf_tuned = mean_absolute_error(y_test, y_pred_rf_tuned)\n", "mse_rf_tuned = mean_squared_error(y_test, y_pred_rf_tuned)\n", "rmse_rf_tuned = np.sqrt(mse_rf_tuned)\n", "r2_rf_tuned = r2_score(y_test, y_pred_rf_tuned)\n", "mape_rf_tuned = mean_absolute_percentage_error(y_test, y_pred_rf_tuned)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"Evaluasi Model Random Forest Tuned\") # Updated print statement\n", "print(f\"Mean Absolute Error (MAE): {mae_rf_tuned:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_rf_tuned:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_rf_tuned:.2f}\")\n", "print(f\"R-squared (R2): {r2_rf_tuned:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_rf_tuned:.2f}%\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "eJ4f80g8iRVW", "outputId": "2f376efd-4dcd-43ac-8c34-03fe81e42f24" }, "execution_count": 62, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Evaluasi Model Random Forest Tuned\n", "Mean Absolute Error (MAE): 327465974.96\n", "Mean Squared Error (MSE): 227429394375061056.00\n", "Root Mean Squared Error (RMSE): 476895580.16\n", "R-squared (R2): 0.72\n", "Mean Absolute Percentage Error (MAPE): 15.78%\n" ] } ] }, { "cell_type": "code", "source": [ "# Mengambil fitur penting dari model Random Forest terbaik (df_new)\n", "# model_rf adalah model Random Forest yang dilatih pada data X_train (df_new) sebelumnya\n", "# Dapatkan feature importances dari model\n", "# Menggunakan model hasil tuning: model_rf_tuned\n", "feature_importances = model_rf_tuned.feature_importances_\n", "\n", "# Buat Series dari feature importances, dengan index adalah nama kolom dari X_train\n", "# Pastikan urutan importances sesuai dengan urutan kolom di X_train\n", "importance_series = pd.Series(feature_importances, index=X_train.columns)\n", "\n", "# Urutkan fitur berdasarkan nilai importance secara menurun\n", "sorted_importance = importance_series.sort_values(ascending=False)\n", "\n", "# Tampilkan fitur dan nilainya\n", "print(\"\\nFeature Importance dari Random Forest (df_new, Setelah Tuning):\")\n", "print(sorted_importance)\n", "\n", "# Visualisasi feature importance\n", "plt.figure(figsize=(10, 6))\n", "sns.barplot(x=sorted_importance.values, y=sorted_importance.index)\n", "plt.title('Feature Importance - Random Forest (df_new, Setelah Tuning)')\n", "plt.xlabel('Importance')\n", "plt.ylabel('Feature')\n", "plt.tight_layout()\n", "plt.show()\n", "\n", "# --- Melakukan Feature Selection berdasarkan threshold ---\n", "# Anda bisa memilih jumlah fitur teratas atau menetapkan threshold\n", "# Contoh: Pilih 10 fitur teratas\n", "num_top_features = 10\n", "top_features = sorted_importance.head(num_top_features).index.tolist()\n", "\n", "print(f\"\\n{num_top_features} Fitur Teratas berdasarkan Random Forest Importance:\")\n", "top_features" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 1000 }, "id": "VwsHYYF5i79i", "outputId": "331e5c37-dd7f-47b6-9c51-584691653990" }, "execution_count": 29, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Feature Importance dari Random Forest (df_new, Setelah Tuning):\n", "s_luas_bangunan 0.355790\n", "s_luas_tanah 0.282135\n", "s_kamar_mandi 0.073084\n", "kabupaten_encoded 0.063242\n", "s_kamar_tidur 0.047353\n", "s_jumlah_lantai 0.026250\n", "s_sertifikat_encoded 0.014842\n", "poi_transportasi 0.012320\n", "poi_sekolah 0.011516\n", "poi_perbelanjaan 0.010496\n", "f_tempat_jemuran 0.008307\n", "f_keamanan_24_jam 0.008233\n", "f_taman 0.007608\n", "f_telepon 0.006641\n", "f_wastafel 0.006365\n", "f_akses_parkir 0.006034\n", "f_masjid 0.005763\n", "f_kitchen_set 0.005704\n", "f_one_gate_system 0.005555\n", "f_ac 0.005282\n", "f_teras 0.004945\n", "f_kolam_renang 0.004412\n", "f_cctv 0.004226\n", "f_laundry 0.003820\n", "f_tempat_cuci 0.003325\n", "f_water_heater 0.003245\n", "f_jogging_track 0.002538\n", "f_taman_bermain 0.002405\n", "f_kompor 0.002233\n", "f_kulkas 0.002025\n", "f_backyard 0.001622\n", "f_mesin_cuci 0.001422\n", "f_kolam_ikan 0.001225\n", "f_lapangan_basket 0.000012\n", "f_tempat_gym 0.000011\n", "f_lapangan_tenis 0.000011\n", "f_lapangan_bulu_tangkis 0.000001\n", "f_lapangan_voli 0.000001\n", "f_lapangan_bola 0.000001\n", "dtype: float64\n" ] }, { "output_type": "display_data", "data": { "text/plain": [ "
" ], "image/png": "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k7ve4GhERERERORWU9J9m0tKSiIxMZHk5GSCg4Px8fG56r7i4+P559sGl0vSLxQQEEBUVBQnT57kvffeu2T5zfbnn39ecRuDwcCSJUto37799Q9IRERERETKFCXdt7mMjAz8/f0JDw+/5r5MJtM1tbezs8PDw4OioiJCQkKuOR4REREREZHbnd7pvo3FxMQQGxuL2WzGYDAQFBR0Re2XL1+OyWRi/vz51v7OP92NiYlh3bp1xMfHYzAYMBgMZGZmAvDLL7/Qrl07PDw8cHd3p0WLFhd9N/utt97C398fb29v+vTpQ35+vrUsLy+PwYMHU6lSJVxdXbn33ntJTk62licmJuLp6cnKlSupVasWbm5utG3blqysrFLNKzk5mXvuuQdXV1c8PT1p3rw5v/76q7X8q6++omHDhjg5OREcHMzo0aMpKCgAsN7DDh06XNU9FRERERER+Sc96b6NxcfHU61aNWbNmkVqaipGo7HUbRcsWMCLL77IggULaNeu3SX73rt3L3Xq1GHMmDEA+Pr6cvjwYVq2bElERARr1qzBw8ODlJQUa9IKsHbtWvz9/Vm7di379+/n6aefpn79+vTs2ROAvn37snPnThYtWkRAQABLliyhbdu2bN++nerVqwNw+vRp3nrrLebNm0e5cuV47rnnGDx4sPUPBMUpKCigffv29OzZk4ULF3L27Fk2bdqEwWAAYP369XTt2pXp06db/1jQq1cvAEaOHElqaioVKlQgISGBtm3bXtE9FRERERERuZCS7tuYyWTC3d0do9GIn59fqdvNnDmT119/nW+++YZWrVoV27eDgwMuLi42fc+cOROTycSiRYuwt7cHoEaNGjZty5cvz4wZMzAajdSsWZNHH32U1atX07NnT8xmMwkJCZjNZus73oMHDyYpKYmEhATGjx8PQH5+Pu+//z7VqlUDziXq55P/kuTk5JCdnU27du2sbWvVqmUtHz16NK+99hrdunUDIDg4mLFjx/Lqq68ycuRIfH19AfD09Czxnubl5ZGXl2czroiIiIiIyIWUdJcxixcv5siRI6SkpNCkSZMrbp+WlkaLFi2sCfel3H333TZPiP39/dm+fTsA27dvp7Cw8KJEPS8vD29vb+u5i4uLNWk+38eRI0cuG5+XlxcxMTFERkby4IMP0qZNGzp16oS/vz8A6enppKSk8MYbb1jbFBYWcubMGU6fPo2Li8tlxwCYMGECo0ePLlVdEREREREpu5R0lzENGjRg69atzJkzh8aNG1uXXZeWs/PlP4d1YUJuMBgoKioCIDc3F6PRyJYtWy5auu3m5lZiH//cWb0kCQkJvPLKKyQlJfHpp58ybNgwVq1aRdOmTcnNzWX06NE88cQTF7W71GfOihMXF8fAgQOt5zk5OQQGBpa6vYiIiIiIlA1KusuYatWqMWXKFCIiIjAajcyYMaPYug4ODhQWFtpcq1u3LnPnziU/P7/Ep93FadCgAYWFhRw5coQWLVpccfsrGadBgwbExcXRrFkzFixYQNOmTWnYsCF79uwpcXd1e3v7i+Z9IUdHRxwdHa932CIiIiIicoe56t3L582bR/PmzQkICLDuDD1t2jS++uqr6xac3Bg1atRg7dq1fPHFF/Tv37/YekFBQWzcuJHMzEz++usvioqK6Nu3Lzk5OTzzzDNs3ryZffv2MW/ePPbs2VPqsTt37kzXrl358ssvOXjwIJs2bWLChAksX778mud28OBB4uLi2LBhA7/++ivfffcd+/bts77XPWLECD7++GNGjx7NL7/8wq5du1i0aBHDhg2zmffq1av53//+x/Hjx685JhERERERKbuuKul+7733GDhwII888ggnTpywPhX09PRk2rRp1zM+uUFCQ0NZs2YNCxcuZNCgQZesM3jwYIxGI7Vr18bX1xez2Yy3tzdr1qwhNzeXVq1a0ahRI2bPnn1FT70TEhLo2rUrgwYNIjQ0lPbt25OamkqVKlWueV4uLi7s3r2bjh07UqNGDXr16kWfPn3o3bs3AJGRkSxbtozvvvuOJk2a0LRpU95++22qVq1q7WPKlCmsWrWKwMBAGjRocM0xiYiIiIhI2WWwlPZF2X+oXbs248ePp3379ri7u5Oenk5wcDA7duwgIiKCv/7660bEKvKvlZOTg8lkIjs7Gw8Pj1sdjoiIiIiI3GClzQGu6kn3wYMHL/kE0NHRkVOnTl1NlyIiIiIiIiJ3nKvaSO2uu+4iLS3NZkkuQFJSks03kW9nFouF3r17s3jxYo4fP862bduoX7/+rQ6rWGazmdq1axdbvnPnzuuyfPvf4J+7nF9oxYoVN3SDtstpOWwhRsfL7/AOsGVy1xscjYiIiIiI3GpXlXQPHDiQPn36cObMGSwWC5s2bWLhwoVMmDCBDz/88HrHeEskJSWRmJhIcnIywcHB+Pj43OqQShQQEEBaWlqJ5ZczatQoli5dWmI//wbn46tevTrvvvsuDz74oLWsUqVKtygqERERERGRi11V0t2jRw+cnZ0ZNmwYp0+f5tlnnyUgIID4+HieeeaZ6x3jLZGRkYG/vz/h4eG3OpRSsbOzK/EzWHeSf87T39+/zMxbRERERERuP1f8TndBQQEff/wxbdq0Yd++feTm5vK///2P3377jRdeeOFGxHjTxcTEEBsbi9lsxmAwEBQUVGL9vLw8XnnlFSpUqICTkxP33Xcfqamp1vLk5GQMBgOrV6+mcePGuLi4EB4eftFntr766isaNmyIk5MTwcHBjB49moKCglLFvHv3bu677z6cnJyoXbs233//PQaDgaVLl1rrDB06lBo1auDi4kJwcDDDhw8nPz8fgMTEREaPHk16ejoGgwGDwUBiYiIAJ06coEePHvj6+uLh4UHr1q1JT08vVVzp6encf//9uLu74+HhQaNGjdi8eTOnTp3Cw8ODxYsX29RfunQprq6unDx5krNnz9K3b1/8/f1xcnKiatWqTJgwAcD6O+nQocNFv6PL3UeDwcAHH3xAu3btcHFxoVatWmzYsIH9+/cTERGBq6sr4eHhZGRklGqOIiIiIiIixbnipNvOzo4XX3yRM2fOAOc+0VShQoXrHtitFB8fz5gxY6hcuTJZWVk2CfSlvPrqq3zxxRfMnTuXrVu3EhISQmRkJMeOHbOp9/rrrzNlyhQ2b96MnZ0d3bt3t5atX7+erl270q9fP3bu3MkHH3xAYmIib7zxxmXjLSwspH379ri4uLBx40ZmzZrF66+/flE9d3d3EhMT2blzJ/Hx8cyePZu3334bgKeffppBgwZx9913k5WVRVZWFk8//TQATz31FEeOHGHFihVs2bKFhg0b8sADD1w0v0vp3LkzlStXJjU1lS1btvDaa69hb2+Pq6srzzzzDAkJCTb1ExISePLJJ3F3d2f69Ol8/fXXfPbZZ+zZs4f58+dbk+vzv5OEhASb31Fp7+PYsWPp2rUraWlp1KxZk2effZbevXsTFxfH5s2bsVgs9O3b97LzExERERERKZHlKrRq1cqyZMmSq2l623j77bctVatWvWy93Nxci729vWX+/PnWa2fPnrUEBARYJk2aZLFYLJa1a9daAMv3339vrbN8+XIL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hQq4urpSvnx5m0NERERERERErvI73UOGDGHt2rW89957dOnShZkzZ3L48GE++OADJk6ceL1jlDuIxWKhd+/eLF68mOPHj7Nt2zbq169/TX2azWZq165dbPnOnTupUqXKNY1RWi2HLcToePmd0LdM7noTohERERERkVvtqpLub775ho8//piIiAief/55WrRoQUhICFWrVmX+/Pl07tz5escpd4ikpCQSExNJTk4mODgYHx+fYutGRERQv359pk2bVmKfAQEBpKWllVguIiIiIiJyK1xV0n3s2DGCg4OBc+9vHzt2DID77ruPl1566fpFJ3ecjIwM/P39CQ8Pv2592tnZERISUmz5hXsOiIiIiIiI3CxX9U53cHAwBw8eBKBmzZp89tlnwLkn4J6entctOLmzxMTEEBsbi9lsxmAwEBQUVGLddevWER8fb/02fGZmJgA7duzg4Ycfxs3NjYoVK9KlSxf++usva9uIiAj69u1L//798fHxITIyEoCpU6cSFhaGq6srgYGBvPzyy+Tm5lrb/frrr0RFRVG+fHlcXV25++67+fbbb2/IvRARERERkbLhqpLu559/nvT0dABee+01Zs6ciZOTEwMGDGDIkCHXNUC5c8THxzNmzBgqV65MVlYWqampJdZt1qwZPXv2JCsri6ysLAIDAzlx4gStW7emQYMGbN68maSkJP744w86depk037u3Lk4ODiQkpLC+++/D5z7dNj06dP55ZdfmDt3LmvWrOHVV1+1tunTpw95eXn88MMPbN++nTfffBM3N7dLxpeXl0dOTo7NISIiIiIicqGrWl4+YMAA689t2rRh9+7dbNmyhZCQEOrWrXvdgpM7i8lkwt3dHaPRiJ+f32XrOjg44OLiYlN3xowZNGjQgPHjx1uvzZkzh8DAQPbu3UuNGjUAqF69OpMmTbLps3///tafg4KCGDduHC+++CLvvvsucG5Dto4dOxIWFgZgfYXiUiZMmMDo0aNLN3ERERERESmzrirp/qczZ85QtWpVqlatej3iESlReno6a9euveQT6IyMDGvS3ahRo4vKv//+eyZMmMDu3bvJycmhoKCAM2fOcPr0aVxcXHjllVd46aWX+O6772jTpg0dO3Ys9o9IcXFxDBw40Hqek5NDYGDgdZqliIiIiIjcKa5qeXlhYSFjx46lUqVKuLm5ceDAAQCGDx/O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cXR0ZM2aNWzZsoXu3btTUFBQ6vvatWtXFi5cyPTp09m1axcffPABbm5upWqbl5dHTk6OzSEiIiIiInIhLS+/DZhMJtzd3TEajZdd8mwymXBwcMDFxcWm7owZM2jQoAHjx4+3XpszZw6BgYHs3buXGjVqAFCvXj2GDRsGQFxcHBMnTsTHx4eePXsCMGLECN577z1+/vlnmjZtau1r5MiRPPjgg8C5xL1y5cosWbKETp06UalSJQYPHmytGxsby8qVK/nss8+45557io25JDNnzsRkMrFo0SLs7e0BrHMojb179/LZZ5+xatUq2rRpA0BwcHCp20+YMIHRo0eXur6IiIiIiJRNetJdRqSnp7N27Vrc3NysR82aNQGsS7IB6tata/3ZaDTi7e1NWFiY9VrFihUBOHLkiE3/zZo1s/7s5eVFaGgou3btAqCwsJCxY8cSFhaGl5cXbm5urFy5ErPZfNXzSUtLo0WLFtaE+2raG41GWrVqdVXt4+LiyM7Oth6HDh26qn5EREREROTOpifdZURubi5RUVG8+eabF5X5+/tbf74wiTUYDDbXDAYDAEVFRaUee/LkycTHxzNt2jTCwsJwdXWlf//+nD179kqnYeXsfPFnuf6pXLlyF+1Ifn65e2naX46joyOOjo7X1IeIiIiIiNz59KT7DuTg4EBhYaHNtYYNG/LLL78QFBRESEiIzeHq6nrNY/73v/+1/nz8+HH27t1LrVq1gHPfwX788cd57rnnqFevHsHBwezdu/eyMZekbt26rF+/3iaR/idfX1+ysrKs54WFhTabu4WFhVFUVMS6detKPaaIiIiIiMiVUtJ9BwoKCmLjxo1kZmby119/UVRURJ8+fTh27BjR0dGkpqaSkZHBypUref75568o2S3OmDFjWL16NTt27CAmJgYfHx/at28PQPXq1Vm1ahU//fQTu3btonfv3vzxxx+Xjbkkffv2JScnh2eeeYbNmzezb98+5s2bx549ewBo3bo1y5cvZ/ny5ezevZuXXnrJZifyoKAgunXrRvfu3Vm6dCkHDx4kOTmZzz777JrvhYiIiIiIyHlaXn4HGjx4MN26daN27dr8/fffHDx4kKCgIFJSUhg6dCgPPfQQeXl5VK1albZt21Ku3LX/7WXixIn069ePffv2Ub9+fb755hscHBwAGDZsGAcOHCAyMhIXFxd69epF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L2rXro2fnx+hoaHWesOGDaNhw4ZERkYSERGBn58f7du3t+lr8ODBGI1Gateuja+vL2azmYCAAFJSUigsLOShhx4iLCyM/v374+npSblyN+6fzuXGLVeuHIsWLWLLli3UqVOHAQMGMHnyZJs+7OzsmD59Oh988AEBAQE8/vjjwLlPqX344YckJCQQFhZGq1atSExMtH5i7Fr9MC6aLZO7XnSIiIiIiEjZZLBYLJZbHYTI7S4nJweTyUR2djYeHh63OhwREREREbnBSpsD6Em3iIiIiIiIyA2ipPtfwGKx0KtXL7y8vDAYDKxYscLmk1b/POzt7YmMjLzpMY4aNYr69etftt78+fOLjf3uu+++8YFepdLO73JaDltIoyEf2xwiIiIiIlJ2affyf4GkpCQSExNJTk4mODgYT09P0tLSLln35MmTBAYG3twAOffOd2xs7GXrPfbYYxd9juu8Cz8TdjkGg4ElS5Zc9P65iIiIiIjI7UJJ979ARkYG/v7+hIeHW6+FhITcwogudv5p9eW4u7vj7u5+EyI65+zZs9bPg4mIiIiIiPzbaHn5LRYTE0NsbCxmsxmDwUBQUNBl6//zyW9eXh6vvPIKFSpUwMnJifvuu4/U1FSbNl9//TXVq1fHycmJ+++/n7lz52IwGDhx4oS1zuzZswkMDMTFxYUOHTowdepUPD09reUXLr8+H8dbb72Fv78/3t7e9OnTh/z8fGudrKwsHn30UZydnbnrrrtYsGABQUFBTJs27bL35fx96NChg819OR/Hhx9+yF133YWTkxNwbrXAfffdh6enJ97e3rRr146MjAybPn/77Teio6Px8vLC1dWVxo0bs3HjxkuOn5GRQXBwMH379kV7DYqIiIiIyNVS0n2LxcfHM2bMGCpXrkxWVtZFCfPlvPrqq3zxxRfMnTuXrVu3EhISQmRkJMeOHQPg4MGDPPnkk7Rv35709HR69+7N66+/btNHSkoKL774Iv369SMtLY0HH3yQN95447Jjr127loyMDNauXcvcuXNJTEwkMTHRWt61a1d+//13kpOT+eKLL5g1axZHjhwp1bzO34eEhISL7sv+/fv54osv+PLLL63L8E+dOsXAgQPZvHkzq1evply5cnTo0IGioiIAcnNzadWqFYcPH+brr78mPT2dV1991Vr+Tz///DP33Xcfzz77LDNmzMBgMFxUJy8vj5ycHJtDRERERETkQlpefouZTCbc3d0xGo34+fldUdtTp07x3nvvkZiYyMMPPwyce2K9atUqPvroI4YMGcIHH3xAaGio9TvWoaGh7Nixwyapfuedd3j44YcZPHgwADVq1OCnn35i2bJlJY5fvnx5ZsyYgdFopGbNmjz66KOsXr2anj17snv3br7//ntSU1Np3LgxAB9++CHVq1cv1dx8fX0B8PT0vOi+nD17lo8//thaB6Bjx442debMmYOvry87d+6kTp06LFiwgD///JPU1FS8vLyASy/h/+mnn2jXrh2vv/46gwYNKja+CRMmMHr06FLNRUREREREyi496b6NZWRkkJ+fT/Pmza3X7O3tueeee9i1axcAe/bsoUmTJjbt7rnnHpvzPXv2XHTtwvNLufvuuzEajdZzf39/65PsPXv2YGdnR8OGDa3lISEhlC9fvpSzK17VqlVtEm6Affv2ER0dTXBwMB4eHtbl6GazGYC0tDQaNGhgTbgvxWw28+CDDzJixIgSE26AuLg4srOzrcehQ4eubVIiIiIiInJH0pNuuWoX7kZuMBguuVz7enN1db3oWlRUFFWrVmX27NkEBARQVFREnTp1OHv2LADOzs6X7dfX15eAgAAWLlxI9+7dS/zAvaOjI46Ojlc/CRERERERKRP0pPs2Vq1aNRwcHEhJSbFey8/PJzU1ldq1awPnlpNv3rzZpt2F742HhoZedO1K3y2/UGhoKAUFBWzbts16bf/+/Rw/frzUfdjb21NYWHjZekePHmXPnj0MGzaMBx54gFq1al00Tt26dUlLS7O+634pzs7OLFu2DCcnJyIjIzl58mSpYxUREREREbkUJd23MVdXV1566SWGDBlCUlISO3fupGfPnpw+fZoXXngBgN69e7N7926GDh3K3r17+eyzz6ybnZ3fICw2NpZvv/2WqVOnsm/fPj744ANWrFhxyQ3ESqtmzZq0adOGXr16sWnTJrZt20avXr1wdnYudb9BQUGsXr2a//3vfyUm6+XLl8fb25tZs2axf/9+1qxZw8CBA23qREdH4+fnR/v27UlJSeHAgQN88cUXbNiwwaaeq6sry5cvx87Ojocffpjc3Nwrn7yIiIiIiMj/p6T7Njdx4kQ6duxIly5daNiwIfv372flypXWd6fvuusuFi9ezJdffkndunV57733rLuXn18e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n0wmU7smk8kAAI2NjRrnvWHDBsTHxyM8PByZmZnIz8+Hn58fbt++/YS1erS3334biYmJAO4tLX/zzTelOtzXXP0evtZafVetWgWVSiUdFRUVWqwBERERERE9L7h7+XNCT08PDQ0Natfc3Nzw5Zdfav1VZvcdP34cNjY2AICamhoUFxfD0dERAJCdnY2AgADMmTMHwL0Be3FxMZycnFotc2scHBzw7bffql1r7ln3OXPmYOXKlfj4449x9uxZBAUFtbluj6Kvrw99fX2tp0tERERERM8XznQ/J+zs7JCbm4uysjJcuXIFjY2NWLhwIa5evYpZs2YhLy8PpaWlOHjwIN588802DXZbEh0djSNHjqCgoADBwcEwNzfHtGnTAAD29vbIyMhATk4OCgsLsWDBAlRVVT2yzK1ZsGABzp07h/DwcBQXF2P37t3SjPaDM9k9e/bEa6+9hrCwMIwfPx59+/Z94roSERERERE9Dg66nxMrVqyAjo4OnJycYGFhgfLycvTu3RvZ2dloaGjA+PHj4ezsjKVLl8LU1BTduj1518fGxiI0NBTu7u64dOkS9u3bBz09PQBAREQE3Nzc4OfnB19fXyiVSmlA3lqZW/Piiy9i7969+Oqrr+Di4oLPPvtM2r384VnnP/zhD7h9+zbeeuutJ64nERERERHR45IJIURHF4KeLVlZWRg9ejRqampgamraoWX505/+hL/85S9Nnqnevn07li1bhl9++UX6Q0B7qq2thUKhgEqlgomJSbvnR0REREREHUvTMQCf6aZnyp///Gd4eHigV69eyM7OxoYNG7Bo0SIp/MaNG6isrERsbCwWLFjwVAbcRERERERELeHy8nYghEBISAjMzMwgk8mQn5/fYlxfX18sXbq01fTKy8vVXvv18PEkr+HqTN55550W6/jOO+8AAM6fP4+AgAA4OTkhJiYGy5cvx5o1a6Q01q9fj0GDBkGpVGLVqlWt5ieTyZCamtqONSIiIiIioq6Oy8vbQXp6OgICApCVlYV+/frB3Ny8xd3DfX194erqio8++qjF9O7evYuysrIWw9trd/Kn7fLly6itrVW7FhgYCEdHR6xfvx4vvPCCVvO7dOkSevbsqZVdyLm8nIiIiIioa+Hy8g5UWloKKysrjBw5Uivp6erqYsCAAVpJqzN74YUXmgysDQ0NYWpqqvUBNwAolUqt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\n" }, "metadata": {} }, { "output_type": "stream", "name": "stdout", "text": [ "\n", "10 Fitur Teratas berdasarkan Random Forest Importance:\n" ] }, { "output_type": "execute_result", "data": { "text/plain": [ "['s_luas_bangunan',\n", " 's_luas_tanah',\n", " 's_kamar_mandi',\n", " 'kabupaten_encoded',\n", " 's_kamar_tidur',\n", " 's_jumlah_lantai',\n", " 's_sertifikat_encoded',\n", " 'poi_transportasi',\n", " 'poi_sekolah',\n", " 'poi_perbelanjaan']" ] }, "metadata": {}, "execution_count": 29 } ] }, { "cell_type": "markdown", "source": [ "10 fitur terbaik" ], "metadata": { "id": "JhHgSicnkI0Q" } }, { "cell_type": "code", "source": [ "# 'top_features' sudah didapatkan dari analisis feature importance sebelumnya\n", "# Pastikan variabel 'top_features' sudah terdefinisi dan berisi daftar nama kolom fitur terbaik\n", "\n", "# Pilih hanya kolom fitur terbaik dari X_train\n", "X_train_selected = X_train[top_features]\n", "\n", "# Pilih hanya kolom fitur terbaik dari X_test\n", "X_test_selected = X_test[top_features]\n", "\n", "\n", "best_params_rf = {\n", " 'bootstrap': False,\n", " 'max_depth': 28,\n", " 'max_features': 0.5, # Catatan: max_features 0.5 relatif terhadap jumlah fitur BARU (10)\n", " 'min_samples_leaf': 1,\n", " 'min_samples_split': 2,\n", " 'n_estimators': 1704\n", "}\n", "\n", "# Inisialisasi model Random Forest Regressor baru dengan parameter terbaik\n", "# Menggunakan model_rf_selected untuk membedakan dari model sebelumnya\n", "model_rf_selected = RandomForestRegressor(random_state=42, **best_params_rf)\n", "\n", "# Melatih model menggunakan data latih dengan fitur yang sudah dipilih\n", "model_rf_selected.fit(X_train_selected, y_train)\n", "\n", "# Langkah 3: Mengevaluasi model dengan 10 fitur terbaik pada data uji\n", "\n", "# Melakukan prediksi pada data uji dengan fitur yang sudah dipilih\n", "y_pred_rf_selected = model_rf_selected.predict(X_test_selected)\n", "\n", "# # Evaluasi Model Random Forest (dengan fitur terpilih)\n", "\n", "# Gunakan kembali fungsi mean_absolute_percentage_error yang sudah didefinisikan\n", "# Pastikan fungsi ini tersedia di lingkungan Anda\n", "# def mean_absolute_percentage_error(y_true, y_pred): ... (kode fungsi)\n", "\n", "\n", "# Menghitung metrik evaluasi\n", "mae_rf_selected = mean_absolute_error(y_test, y_pred_rf_selected)\n", "mse_rf_selected = mean_squared_error(y_test, y_pred_rf_selected)\n", "rmse_rf_selected = np.sqrt(mse_rf_selected)\n", "r2_rf_selected = r2_score(y_test, y_pred_rf_selected)\n", "mape_rf_selected = mean_absolute_percentage_error(y_test, y_pred_rf_selected)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"\\nEvaluasi Model Random Forest (dengan 10 fitur terbaik) pada Data Uji:\")\n", "print(f\"Mean Absolute Error (MAE): {mae_rf_selected:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_rf_selected:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_rf_selected:.2f}\")\n", "print(f\"R-squared (R2): {r2_rf_selected:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_rf_selected:.2f}%\")\n" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "ASn9ZjBAjhCe", "outputId": "f1dc97da-dd9d-4af1-8c9b-d453537da48d" }, "execution_count": 30, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Evaluasi Model Random Forest (dengan 10 fitur terbaik) pada Data Uji:\n", "Mean Absolute Error (MAE): 320638680.44\n", "Mean Squared Error (MSE): 236363402272989600.00\n", "Root Mean Squared Error (RMSE): 486172194.06\n", "R-squared (R2): 0.71\n", "Mean Absolute Percentage Error (MAPE): 15.60%\n" ] } ] }, { "cell_type": "markdown", "source": [ "6 fitur terbaik" ], "metadata": { "id": "0ZX0xEs2knWj" } }, { "cell_type": "code", "source": [ "num_top_features = 6\n", "top_features = sorted_importance.head(num_top_features).index.tolist()\n", "\n", "\n", "# Pilih hanya kolom fitur terbaik dari X_train, simpan di X_train_selected2\n", "X_train_selected2 = X_train[top_features]\n", "\n", "# Pilih hanya kolom fitur terbaik dari X_test, simpan di X_test_selected2\n", "X_test_selected2 = X_test[top_features]\n", "\n", "# Gunakan parameter terbaik yang sudah Anda temukan sebelumnya\n", "best_params_rf = {\n", " 'bootstrap': False,\n", " 'max_depth': 28,\n", " 'max_features': 0.5, # Catatan: max_features 0.5 relatif terhadap jumlah fitur BARU (6)\n", " 'min_samples_leaf': 1,\n", " 'min_samples_split': 2,\n", " 'n_estimators': 100\n", "}\n", "\n", "# Inisialisasi model Random Forest Regressor baru dengan parameter terbaik\n", "# Menggunakan model_rf_selected2\n", "model_rf_selected2 = RandomForestRegressor(random_state=42, **best_params_rf)\n", "\n", "# Melatih model menggunakan data latih dengan fitur yang sudah dipilih (X_train_selected2)\n", "model_rf_selected2.fit(X_train_selected2, y_train)\n", "\n", "# Langkah 3: Mengevaluasi model dengan 6 fitur terbaik pada data uji\n", "\n", "# Melakukan prediksi pada data uji dengan fitur yang sudah dipilih (X_test_selected2)\n", "y_pred_rf_selected2 = model_rf_selected2.predict(X_test_selected2)\n", "\n", "# # Evaluasi Model Random Forest (dengan 6 fitur terpilih)\n", "\n", "# Gunakan kembali fungsi mean_absolute_percentage_error yang sudah didefinisikan\n", "\n", "# Menghitung metrik evaluasi, simpan di variabel dengan suffix selected2\n", "mae_rf_selected2 = mean_absolute_error(y_test, y_pred_rf_selected2)\n", "mse_rf_selected2 = mean_squared_error(y_test, y_pred_rf_selected2)\n", "rmse_rf_selected2 = np.sqrt(mse_rf_selected2)\n", "r2_rf_selected2 = r2_score(y_test, y_pred_rf_selected2)\n", "mape_rf_selected2 = mean_absolute_percentage_error(y_test, y_pred_rf_selected2)\n", "\n", "# Menampilkan hasil evaluasi\n", "print(\"\\nEvaluasi Model Random Forest (dengan 6 fitur terbaik) pada Data Uji:\")\n", "print(f\"Mean Absolute Error (MAE): {mae_rf_selected2:.2f}\")\n", "print(f\"Mean Squared Error (MSE): {mse_rf_selected2:.2f}\")\n", "print(f\"Root Mean Squared Error (RMSE): {rmse_rf_selected2:.2f}\")\n", "print(f\"R-squared (R2): {r2_rf_selected2:.2f}\")\n", "print(f\"Mean Absolute Percentage Error (MAPE): {mape_rf_selected2:.2f}%\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "meE1UY8Hkskf", "outputId": "f15f6b08-12a4-464b-aab4-8b4d88b7cfd7" }, "execution_count": 31, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Evaluasi Model Random Forest (dengan 6 fitur terbaik) pada Data Uji:\n", "Mean Absolute Error (MAE): 334688657.40\n", "Mean Squared Error (MSE): 260753068038325824.00\n", "Root Mean Squared Error (RMSE): 510639861.39\n", "R-squared (R2): 0.68\n", "Mean Absolute Percentage Error (MAPE): 16.35%\n" ] } ] }, { "cell_type": "markdown", "source": [ "# Evaluasi" ], "metadata": { "id": "1RzdTyHNFnel" } }, { "cell_type": "code", "source": [ "# Hasil Random Forest Tuned (df_new)\n", "mae_tuned_rf = 332753756.71\n", "mse_tuned_rf = 232456813719354784.00\n", "rmse_tuned_rf = 482137753.88\n", "r2_tuned_rf = 0.72\n", "mape_tuned_rf = 16.27\n", "\n", "# Hasil LightGBM Tuned (df_new)\n", "mae_tuned_lgbm = 341784485.78\n", "mse_tuned_lgbm = 228333511854738592.00\n", "rmse_tuned_lgbm = 477842559.69\n", "r2_tuned_lgbm = 0.72\n", "mape_tuned_lgbm = 16.67\n", "\n", "# Hasil Random Forest Tuned (df_new2)\n", "mae_tuned_rf2 = 337560411.23\n", "mse_tuned_rf2 = 250825742621526528.00\n", "rmse_tuned_rf2 = 500825061.89\n", "r2_tuned_rf2 = 0.69\n", "mape_tuned_rf2 = 16.49\n", "\n", "# Hasil LightGBM Tuned (df_new2)\n", "mae_tuned_lgbm2 = 349262781.49\n", "mse_tuned_lgbm2 = 246357945995794144.00\n", "rmse_tuned_lgbm2 = 496344583.93\n", "r2_tuned_lgbm2 = 0.70\n", "mape_tuned_lgbm2 = 17.20\n", "\n", "# --- Kumpulkan semua hasil evaluasi, TERMASUK hasil tuning ---\n", "# Gunakan kembali variabel hasil model awal (rf, gb, xgb, cb, lgbm, rf2, gb2, xgb2, cb2, lgb2)\n", "# yang seharusnya sudah ada di memori dari eksekusi sel-sel sebelumnya.\n", "# Jika belum ada, Anda perlu menjalankan kembali sel-sel yang menghitungnya\n", "# atau memuatnya jika sudah disimpan.\n", "\n", "results_with_mape_and_tuning = {\n", " 'Model': [\n", " 'Random Forest (semua fasilitas)',\n", " 'Gradient Boosting (semua fasilitas)',\n", " 'XGBoost (semua fasilitas)',\n", " 'CatBoost (semua fasilitas)',\n", " 'LightGBM (semua fasilitas)',\n", " 'Random Forest (fasilitas tertentu)',\n", " 'Gradient Boosting (fasilitas tertentu)',\n", " 'XGBoost (fasilitas tertentu)',\n", " 'CatBoost (fasilitas tertentu)',\n", " 'LightGBM (fasilitas tertentu)',\n", " 'Random Forest Tuned (semua fasilitas)', # <-- Tambahan hasil tuning\n", " 'LightGBM Tuned (semua fasilitas)', # <-- Tambahan hasil tuning\n", " 'Random Forest Tuned (fasilitas tertentu)',# <-- Tambahan hasil tuning\n", " 'LightGBM Tuned (fasilitas tertentu)' # <-- Tambahan hasil tuning\n", " ],\n", " 'MAE': [\n", " mae_rf, mae_gb, mae_xgb, mae_cb, mae_lgbm,\n", " mae_rf2, mae_gb2, mae_xgb2, mae_cb2, mae_lgb2,\n", " mae_tuned_rf, mae_tuned_lgbm, mae_tuned_rf2, mae_tuned_lgbm2 # <-- Masukkan nilainya\n", " ],\n", " 'MSE': [\n", " mse_rf, mse_gb, mse_xgb, mse_cb, mse_lgbm,\n", " mse_rf2, mse_gb2, mse_xgb2, mse_cb2, mse_lgb2,\n", " mse_tuned_rf, mse_tuned_lgbm, mse_tuned_rf2, mse_tuned_lgbm2 # <-- Masukkan nilainya\n", " ],\n", " 'RMSE': [\n", " rmse_rf, rmse_gb, rmse_xgb, rmse_cb, rmse_lgbm,\n", " rmse_rf2, rmse_gb2, rmse_xgb2, rmse_cb2, rmse_lgb2,\n", " rmse_tuned_rf, rmse_tuned_lgbm, rmse_tuned_rf2, rmse_tuned_lgbm2 # <-- Masukkan nilainya\n", " ],\n", " 'R2': [\n", " r2_rf, r2_gb, r2_xgb, r2_cb, r2_lgbm,\n", " r2_rf2, r2_gb2, r2_xgb2, r2_cb2, r2_lgb2,\n", " r2_tuned_rf, r2_tuned_lgbm, r2_tuned_rf2, r2_tuned_lgbm2 # <-- Masukkan nilainya\n", " ],\n", " 'MAPE (%)': [\n", " mape_rf, mape_gb, mape_xgb, mape_cb, mape_lgbm,\n", " mape_rf2, mape_gb2, mape_xgb2, mape_cb2, mape_lgb2,\n", " mape_tuned_rf, mape_tuned_lgbm, mape_tuned_rf2, mape_tuned_lgbm2 # <-- Masukkan nilainya\n", " ]\n", "}\n", "\n", "# Buat DataFrame dari dictionary hasil yang diperbarui\n", "df_results_with_mape_and_tuning = pd.DataFrame(results_with_mape_and_tuning)\n", "\n", "# Tampilkan tabel hasil evaluasi yang baru\n", "print(\"\\nTabel Kumpulan Evaluasi Model Regresi (Termasuk Hasil Tuning)\")\n", "# Atur format tampilan untuk kolom angka\n", "# pd.options.display.float_format = '{:,.2f}'.format # Jika ingin format ribuan\n", "pd.options.display.float_format = '{:.2f}'.format # Hanya 2 angka desimal\n", "\n", "display(df_results_with_mape_and_tuning)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 523 }, "id": "tyTsA6kZVKl4", "outputId": "04cace44-d9a0-44d7-9b80-b82e9a95ef50" }, "execution_count": 78, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "\n", "Tabel Kumpulan Evaluasi Model Regresi (Termasuk Hasil Tuning)\n" ] }, { "output_type": "display_data", "data": { "text/plain": [ " Model MAE \\\n", "0 Random Forest (semua fasilitas) 340591445.36 \n", "1 Gradient Boosting (semua fasilitas) 418700931.06 \n", "2 XGBoost (semua fasilitas) 397052713.54 \n", "3 CatBoost (semua fasilitas) 409382988.70 \n", "4 LightGBM (semua fasilitas) 389476379.68 \n", "5 Random Forest (fasilitas tertentu) 339994351.55 \n", "6 Gradient Boosting (fasilitas tertentu) 421427023.73 \n", "7 XGBoost (fasilitas tertentu) 405544248.31 \n", "8 CatBoost (fasilitas tertentu) 417138162.66 \n", "9 LightGBM (fasilitas tertentu) 395831028.18 \n", "10 Random Forest Tuned (semua fasilitas) 332753756.71 \n", "11 LightGBM Tuned (semua fasilitas) 341784485.78 \n", "12 Random Forest Tuned (fasilitas tertentu) 337560411.23 \n", "13 LightGBM Tuned (fasilitas tertentu) 349262781.49 \n", "\n", " MSE RMSE R2 MAPE (%) \n", "0 231001733762805536.00 480626397.28 0.72 16.47 \n", "1 290482649647068288.00 538964423.36 0.65 20.61 \n", "2 267103514658796320.00 516820582.66 0.67 19.36 \n", "3 280091241391207424.00 529236470.20 0.66 20.03 \n", "4 258408876860365696.00 508339332.40 0.69 18.97 \n", "5 238970969089081728.00 488846570.09 0.71 16.49 \n", "6 293391967803029952.00 541656688.14 0.64 20.75 \n", "7 277747114339317472.00 527017186.00 0.66 19.77 \n", "8 288506045478334464.00 537127587.71 0.65 20.48 \n", "9 268234832053471520.00 517913923.40 0.67 19.45 \n", "10 232456813719354784.00 482137753.88 0.72 16.27 \n", "11 228333511854738592.00 477842559.69 0.72 16.67 \n", "12 250825742621526528.00 500825061.89 0.69 16.49 \n", "13 246357945995794144.00 496344583.93 0.70 17.20 " ], "text/html": [ "\n", "
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
ModelMAEMSERMSER2MAPE (%)
0Random Forest (semua fasilitas)340591445.36231001733762805536.00480626397.280.7216.47
1Gradient Boosting (semua fasilitas)418700931.06290482649647068288.00538964423.360.6520.61
2XGBoost (semua fasilitas)397052713.54267103514658796320.00516820582.660.6719.36
3CatBoost (semua fasilitas)409382988.70280091241391207424.00529236470.200.6620.03
4LightGBM (semua fasilitas)389476379.68258408876860365696.00508339332.400.6918.97
5Random Forest (fasilitas tertentu)339994351.55238970969089081728.00488846570.090.7116.49
6Gradient Boosting (fasilitas tertentu)421427023.73293391967803029952.00541656688.140.6420.75
7XGBoost (fasilitas tertentu)405544248.31277747114339317472.00527017186.000.6619.77
8CatBoost (fasilitas tertentu)417138162.66288506045478334464.00537127587.710.6520.48
9LightGBM (fasilitas tertentu)395831028.18268234832053471520.00517913923.400.6719.45
10Random Forest Tuned (semua fasilitas)332753756.71232456813719354784.00482137753.880.7216.27
11LightGBM Tuned (semua fasilitas)341784485.78228333511854738592.00477842559.690.7216.67
12Random Forest Tuned (fasilitas tertentu)337560411.23250825742621526528.00500825061.890.6916.49
13LightGBM Tuned (fasilitas tertentu)349262781.49246357945995794144.00496344583.930.7017.20
\n", "
\n", "
\n", "\n", "
\n", " \n", "\n", " \n", "\n", " \n", "
\n", "\n", "\n", "
\n", " \n", "\n", "\n", "\n", " \n", "
\n", "\n", "
\n", " \n", " \n", " \n", "
\n", "\n", "
\n", "
\n" ], "application/vnd.google.colaboratory.intrinsic+json": { "type": "dataframe", "variable_name": "df_results_with_mape_and_tuning", "summary": "{\n \"name\": \"df_results_with_mape_and_tuning\",\n \"rows\": 14,\n \"fields\": [\n {\n \"column\": \"Model\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 14,\n \"samples\": [\n \"LightGBM (fasilitas tertentu)\",\n \"LightGBM Tuned (semua fasilitas)\",\n \"Random Forest (semua fasilitas)\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"MAE\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 35401934.713892296,\n \"min\": 332753756.71,\n \"max\": 421427023.7262506,\n \"num_unique_values\": 14,\n \"samples\": [\n 395831028.1794402,\n 341784485.78,\n 340591445.3638267\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"MSE\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 2.3206234131385456e+16,\n \"min\": 2.283335118547386e+17,\n \"max\": 2.9339196780302995e+17,\n \"num_unique_values\": 14,\n \"samples\": [\n 2.6823483205347152e+17,\n 2.283335118547386e+17,\n 2.3100173376280554e+17\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"RMSE\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 22767856.62269082,\n \"min\": 477842559.69,\n \"max\": 541656688.1365261,\n \"num_unique_values\": 14,\n \"samples\": [\n 517913923.4018251,\n 477842559.69,\n 480626397.2804714\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"R2\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.028187609656603625,\n \"min\": 0.6428721532432993,\n \"max\": 0.72,\n \"num_unique_values\": 13,\n \"samples\": [\n 0.69,\n 0.673494374390258,\n 0.71881591580871\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"MAPE (%)\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 1.785973294639698,\n \"min\": 16.27,\n \"max\": 20.752791600164073,\n \"num_unique_values\": 14,\n \"samples\": [\n 19.45145453091966,\n 16.67,\n 16.471807910846316\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" } }, "metadata": {} } ] }, { "cell_type": "markdown", "source": [ "# Simpan Model" ], "metadata": { "id": "Xeo4UGrp3FVo" } }, { "cell_type": "code", "source": [ "# Tentukan nama file untuk menyimpan model, encoder dan scaler\n", "model_filename = 'model.joblib'\n", "encoder_filename = 'label_encoder.joblib'\n", "scaler_filename = 'standard_scaler.joblib'\n", "\n", "# Simpan model ke file\n", "joblib.dump(model_rf, model_filename)\n", "\n", "# Simpan objek scaler (gunakan scaler atau scaler2 sesuai model terbaik Anda)\n", "joblib.dump(scaler, scaler_filename)\n", "\n", "print(f\"Model 'model_rf' telah disimpan ke '{model_filename}'\")\n", "print(f\"LabelEncoder telah disimpan ke '{encoder_filename}'\")\n", "print(f\"StandardScaler telah disimpan ke '{scaler_filename}'\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "Gil0GOq1y9oZ", "outputId": "0e0cd2be-0367-4125-e8cc-057749ac22c2" }, "execution_count": 67, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Model 'model_rf' telah disimpan ke 'model.joblib'\n", "LabelEncoder telah disimpan ke 'label_encoder.joblib'\n", "StandardScaler telah disimpan ke 'standard_scaler.joblib'\n" ] } ] } ] }