Machine Learning Regression hingga Menjadi REST API dengan FastAPI
Materi ini membahas proses membangun aplikasi Machine Learning Regression secara end-to-end, mulai dari pengolahan dataset menggunakan Jupyter Notebook sampai model dapat digunakan sebagai REST API dan dijalankan pada VPS.
Studi kasus yang digunakan adalah prediksi harga rumah berdasarkan:
- Luas rumah
- Jumlah kamar
- Jarak ke kota
- Kondisi rumah
Teknologi yang digunakan:
Python
Pandas
NumPy
Matplotlib
Scikit-learn
Joblib
Jupyter Notebook
FastAPI
Uvicorn
PM2
Nginx
VPS
Alur keseluruhan project:
Dataset
↓
Jupyter Notebook
↓
Data Exploration
↓
Data Cleaning
↓
Visualisasi
↓
Preprocessing
↓
Train-Test Split
↓
Membandingkan Algoritma
↓
Evaluasi
↓
Memilih Model
↓
Menyimpan Model
↓
FastAPI
↓
Testing API
↓
Upload ke VPS
↓
Uvicorn
↓
PM2
↓
Nginx
↓
HTTPS
↓
Production API
1. Apa Itu Machine Learning Regression?
Regression adalah salah satu jenis supervised learning yang digunakan untuk memprediksi nilai numerik.
Contohnya:
Luas rumah → Harga rumah
Luas tanah → Harga tanah
Umur kendaraan → Harga kendaraan
Jam belajar → Nilai ujian
Jumlah penduduk → Konsumsi listrik
Misalnya kita mempunyai data:
| Luas | Kamar | Jarak Kota | Kondisi | Harga |
|---|---|---|---|---|
| 80 | 2 | 10 | sedang | 425000000 |
| 120 | 3 | 5 | baik | 750000000 |
| 150 | 4 | 3 | baik | 1100000000 |
Model belajar dari hubungan antara:
Feature
↓
Harga
Setelah model selesai dilatih, kita dapat memberikan rumah baru:
Luas = 120
Kamar = 3
Jarak kota = 5
Kondisi = baik
dan model menghasilkan:
Prediksi harga = Rp xxx.xxx.xxx
2. Regression vs Classification
Regression dan classification sama-sama dapat menggunakan supervised learning, tetapi target yang diprediksi berbeda.
Regression
Output berupa angka.
Prediksi harga
Prediksi suhu
Prediksi pendapatan
Prediksi penjualan
Contoh:
Rp 750.000.000
Classification
Output berupa kategori.
Spam
Tidak Spam
atau:
Baik
Sedang
Buruk
Secara sederhana:
Target angka → Regression
Target kategori → Classification
3. Studi Kasus Prediksi Harga Rumah
Kita akan membuat model:
Input
├── luas
├── jumlah_kamar
├── jarak_ke_kota
└── kondisi
↓
Machine Learning
↓
Output
└── harga
Contoh data:
| Feature | Contoh |
|---|---|
| luas | 120 |
| jumlah_kamar | 3 |
| jarak_ke_kota | 5 |
| kondisi | baik |
Target:
harga
4. Struktur Project
Struktur project yang akan digunakan:
prediksi-harga-rumah/
│
├── regression_harga_rumah.ipynb
├── rumah.csv
├── model_forest.joblib
├── main.py
├── requirements.txt
│
└── venv/
Keterangan:
regression_harga_rumah.ipynb
→ Notebook untuk training Machine Learning
rumah.csv
→ Dataset
model_forest.joblib
→ Model Machine Learning yang sudah dilatih
main.py
→ FastAPI
requirements.txt
→ Daftar dependency
venv/
→ Python virtual environment
5. Menyiapkan Environment Python
Sebaiknya setiap project mempunyai environment sendiri agar dependency tidak saling bertabrakan.
Jika menggunakan Conda:
conda create -n house_regression python=3.12
Aktifkan:
conda activate house_regression
Install library:
pip install pandas numpy matplotlib scikit-learn joblib jupyterlab
Jalankan Jupyter:
jupyter lab
Bagian Jupyter Notebook
6. Membuat Notebook
Buat file:
regression_harga_rumah.ipynb
Notebook inilah yang akan digunakan untuk seluruh proses Machine Learning.
Tahapan notebook:
Import Library
↓
Dataset
↓
Data Inspection
↓
Data Cleaning
↓
EDA
↓
Visualisasi
↓
Feature & Target
↓
Train-Test Split
↓
Preprocessing
↓
Model Training
↓
Model Comparison
↓
Evaluation
↓
Model Selection
↓
Prediction
↓
Save Model
7. Import Library
Pada cell pertama:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import joblib
from sklearn.model_selection import train_test_split
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import (
OneHotEncoder,
StandardScaler
)
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LinearRegression
from sklearn.neighbors import KNeighborsRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import (
RandomForestRegressor,
GradientBoostingRegressor
)
from sklearn.metrics import (
mean_absolute_error,
mean_squared_error,
r2_score
)
from sklearn.inspection import permutation_importance
Library tersebut mempunyai fungsi berbeda.
NumPy
→ operasi numerik
Pandas
→ pengolahan dataset
Matplotlib
→ visualisasi
Scikit-learn
→ Machine Learning
Joblib
→ menyimpan model
8. Membuat Dataset Contoh
Jika belum mempunyai dataset sendiri, kita dapat membuat dataset simulasi.
8.1 Membuat Jumlah Data
np.random.seed(42)
jumlah_data = 500
Kita akan membuat:
500 rumah
8.2 Membuat Feature Luas
luas = np.random.randint(
40,
250,
jumlah_data
)
Nilai luas rumah akan berada pada kisaran:
40 – 249
8.3 Membuat Jumlah Kamar
jumlah_kamar = np.random.randint(
1,
6,
jumlah_data
)
8.4 Membuat Jarak ke Kota
jarak_ke_kota = np.random.randint(
1,
31,
jumlah_data
)
8.5 Membuat Kondisi Rumah
kondisi = np.random.choice(
[
"buruk",
"sedang",
"baik"
],
jumlah_data,
p=[
0.2,
0.4,
0.4
]
)
8.6 Memberikan Nilai untuk Kondisi
Kita membuat pengaruh kondisi rumah:
nilai_kondisi = {
"buruk": -100_000_000,
"sedang": 0,
"baik": 150_000_000
}
8.7 Membuat Harga
harga = (
luas * 5_000_000
+ jumlah_kamar * 30_000_000
- jarak_ke_kota * 8_000_000
+ np.array([
nilai_kondisi[k]
for k in kondisi
])
+ np.random.normal(
0,
60_000_000,
jumlah_data
)
)
Dalam dataset simulasi ini:
Luas lebih besar
→ harga cenderung lebih tinggi
Jumlah kamar lebih banyak
→ harga cenderung lebih tinggi
Jarak ke kota semakin jauh
→ harga cenderung lebih rendah
Kondisi baik
→ harga cenderung lebih tinggi
8.8 Membuat DataFrame
df = pd.DataFrame({
"luas": luas,
"jumlah_kamar": jumlah_kamar,
"jarak_ke_kota": jarak_ke_kota,
"kondisi": kondisi,
"harga": harga.astype(int)
})
8.9 Melihat Data
df.head()
8.10 Menyimpan Dataset
df.to_csv(
"rumah.csv",
index=False
)
Jika dataset sudah tersedia, tahap pembuatan dataset dapat dilewati.
9. Membaca Dataset
Untuk project sebenarnya:
df = pd.read_csv(
"rumah.csv"
)
Kemudian:
df.head()
10. Melihat Dimensi Dataset
Gunakan:
df.shape
Contoh:
(500, 5)
Artinya:
500 baris
5 kolom
11. Melihat Nama Kolom
df.columns
Hasil:
luas
jumlah_kamar
jarak_ke_kota
kondisi
harga
12. Melihat Informasi Dataset
df.info()
Informasi ini berguna untuk mengetahui:
Jumlah baris
Nama kolom
Tipe data
Non-null value
Memory usage
13. Statistik Deskriptif
df.describe()
Kita dapat mengetahui:
count
mean
std
min
25%
50%
75%
max
Ini membantu memahami karakteristik data numerik.
14. Memeriksa Missing Value
df.isnull().sum()
Jika hasil:
luas 0
jumlah_kamar 0
jarak_ke_kota 0
kondisi 0
harga 0
berarti tidak terdapat missing value.
15. Memeriksa Data Duplikat
df.duplicated().sum()
Jika ditemukan duplicate:
df = df.drop_duplicates()
16. Memeriksa Data Kategorikal
df["kondisi"].unique()
Kemudian:
df["kondisi"].value_counts()
Kita dapat mengetahui jumlah rumah berdasarkan:
baik
sedang
buruk
Misalnya kita memiliki dataset yang Missing Value (NaN) rincian:
luas 6
jumlah_kamar 6
jarak_ke_kota 6
kondisi 6
harga 0
dtype: int64
Kita dapat melakukan preprocessing dengan memasukan nilai Median:
# mengisi data Nan dengan nilai Median pada data numerik
df["luas"] = df["luas"].fillna(df["luas"].median())
df["jumlah_kamar"] = df["jumlah_kamar"].fillna(df["jumlah_kamar"].median())
df["jarak_ke_kota"] = df["jarak_ke_kota"].fillna(df["jarak_ke_kota"].median())
df["luas"] = df["luas"].fillna(df["luas"].median())
# .str.strip() -> menghilangkan spasi di awal/akhir.
# .str.lower() -> mengubah semuanya menjadi huruf kecil
df["kondisi"] = df["kondisi"].str.strip().str.lower()
# mengisi data Nan dengan nilai Median pada data string
# mode() -> mengambil nilai yang paling sering muncul (modus)
# [0] -> Hasil dari .mode() adalah sebuah Series, bukan satu nilai langsung.
# Contoh hasil: 0 baru, 1 bekas
df["kondisi"] = df["kondisi"].fillna(df["kondisi"].mode()[0])
# df["kondisi"].value_counts()
df.isna().sum() # cek data kosong
Sehingga hasilnya:
luas 0
jumlah_kamar 0
jarak_ke_kota 0
kondisi 0
harga 0
dtype: int64
Tidak terdapat lagi data yang Missing Value (NaN).
Exploratory Data Analysis
17. Mengapa EDA Penting?
EDA atau Exploratory Data Analysis digunakan untuk memahami data sebelum melakukan training.
EDA dapat membantu menemukan:
Distribusi data
Outlier
Missing value
Hubungan antar fitur
Hubungan feature dengan target
Data yang tidak masuk akal
Jangan langsung melakukan training sebelum memahami dataset.
18. Visualisasi Distribusi Harga
plt.figure(figsize=(8, 5))
plt.hist(
df["harga"],
bins=30
)
plt.title(
"Distribusi Harga Rumah"
)
plt.xlabel(
"Harga Rumah"
)
plt.ylabel(
"Jumlah Rumah"
)
plt.show()
Histogram menunjukkan distribusi nilai harga rumah.
19. Visualisasi Distribusi Luas
plt.figure(figsize=(8, 5))
plt.hist(
df["luas"],
bins=25
)
plt.title(
"Distribusi Luas Rumah"
)
plt.xlabel(
"Luas Rumah"
)
plt.ylabel(
"Jumlah Rumah"
)
plt.show()
20. Scatter Plot Luas vs Harga
plt.figure(figsize=(8, 5))
plt.scatter(
df["luas"],
df["harga"],
alpha=0.6
)
plt.title(
"Hubungan Luas Rumah dengan Harga"
)
plt.xlabel(
"Luas Rumah"
)
plt.ylabel(
"Harga Rumah"
)
plt.show()
Scatter plot membantu melihat hubungan antara:
luas
↓
harga
Jika titik cenderung bergerak naik dari kiri ke kanan, terdapat hubungan positif.
21. Scatter Plot Jarak vs Harga
plt.figure(figsize=(8, 5))
plt.scatter(
df["jarak_ke_kota"],
df["harga"],
alpha=0.6
)
plt.title(
"Hubungan Jarak ke Kota dengan Harga"
)
plt.xlabel(
"Jarak ke Kota"
)
plt.ylabel(
"Harga Rumah"
)
plt.show()
Pada dataset simulasi, semakin jauh jarak rumah dari kota, harga cenderung menurun.
22. Jumlah Kamar vs Harga
Hitung rata-rata harga:
harga_per_kamar = (
df.groupby(
"jumlah_kamar"
)["harga"]
.mean()
)
Visualisasikan:
plt.figure(figsize=(8, 5))
harga_per_kamar.plot(
kind="bar"
)
plt.title(
"Rata-rata Harga berdasarkan Jumlah Kamar"
)
plt.xlabel(
"Jumlah Kamar"
)
plt.ylabel(
"Rata-rata Harga"
)
plt.show()
23. Kondisi Rumah vs Harga
Hitung:
harga_kondisi = (
df.groupby(
"kondisi"
)["harga"]
.mean()
.sort_values()
)
Visualisasikan:
plt.figure(figsize=(8, 5))
harga_kondisi.plot(
kind="bar"
)
plt.title(
"Rata-rata Harga berdasarkan Kondisi Rumah"
)
plt.xlabel(
"Kondisi"
)
plt.ylabel(
"Rata-rata Harga"
)
plt.show()
24. Boxplot Harga
Boxplot dapat membantu melihat outlier.
plt.figure(figsize=(8, 4))
plt.boxplot(
df["harga"],
vert=False
)
plt.title(
"Boxplot Harga Rumah"
)
plt.xlabel(
"Harga"
)
plt.show()
25. Correlation Matrix
Ambil feature numerik:
numeric_df = df[
[
"luas",
"jumlah_kamar",
"jarak_ke_kota",
"harga"
]
]
Hitung korelasi:
correlation = numeric_df.corr()
correlation
Visualisasikan:
plt.figure(figsize=(8, 6))
plt.imshow(
correlation,
interpolation="nearest"
)
plt.title(
"Correlation Matrix"
)
plt.xticks(
range(len(correlation.columns)),
correlation.columns,
rotation=45
)
plt.yticks(
range(len(correlation.columns)),
correlation.columns
)
plt.colorbar()
for i in range(
len(correlation.columns)
):
for j in range(
len(correlation.columns)
):
plt.text(
j,
i,
f"{correlation.iloc[i, j]:.2f}",
ha="center",
va="center"
)
plt.tight_layout()
plt.show()
Korelasi berada pada rentang:
-1 sampai 1
Secara sederhana:
+1 → hubungan positif kuat
0 → hubungan linear lemah
-1 → hubungan negatif kuat
Namun korelasi tidak otomatis berarti hubungan sebab-akibat.
Persiapan Machine Learning
26. Menentukan Feature
Feature adalah input yang digunakan model.
X = df[
[
"luas",
"jumlah_kamar",
"jarak_ke_kota",
"kondisi"
]
]
27. Menentukan Target
Target adalah nilai yang ingin diprediksi.
y = df[
"harga"
]
Sehingga:
X
↓
Input
y
↓
Target
28. Train-Test Split
Bagi dataset:
X_train, X_test, y_train, y_test = train_test_split(
X,
y,
test_size=0.2,
random_state=42
)
Artinya:
80% → training
20% → testing
Periksa:
print(
"X Train:",
X_train.shape
)
print(
"X Test:",
X_test.shape
)
print(
"y Train:",
y_train.shape
)
print(
"y Test:",
y_test.shape
)
29. Menentukan Numerical Feature
numerical_columns = [
"luas",
"jumlah_kamar",
"jarak_ke_kota"
]
30. Menentukan Categorical Feature
categorical_columns = [
"kondisi"
]
Preprocessing
31. One Hot Encoding
Machine Learning tidak dapat langsung memahami:
baik
sedang
buruk
sebagai kategori teks.
Kita dapat menggunakan:
OneHotEncoder()
Contohnya:
baik
sedang
buruk
menjadi konsep:
kondisi_baik
kondisi_sedang
kondisi_buruk
Setelah One Hot Encoding:
kondisi_baik kondisi_sedang kondisi_buruk
1 0 0
0 1 0
0 0 1
32. Preprocessing untuk Model yang Membutuhkan Scaling
Untuk model seperti Linear Regression dan KNN, kita dapat melakukan scaling terhadap feature numerik.
preprocessor_scaled = ColumnTransformer(
transformers=[
(
"numeric",
StandardScaler(),
numerical_columns
),
(
"categorical",
OneHotEncoder(
handle_unknown="ignore"
),
categorical_columns
)
]
)
33. Preprocessing untuk Tree-Based Model
Decision Tree, Random Forest, dan Gradient Boosting tidak membutuhkan scaling numerik seperti KNN.
Kita tetap harus mengubah categorical feature.
preprocessor_tree = ColumnTransformer(
transformers=[
(
"categorical",
OneHotEncoder(
handle_unknown="ignore"
),
categorical_columns
)
],
remainder="passthrough"
)
Membandingkan Algoritma Regression
34. Mengapa Membandingkan Algoritma?
Jangan langsung menganggap:
Random Forest pasti terbaik.
Setiap dataset dapat menghasilkan performa yang berbeda.
Karena itu kita akan mencoba:
Linear Regression
KNN Regression
Decision Tree Regression
Random Forest Regression
Gradient Boosting Regression
Kemudian membandingkan hasilnya.
35. Linear Regression
Linear Regression merupakan algoritma regression yang mencoba memodelkan hubungan linear.
Secara sederhana:
y = b0 + b1x1 + b2x2 + ...
Pipeline:
linear_model = Pipeline(
steps=[
(
"preprocessor",
preprocessor_scaled
),
(
"regressor",
LinearRegression()
)
]
)
Kelebihan:
Sederhana
Cepat
Mudah dipahami
Bagus sebagai baseline
Kekurangan:
Kurang fleksibel terhadap pola non-linear
36. KNN Regression
KNN menggunakan data yang paling dekat untuk melakukan prediksi.
knn_model = Pipeline(
steps=[
(
"preprocessor",
preprocessor_scaled
),
(
"regressor",
KNeighborsRegressor(
n_neighbors=5
)
)
]
)
KNN sangat dipengaruhi oleh jarak.
Karena itu scaling penting.
Kelebihan:
Sederhana
Dapat menangkap pola non-linear
Kekurangan:
Sensitif terhadap skala
Prediction dapat lambat pada dataset besar
Pemilihan K berpengaruh
37. Decision Tree Regression
Decision Tree membagi data berdasarkan kondisi tertentu.
Konsep sederhananya:
Apakah luas > 100?
│
┌───┴───┐
Ya Tidak
│ │
↓ ↓
...
Pipeline:
decision_tree_model = Pipeline(
steps=[
(
"preprocessor",
preprocessor_tree
),
(
"regressor",
DecisionTreeRegressor(
random_state=42
)
)
]
)
Kelebihan:
Menangkap hubungan non-linear
Tidak membutuhkan scaling
Mudah dipahami
Kekurangan:
Mudah overfitting
38. Random Forest Regression
Random Forest terdiri dari banyak Decision Tree.
Konsepnya:
Dataset
↓
Tree 1
Tree 2
Tree 3
Tree 4
...
Tree N
↓
Digabungkan
↓
Prediction
Pipeline:
random_forest_model = Pipeline(
steps=[
(
"preprocessor",
preprocessor_tree
),
(
"regressor",
RandomForestRegressor(
n_estimators=200,
random_state=42,
n_jobs=-1
)
)
]
)
Kelebihan:
Bagus untuk data tabular
Dapat menangkap pola non-linear
Lebih stabil dibanding single Decision Tree
Tidak membutuhkan scaling
Kekurangan:
Model lebih besar
Training lebih berat
Interpretasi lebih sulit
39. Gradient Boosting Regression
Gradient Boosting membangun model secara bertahap.
Model berikutnya berusaha memperbaiki kesalahan model sebelumnya.
Pipeline:
gradient_boosting_model = Pipeline(
steps=[
(
"preprocessor",
preprocessor_tree
),
(
"regressor",
GradientBoostingRegressor(
random_state=42
)
)
]
)
Kelebihan:
Bagus untuk data tabular
Dapat menangkap pola kompleks
Sering menghasilkan performa tinggi
Kekurangan:
Lebih kompleks
Parameter lebih banyak
Dapat overfitting
Training Model
40. Membuat Dictionary Model
models = {
"Linear Regression":
linear_model,
"KNN":
knn_model,
"Decision Tree":
decision_tree_model,
"Random Forest":
random_forest_model,
"Gradient Boosting":
gradient_boosting_model
}
41. Training Semua Model
results = []
trained_models = {}
for name, model in models.items():
model.fit(
X_train,
y_train
)
y_pred = model.predict(
X_test
)
mae = mean_absolute_error(
y_test,
y_pred
)
mse = mean_squared_error(
y_test,
y_pred
)
rmse = np.sqrt(mse)
r2 = r2_score(
y_test,
y_pred
)
results.append({
"Model": name,
"MAE": mae,
"MSE": mse,
"RMSE": rmse,
"R2": r2
})
trained_models[name] = model
Evaluasi Regression
42. Mean Absolute Error
MAE atau Mean Absolute Error menghitung rata-rata error absolut.
Secara sederhana:
Actual = 500 juta
Prediksi = 450 juta
Error = 50 juta
Semakin kecil:
MAE
↓
semakin baik
43. Mean Squared Error
MSE menghitung error yang dikuadratkan.
Error
↓
Error²
Kesalahan besar akan mendapatkan penalti lebih besar.
Semakin kecil MSE:
semakin baik
44. Root Mean Squared Error
RMSE:
RMSE = √MSE
Keuntungannya adalah satuannya kembali sama dengan target.
Jika target:
Rupiah
maka RMSE juga dapat dipahami dalam skala Rupiah.
Semakin kecil:
RMSE
↓
semakin baik
45. R² Score
R² menunjukkan seberapa baik model menjelaskan variasi target.
Secara umum:
R² mendekati 1 → semakin baik
R² mendekati 0 → kemampuan penjelasan rendah
R² dapat bernilai negatif pada kondisi tertentu.
Semakin tinggi:
R²
↓
umumnya semakin baik
Perbandingan Model
46. Membuat DataFrame Hasil Evaluasi
results_df = pd.DataFrame(
results
)
Urutkan berdasarkan RMSE:
results_df = results_df.sort_values(
by="RMSE"
)
Tampilkan:
results_df
Contoh struktur:
| Model | MAE | MSE | RMSE | R² |
|---|---|---|---|---|
| Linear Regression | ... | ... | ... | ... |
| KNN | ... | ... | ... | ... |
| Decision Tree | ... | ... | ... | ... |
| Random Forest | ... | ... | ... | ... |
| Gradient Boosting | ... | ... | ... | ... |
Jangan memasukkan angka hasil evaluasi secara manual dalam dokumentasi. Nilai tersebut harus berasal dari notebook ketika dataset dijalankan.
47. Visualisasi Perbandingan RMSE
plt.figure(figsize=(10, 5))
plt.bar(
results_df["Model"],
results_df["RMSE"]
)
plt.title(
"Perbandingan RMSE Model Regression"
)
plt.xlabel(
"Model"
)
plt.ylabel(
"RMSE"
)
plt.xticks(
rotation=30,
ha="right"
)
plt.tight_layout()
plt.show()
Interpretasi:
RMSE lebih kecil
↓
error prediksi lebih kecil
48. Visualisasi Perbandingan MAE
plt.figure(figsize=(10, 5))
plt.bar(
results_df["Model"],
results_df["MAE"]
)
plt.title(
"Perbandingan MAE Model Regression"
)
plt.xlabel(
"Model"
)
plt.ylabel(
"MAE"
)
plt.xticks(
rotation=30,
ha="right"
)
plt.tight_layout()
plt.show()
49. Visualisasi Perbandingan R²
plt.figure(figsize=(10, 5))
plt.bar(
results_df["Model"],
results_df["R2"]
)
plt.title(
"Perbandingan R² Model Regression"
)
plt.xlabel(
"Model"
)
plt.ylabel(
"R²"
)
plt.xticks(
rotation=30,
ha="right"
)
plt.tight_layout()
plt.show()
Interpretasi:
MAE → semakin kecil semakin baik
RMSE → semakin kecil semakin baik
R² → semakin besar semakin baik
Model Selection
50. Menentukan Model Terbaik Berdasarkan RMSE
best_row = results_df.iloc[0]
best_model_name = best_row[
"Model"
]
print(
"Model terbaik berdasarkan RMSE:",
best_model_name
)
Ambil model:
best_model = trained_models[
best_model_name
]
Namun model dengan metric terbaik tidak selalu otomatis menjadi pilihan production.
Pertimbangkan juga:
Akurasi
Ukuran model
Kecepatan inference
Kompleksitas
Interpretability
Kebutuhan aplikasi
Untuk tutorial deployment ini kita menggunakan:
Random Forest
sehingga file akhirnya:
model_forest.joblib
Evaluasi Random Forest
51. Mengambil Random Forest
model_forest = trained_models[
"Random Forest"
]
Prediksi:
y_pred_forest = model_forest.predict(
X_test
)
52. Actual vs Prediction
Buat DataFrame:
comparison_df = pd.DataFrame({
"Actual": y_test.values,
"Prediction": y_pred_forest
})
Lihat:
comparison_df.head(
10
)
53. Visualisasi Actual vs Prediction
plt.figure(figsize=(7, 7))
plt.scatter(
y_test,
y_pred_forest,
alpha=0.6
)
minimum = min(
y_test.min(),
y_pred_forest.min()
)
maximum = max(
y_test.max(),
y_pred_forest.max()
)
plt.plot(
[minimum, maximum],
[minimum, maximum]
)
plt.title(
"Actual vs Predicted Price"
)
plt.xlabel(
"Harga Aktual"
)
plt.ylabel(
"Harga Prediksi"
)
plt.show()
Jika prediksi sempurna, titik akan berada dekat garis diagonal.
54. Menghitung Residual
Residual:
Actual - Prediction
Kode:
residual = (
y_test.values
- y_pred_forest
)
55. Residual Plot
plt.figure(figsize=(8, 5))
plt.scatter(
y_pred_forest,
residual,
alpha=0.6
)
plt.axhline(
y=0
)
plt.title(
"Residual Plot"
)
plt.xlabel(
"Predicted Price"
)
plt.ylabel(
"Residual"
)
plt.show()
Residual yang tersebar relatif acak di sekitar nol biasanya merupakan pola yang lebih baik daripada residual yang menunjukkan pola sistematis.
56. Distribusi Residual
plt.figure(figsize=(8, 5))
plt.hist(
residual,
bins=30
)
plt.title(
"Distribusi Residual"
)
plt.xlabel(
"Residual"
)
plt.ylabel(
"Jumlah"
)
plt.show()
Feature Importance
57. Mengapa Feature Importance?
Feature importance membantu memahami fitur mana yang berkontribusi terhadap prediksi model.
Untuk Pipeline yang kita gunakan, kita dapat menggunakan permutation importance.
58. Menghitung Permutation Importance
importance = permutation_importance(
model_forest,
X_test,
y_test,
n_repeats=10,
random_state=42,
scoring="r2"
)
Buat DataFrame:
importance_df = pd.DataFrame({
"Feature": X_test.columns,
"Importance": importance.importances_mean
})
Urutkan:
importance_df = importance_df.sort_values(
by="Importance",
ascending=False
)
Tampilkan:
importance_df
59. Visualisasi Feature Importance
plt.figure(figsize=(8, 5))
plt.bar(
importance_df["Feature"],
importance_df["Importance"]
)
plt.title(
"Permutation Feature Importance"
)
plt.xlabel(
"Feature"
)
plt.ylabel(
"Importance"
)
plt.xticks(
rotation=30,
ha="right"
)
plt.tight_layout()
plt.show()
Hasil ini membantu memahami feature mana yang paling memberikan kontribusi terhadap performa model pada data pengujian.
Prediction
60. Membuat Data Rumah Baru
Misalnya kita ingin memprediksi rumah:
Luas = 120
Jumlah kamar = 3
Jarak kota = 5
Kondisi = baik
Buat DataFrame:
new_house = pd.DataFrame(
[
[
120,
3,
5,
"baik"
]
],
columns=[
"luas",
"jumlah_kamar",
"jarak_ke_kota",
"kondisi"
]
)
61. Melakukan Prediction
prediction = model_forest.predict(
new_house
)
Tampilkan:
print(
f"Prediksi Harga Rumah: "
f"Rp {prediction[0]:,.0f}"
)
Menyimpan Model
62. Mengapa Model Harus Disimpan?
Training tidak perlu dilakukan setiap kali API menerima request.
Prosesnya:
Training
↓
Model
↓
Simpan
↓
Production
↓
Load Model
↓
Prediction
63. Menyimpan Model dengan Joblib
joblib.dump(
model_forest,
"model_forest.joblib"
)
File:
model_forest.joblib
sekarang berisi Pipeline:
Preprocessing
+
Random Forest
64. Menguji Model yang Disimpan
Load:
loaded_model = joblib.load(
"model_forest.joblib"
)
Prediction:
loaded_prediction = loaded_model.predict(
new_house
)
Tampilkan:
print(
f"Prediksi: "
f"Rp {loaded_prediction[0]:,.0f}"
)
Jika berhasil, model siap digunakan oleh API.
FastAPI
65. Apa Itu FastAPI?
FastAPI adalah framework Python untuk membangun API.
Dalam project ini FastAPI berfungsi sebagai penghubung:
Client
↓
FastAPI
↓
Machine Learning Model
↓
Prediction
↓
JSON
66. Install FastAPI
pip install fastapi uvicorn
67. Membuat requirements.txt
Buat:
requirements.txt
Isi:
fastapi
uvicorn[standard]
pandas
joblib
scikit-learn
Untuk deployment, sebaiknya dependency dan versinya dikunci berdasarkan environment training.
Misalnya:
pip freeze > requirements.txt
Dengan demikian environment server lebih mudah disamakan dengan environment training.
Membuat API
68. Membuat main.py
Buat:
main.py
Gunakan kode berikut:
from typing import Literal
from fastapi import FastAPI
from pydantic import BaseModel, Field
import joblib
import pandas as pd
app = FastAPI(
title="Prediksi Harga Rumah",
description="REST API Machine Learning untuk memprediksi harga rumah"
)
model = joblib.load(
"model_forest.joblib"
)
class HouseInput(BaseModel):
luas: int = Field(gt=0)
jumlah_kamar: int = Field(gt=0)
jarak_ke_kota: int = Field(ge=0)
kondisi: Literal[
"baik",
"sedang",
"buruk"
]
@app.get("/")
def home():
return {
"message": "API Prediksi Harga Rumah aktif"
}
@app.post("/predict")
def predict(data: HouseInput):
input_df = pd.DataFrame(
[[
data.luas,
data.jumlah_kamar,
data.jarak_ke_kota,
data.kondisi
]],
columns=[
"luas",
"jumlah_kamar",
"jarak_ke_kota",
"kondisi"
]
)
prediction = model.predict(
input_df
)[0]
return {
"input": {
"luas": data.luas,
"jumlah_kamar": data.jumlah_kamar,
"jarak_ke_kota": data.jarak_ke_kota,
"kondisi": data.kondisi
},
"prediksi_harga": float(
prediction
)
}
69. Mengapa Menggunakan Pydantic?
Bagian:
class HouseInput(BaseModel):
digunakan untuk menentukan bentuk data yang boleh diterima API.
Contohnya:
{
"luas": 120,
"jumlah_kamar": 3,
"jarak_ke_kota": 5,
"kondisi": "baik"
}
FastAPI akan melakukan validasi sebelum data diberikan kepada model.
70. Mengapa Menggunakan Literal?
Kita hanya mengizinkan:
baik
sedang
buruk
Dengan:
Literal[
"baik",
"sedang",
"buruk"
]
Jika client mengirim:
sangat_bagus
FastAPI akan menolak request karena kategori tersebut tidak termasuk kategori yang diperbolehkan.
Menjalankan API
71. Menjalankan FastAPI Secara Lokal
Di terminal:
uvicorn main:app --reload
Penjelasan:
main
↓
main.py
app
↓
object FastAPI
--reload cocok digunakan untuk development karena server akan melakukan reload ketika source code berubah.
Jangan menggunakan --reload untuk production.
72. Menguji Endpoint Home
Buka:
http://127.0.0.1:8000/
Response:
{
"message": "API Prediksi Harga Rumah aktif"
}
73. Swagger Documentation
FastAPI secara otomatis menyediakan dokumentasi.
Buka:
http://127.0.0.1:8000/docs
Di sana tersedia endpoint:
GET /
POST /predict
Klik:
Try it out
untuk melakukan testing.
74. Testing Prediction API
Request:
{
"luas": 120,
"jumlah_kamar": 3,
"jarak_ke_kota": 5,
"kondisi": "baik"
}
Response:
{
"input": {
"luas": 120,
"jumlah_kamar": 3,
"jarak_ke_kota": 5,
"kondisi": "baik"
},
"prediksi_harga": 725631245.12
}
Angka pada prediksi_harga hanya contoh format. Nilai sebenarnya berasal dari model yang Anda latih.
75. Testing Menggunakan cURL
curl -X POST \
"http://127.0.0.1:8000/predict" \
-H "Content-Type: application/json" \
-d '{
"luas": 120,
"jumlah_kamar": 3,
"jarak_ke_kota": 5,
"kondisi": "baik"
}'
Deployment ke VPS
76. Apa yang Akan Dipindahkan ke VPS?
Tidak semua file dari project perlu dipindahkan.
File utama:
main.py
model_forest.joblib
requirements.txt
Notebook:
regression_harga_rumah.ipynb
tidak wajib berada di server production.
Dataset:
rumah.csv
juga tidak diperlukan jika API hanya melakukan inference menggunakan model yang sudah disimpan.
77. Login ke VPS
Dari terminal:
ssh username@IP_VPS
Contoh:
ssh deploy@192.168.1.100
Sebaiknya aplikasi production dijalankan menggunakan user non-root.
78. Update VPS
sudo apt update
sudo apt upgrade -y
79. Install Python
sudo apt install python3 python3-pip python3-venv -y
Periksa:
python3 --version
Menyiapkan PM2
80. Apa Itu PM2?
PM2 merupakan process manager yang umum digunakan pada ekosistem Node.js, tetapi dapat digunakan untuk menjalankan command seperti Uvicorn.
Dalam project ini:
PM2
↓
Uvicorn
↓
FastAPI
↓
Machine Learning
PM2 membantu:
Menjalankan process
Restart process
Melihat log
Monitoring status
Menjalankan kembali setelah reboot
81. Install Node.js dan NPM
sudo apt install nodejs npm -y
Periksa:
node --version
dan:
npm --version
82. Install PM2
sudo npm install -g pm2
Cek:
pm2 --version
Menyiapkan Directory Project
83. Membuat Folder Project
sudo mkdir -p /var/www/prediksi-rumah
Berikan ownership:
sudo chown -R $USER:$USER \
/var/www/prediksi-rumah
Masuk:
cd /var/www/prediksi-rumah
Upload File ke VPS
84. Upload Menggunakan SFTP
Untuk VPS, lebih disarankan menggunakan SFTP daripada FTP biasa karena menggunakan SSH.
Dari komputer lokal:
sftp username@IP_VPS
Masuk directory:
cd /var/www/prediksi-rumah
Upload:
put main.py
Kemudian:
put model_forest.joblib
Dan:
put requirements.txt
Keluar:
exit
85. Upload Menggunakan SCP
Alternatif lain:
scp main.py \
username@IP_VPS:/var/www/prediksi-rumah/
Model:
scp model_forest.joblib \
username@IP_VPS:/var/www/prediksi-rumah/
Requirements:
scp requirements.txt \
username@IP_VPS:/var/www/prediksi-rumah/
Atau sekaligus:
scp \
main.py \
model_forest.joblib \
requirements.txt \
username@IP_VPS:/var/www/prediksi-rumah/
86. Upload Menggunakan FTP dari Terminal
Jika server memang menyediakan FTP, salah satu client terminal yang dapat digunakan adalah lftp.
Install:
sudo apt install lftp
Connect:
lftp -u USERNAME,PASSWORD ftp://IP_VPS
Masuk:
cd /var/www/prediksi-rumah
Upload:
put main.py
put model_forest.joblib
put requirements.txt
Keluar:
bye
Namun plain FTP sebaiknya dihindari pada server internet karena kredensial dan transfer data tidak terenkripsi seperti SFTP.
Python Environment di VPS
87. Membuat Virtual Environment
Masuk:
cd /var/www/prediksi-rumah
Buat:
python3 -m venv venv
Aktifkan:
source venv/bin/activate
88. Install Dependency
Upgrade pip:
pip install --upgrade pip
Install requirements:
pip install -r requirements.txt
89. Memeriksa File
ls
Seharusnya:
main.py
model_forest.joblib
requirements.txt
venv
Testing di VPS
90. Menjalankan Uvicorn Manual
Sebelum menggunakan PM2, test terlebih dahulu:
venv/bin/uvicorn \
main:app \
--host 0.0.0.0 \
--port 8000
Jika tidak ada error, berarti aplikasi berhasil dijalankan.
91. Testing dari VPS
Buka terminal lain:
curl http://127.0.0.1:8000/
Testing prediction:
curl -X POST \
"http://127.0.0.1:8000/predict" \
-H "Content-Type: application/json" \
-d '{
"luas": 120,
"jumlah_kamar": 3,
"jarak_ke_kota": 5,
"kondisi": "baik"
}'
Jika berhasil:
FastAPI
↓
Model
↓
Prediction
berarti deployment dapat dilanjutkan.
Hentikan Uvicorn:
Ctrl + C
Menjalankan dengan PM2
92. Menjalankan Uvicorn dengan PM2
Masuk:
cd /var/www/prediksi-rumah
Kemudian:
pm2 start \
"venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000" \
--name prediksi-rumah
93. Melihat Status PM2
pm2 status
Jika status:
online
berarti API sedang berjalan.
94. Melihat Log
pm2 logs prediksi-rumah
Log sangat berguna ketika terjadi:
ModuleNotFoundError
FileNotFoundError
Port conflict
Model loading error
95. Restart API
pm2 restart prediksi-rumah
96. Stop API
pm2 stop prediksi-rumah
97. Delete Process
pm2 delete prediksi-rumah
98. Menjalankan PM2 Setelah Reboot
Jalankan:
pm2 startup
PM2 akan memberikan command yang perlu dijalankan.
Setelah itu:
pm2 save
Dengan demikian process yang telah disimpan dapat dipulihkan ketika server reboot.
PM2 Ecosystem File
99. Membuat ecosystem.config.js
Agar konfigurasi lebih mudah dikelola, buat:
ecosystem.config.js
Isi:
module.exports = {
apps: [
{
name: "prediksi-rumah",
script:
"/var/www/prediksi-rumah/venv/bin/uvicorn",
args:
"main:app --host 127.0.0.1 --port 8000",
cwd:
"/var/www/prediksi-rumah",
interpreter:
"none"
}
]
};
Jalankan:
pm2 start ecosystem.config.js
Kemudian:
pm2 save
Pendekatan ini lebih mudah ketika konfigurasi aplikasi mulai bertambah.
Nginx
100. Mengapa Menggunakan Nginx?
Kita sebenarnya dapat membuat API langsung:
IP_VPS:8000
Tetapi production biasanya lebih baik menggunakan:
Domain
↓
Nginx
↓
Uvicorn
↓
FastAPI
Keuntungannya antara lain:
Reverse proxy
HTTPS
Domain
Security
Routing
101. Install Nginx
sudo apt install nginx -y
Periksa:
sudo systemctl status nginx
102. Membuat Konfigurasi Nginx
Buat:
sudo nano \
/etc/nginx/sites-available/prediksi-rumah
Isi:
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Ganti:
api.example.com
dengan domain yang digunakan.
103. Mengaktifkan Konfigurasi
sudo ln -s \
/etc/nginx/sites-available/prediksi-rumah \
/etc/nginx/sites-enabled/
Test:
sudo nginx -t
Jika berhasil:
sudo systemctl reload nginx
HTTPS
104. Mengapa HTTPS?
API production sebaiknya menggunakan HTTPS.
Tanpa HTTPS:
HTTP
Dengan HTTPS:
HTTPS
Data antara client dan server dienkripsi selama koneksi HTTPS.
105. Install Certbot
sudo apt install \
certbot \
python3-certbot-nginx \
-y
106. Mengaktifkan SSL
sudo certbot \
--nginx \
-d api.example.com
Setelah berhasil, API dapat diakses melalui:
https://api.example.com
Swagger:
https://api.example.com/docs
Firewall
107. Mengatur UFW
Jika menggunakan Nginx:
sudo ufw allow OpenSSH
Kemudian:
sudo ufw allow 'Nginx Full'
Aktifkan:
sudo ufw enable
Periksa:
sudo ufw status
Karena Uvicorn hanya mendengarkan:
127.0.0.1:8000
port 8000 tidak perlu dibuka ke publik ketika Nginx menjadi reverse proxy.
Update Model
108. Training Model Baru
Ketika dataset bertambah:
Dataset baru
↓
Jupyter Notebook
↓
Training
↓
Evaluasi
↓
model_forest.joblib baru
109. Upload Model Baru
Dari komputer:
scp model_forest.joblib \
username@IP_VPS:/var/www/prediksi-rumah/
Kemudian login:
ssh username@IP_VPS
110. Restart API
cd /var/www/prediksi-rumah
Kemudian:
pm2 restart prediksi-rumah
API sekarang menggunakan model baru.
Troubleshooting
111. Model Tidak Ditemukan
Jika muncul:
FileNotFoundError:
model_forest.joblib
periksa:
pwd
Kemudian:
ls
Pastikan:
main.py
model_forest.joblib
berada pada directory yang benar.
112. Module Tidak Ditemukan
Contoh:
ModuleNotFoundError:
No module named 'sklearn'
Aktifkan environment:
source venv/bin/activate
Kemudian:
pip install -r requirements.txt
113. Port 8000 Sudah Digunakan
Periksa:
sudo ss -tulpn | grep 8000
Kemudian periksa:
pm2 status
Kemungkinan terdapat process lama yang masih berjalan.
114. API Tidak Bisa Diakses
Periksa beberapa hal:
Uvicorn berjalan
PM2 online
Nginx aktif
Domain mengarah ke VPS
Firewall
Port
Periksa PM2:
pm2 status
Periksa log:
pm2 logs prediksi-rumah
Periksa Nginx:
sudo nginx -t
115. Error Ketika Load Joblib
Model Machine Learning bergantung pada library dan versi tertentu.
Karena itu environment training dan production sebaiknya menggunakan dependency yang kompatibel.
Simpan dependency:
pip freeze > requirements.txt
Kemudian install dependency tersebut di VPS:
pip install -r requirements.txt
Production Best Practice
116. Jangan Menggunakan --reload
Development:
uvicorn main:app --reload
Production:
uvicorn main:app --host 127.0.0.1 --port 8000
117. Jangan Menjalankan Aplikasi sebagai Root
Sebaiknya gunakan user khusus deployment.
Contoh:
deploy
daripada menjalankan aplikasi sebagai:
root
118. Validasi Input
API harus memvalidasi:
Luas > 0
Jumlah kamar > 0
Jarak >= 0
Kondisi harus kategori yang valid
Pydantic membantu melakukan validasi tersebut.
119. Gunakan HTTPS
Production API sebaiknya menggunakan:
HTTPS
bukan hanya:
HTTP
120. Jangan Membuka Port Internal Jika Tidak Diperlukan
Jika menggunakan:
Nginx
↓
127.0.0.1:8000
maka port 8000 tidak perlu dibuka ke internet.
Client cukup mengakses:
HTTPS
↓
Nginx
Alur Deployment Lengkap
121. Arsitektur Training
LAPTOP
rumah.csv
↓
Jupyter Notebook
↓
Data Cleaning
↓
EDA
↓
Visualisasi
↓
Preprocessing
↓
Train-Test Split
↓
┌──────────────────────┐
│ Linear Regression │
│ KNN │
│ Decision Tree │
│ Random Forest │
│ Gradient Boosting │
└──────────────────────┘
↓
Evaluation
↓
Comparison
↓
Model Selection
↓
model_forest.joblib
122. Arsitektur Production
INTERNET
↓
HTTPS
↓
Nginx
↓
127.0.0.1:8000
↓
Uvicorn
↓
FastAPI
↓
Pydantic Validation
↓
Pandas
↓
Machine Learning
Pipeline
↓
Random Forest
↓
Prediction
↓
JSON
Checklist Project
123. Checklist Jupyter Notebook
[ ] Dataset tersedia
[ ] Data berhasil dibaca
[ ] Data berhasil diperiksa
[ ] Missing value diperiksa
[ ] Duplicate diperiksa
[ ] EDA dilakukan
[ ] Visualisasi dibuat
[ ] Feature ditentukan
[ ] Target ditentukan
[ ] Train-test split
[ ] Preprocessing
[ ] Linear Regression
[ ] KNN
[ ] Decision Tree
[ ] Random Forest
[ ] Gradient Boosting
[ ] MAE
[ ] MSE
[ ] RMSE
[ ] R²
[ ] Perbandingan model
[ ] Actual vs Prediction
[ ] Residual analysis
[ ] Feature importance
[ ] Prediction data baru
[ ] Model disimpan
124. Checklist FastAPI
[ ] FastAPI terinstall
[ ] requirements.txt tersedia
[ ] model_forest.joblib tersedia
[ ] main.py dibuat
[ ] Pydantic validation
[ ] Endpoint /
[ ] Endpoint /predict
[ ] Swagger berhasil
[ ] Prediction berhasil
[ ] cURL berhasil
125. Checklist VPS
[ ] SSH dapat digunakan
[ ] Python terinstall
[ ] Virtual environment dibuat
[ ] Dependency terinstall
[ ] File model diupload
[ ] main.py diupload
[ ] requirements.txt diupload
[ ] Uvicorn berhasil
[ ] PM2 terinstall
[ ] PM2 online
[ ] PM2 startup
[ ] pm2 save
126. Checklist Production
[ ] Nginx terinstall
[ ] Domain mengarah ke VPS
[ ] Reverse proxy aktif
[ ] HTTPS aktif
[ ] Firewall aktif
[ ] Port internal tidak terbuka publik
[ ] API tidak menggunakan --reload
[ ] Aplikasi tidak berjalan sebagai root
[ ] Input tervalidasi
[ ] Dependency kompatibel
[ ] Log dapat diperiksa
Kesimpulan
127. Dari Notebook hingga Production API
Dalam project ini kita belajar bahwa Machine Learning bukan hanya tentang:
model.fit()
Tetapi merupakan sebuah proses yang lebih panjang:
Dataset
↓
Data Understanding
↓
Data Cleaning
↓
EDA
↓
Visualisasi
↓
Feature Engineering / Preprocessing
↓
Train-Test Split
↓
Model Training
↓
Model Comparison
↓
Evaluation
↓
Model Selection
↓
Model Saving
↓
API
↓
Deployment
↓
Monitoring
Model yang awalnya hanya berada di:
Jupyter Notebook
akhirnya dapat digunakan oleh aplikasi lain melalui:
REST API
dengan arsitektur:
Client
↓
Nginx
↓
FastAPI
↓
Machine Learning Pipeline
↓
Random Forest
↓
Prediction
Dengan workflow ini, kita telah membangun contoh sederhana Machine Learning to Production (ML deployment).
Hal yang paling penting adalah memahami bahwa model Machine Learning yang baik bukan hanya model dengan metric bagus, tetapi model yang:
dilatih dengan benar
↓
dievaluasi dengan benar
↓
preprocessing konsisten
↓
dapat disimpan
↓
dapat digunakan kembali
↓
dapat diakses aplikasi
↓
dapat dijalankan secara stabil di server
Itulah transisi dari Machine Learning experiment menjadi Machine Learning application.