Update src/streamlit_app.py
Browse files- src/streamlit_app.py +281 -29
src/streamlit_app.py
CHANGED
|
@@ -1,40 +1,292 @@
|
|
| 1 |
-
|
| 2 |
-
import numpy as np
|
| 3 |
import pandas as pd
|
| 4 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
|
| 13 |
-
In the meantime, below is an example of what you can do with just a few lines of code:
|
| 14 |
"""
|
| 15 |
|
| 16 |
-
|
| 17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
-
|
| 20 |
-
theta = 2 * np.pi * num_turns * indices
|
| 21 |
-
radius = indices
|
| 22 |
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
| 31 |
})
|
| 32 |
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Import libraries
|
|
|
|
| 2 |
import pandas as pd
|
| 3 |
+
import numpy as np
|
| 4 |
+
import matplotlib.pyplot as plt
|
| 5 |
+
import seaborn as sns
|
| 6 |
+
import warnings
|
| 7 |
+
warnings.filterwarnings('ignore')
|
| 8 |
|
| 9 |
+
# Machine Learning Libraries
|
| 10 |
+
from sklearn.model_selection import train_test_split
|
| 11 |
+
from sklearn.preprocessing import StandardScaler
|
| 12 |
+
from sklearn.ensemble import RandomForestClassifier
|
| 13 |
+
from sklearn.metrics import (classification_report, confusion_matrix,
|
| 14 |
+
accuracy_score, precision_score, recall_score, f1_score)
|
| 15 |
+
|
| 16 |
+
# Visualization
|
| 17 |
+
import matplotlib.pyplot as plt
|
| 18 |
+
import seaborn as sns
|
| 19 |
+
plt.style.use('seaborn-v0_8')
|
| 20 |
|
| 21 |
+
print("Library berhasil diimpor!")
|
| 22 |
+
|
| 23 |
+
"""## 2. Data Loading & Exploration
|
| 24 |
|
|
|
|
| 25 |
"""
|
| 26 |
|
| 27 |
+
# Load dataset
|
| 28 |
+
print("Memuat dataset diabetes...")
|
| 29 |
+
try:
|
| 30 |
+
df = pd.read_csv("datasets.csv")
|
| 31 |
+
print(f"Dataset berhasil dimuat: {df.shape[0]:,} baris, {df.shape[1]} kolom")
|
| 32 |
+
except FileNotFoundError:
|
| 33 |
+
print("File 'datasets.csv' tidak ditemukan!")
|
| 34 |
+
print("Silakan upload file dataset ke Google Colab terlebih dahulu.")
|
| 35 |
+
|
| 36 |
+
# Basic dataset information
|
| 37 |
+
print(f"\nInformasi Dataset:")
|
| 38 |
+
print(f" • Ukuran: {df.shape}")
|
| 39 |
+
print(f" • Penggunaan memori: {df.memory_usage(deep=True).sum() / 1024**2:.2f} MB")
|
| 40 |
+
print(f" • Nilai kosong: {df.isnull().sum().sum()}")
|
| 41 |
+
|
| 42 |
+
# Display first few rows
|
| 43 |
+
print(f"\n5 Baris Pertama:")
|
| 44 |
+
display(df.head())
|
| 45 |
+
|
| 46 |
+
# Dataset statistics
|
| 47 |
+
print(f"\nStatistik Dataset:")
|
| 48 |
+
display(df.describe())
|
| 49 |
|
| 50 |
+
"""## 3. Target Variable Analysis
|
|
|
|
|
|
|
| 51 |
|
| 52 |
+
"""
|
| 53 |
+
|
| 54 |
+
# Target variable distribution
|
| 55 |
+
target_column = 'Diabetes_012'
|
| 56 |
+
print(f"Variabel target: {target_column}")
|
| 57 |
|
| 58 |
+
target_counts = df[target_column].value_counts().sort_index()
|
| 59 |
+
target_percentages = df[target_column].value_counts(normalize=True).sort_index() * 100
|
| 60 |
+
|
| 61 |
+
# Create target analysis dataframe
|
| 62 |
+
target_analysis = pd.DataFrame({
|
| 63 |
+
'Kelas': ['Tidak Diabetes', 'Diabetes Tipe 1', 'Diabetes Tipe 2'],
|
| 64 |
+
'Jumlah': target_counts.values,
|
| 65 |
+
'Persentase': target_percentages.values
|
| 66 |
})
|
| 67 |
|
| 68 |
+
print("Distribusi:")
|
| 69 |
+
display(target_analysis)
|
| 70 |
+
|
| 71 |
+
# Visualization of target distribution
|
| 72 |
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
|
| 73 |
+
|
| 74 |
+
# Pie chart
|
| 75 |
+
colors = ['#2E8B57', '#DC143C', '#FF8C00']
|
| 76 |
+
ax1.pie(target_counts.values, labels=target_analysis['Kelas'],
|
| 77 |
+
autopct='%1.1f%%', colors=colors, startangle=90)
|
| 78 |
+
ax1.set_title('Distribusi Variabel Target', fontsize=14, fontweight='bold')
|
| 79 |
+
|
| 80 |
+
# Bar chart
|
| 81 |
+
bars = ax2.bar(target_analysis['Kelas'], target_analysis['Jumlah'], color=colors)
|
| 82 |
+
ax2.set_title('Jumlah Sampel per Kelas', fontsize=14, fontweight='bold')
|
| 83 |
+
ax2.set_ylabel('Jumlah Sampel')
|
| 84 |
+
ax2.set_xlabel('Kelas Diabetes')
|
| 85 |
+
|
| 86 |
+
# Add value labels on bars
|
| 87 |
+
for bar, count in zip(bars, target_analysis['Jumlah']):
|
| 88 |
+
ax2.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 1000,
|
| 89 |
+
f'{count:,}', ha='center', va='bottom', fontweight='bold')
|
| 90 |
+
|
| 91 |
+
plt.tight_layout()
|
| 92 |
+
plt.show()
|
| 93 |
+
|
| 94 |
+
"""## 4. Data Preprocessing & Model Training
|
| 95 |
+
|
| 96 |
+
"""
|
| 97 |
+
|
| 98 |
+
# Prepare data
|
| 99 |
+
feature_columns = [col for col in df.columns if col != target_column]
|
| 100 |
+
X = df[feature_columns]
|
| 101 |
+
y = df[target_column]
|
| 102 |
+
|
| 103 |
+
print(f"Ukuran data:")
|
| 104 |
+
print(f" • Fitur (X): {X.shape}")
|
| 105 |
+
print(f" • Target (y): {y.shape}")
|
| 106 |
+
|
| 107 |
+
# Feature scaling
|
| 108 |
+
print(f"\nMenerapkan StandardScaler...")
|
| 109 |
+
scaler = StandardScaler()
|
| 110 |
+
X_scaled = scaler.fit_transform(X)
|
| 111 |
+
X_scaled = pd.DataFrame(X_scaled, columns=feature_columns)
|
| 112 |
+
|
| 113 |
+
print(f"Fitur berhasil dinormalisasi!")
|
| 114 |
+
|
| 115 |
+
# Split data
|
| 116 |
+
X_train, X_test, y_train, y_test = train_test_split(
|
| 117 |
+
X_scaled, y, test_size=0.2, random_state=42, stratify=y
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
print(f"\nHasil Pembagian Data:")
|
| 121 |
+
print(f" • Data latih: {X_train.shape[0]:,} sampel")
|
| 122 |
+
print(f" • Data uji: {X_test.shape[0]:,} sampel")
|
| 123 |
+
|
| 124 |
+
# Train Random Forest
|
| 125 |
+
print(f"\nMelatih Random Forest Classifier...")
|
| 126 |
+
rf_classifier = RandomForestClassifier(
|
| 127 |
+
n_estimators=100,
|
| 128 |
+
random_state=42,
|
| 129 |
+
max_depth=10,
|
| 130 |
+
min_samples_split=5,
|
| 131 |
+
min_samples_leaf=2,
|
| 132 |
+
n_jobs=-1
|
| 133 |
+
)
|
| 134 |
+
|
| 135 |
+
rf_classifier.fit(X_train, y_train)
|
| 136 |
+
print("Pelatihan model selesai!")
|
| 137 |
+
|
| 138 |
+
# Make predictions
|
| 139 |
+
y_pred = rf_classifier.predict(X_test)
|
| 140 |
+
y_pred_proba = rf_classifier.predict_proba(X_test)
|
| 141 |
+
|
| 142 |
+
print(f"\nPrediksi selesai!")
|
| 143 |
+
print(f" • Ukuran prediksi: {y_pred.shape}")
|
| 144 |
+
print(f" • Ukuran probabilitas: {y_pred_proba.shape}")
|
| 145 |
+
|
| 146 |
+
"""## 5. Model Evaluation & Visualization
|
| 147 |
+
|
| 148 |
+
"""
|
| 149 |
+
|
| 150 |
+
# Calculate metrics
|
| 151 |
+
accuracy = accuracy_score(y_test, y_pred)
|
| 152 |
+
precision = precision_score(y_test, y_pred, average='weighted')
|
| 153 |
+
recall = recall_score(y_test, y_pred, average='weighted')
|
| 154 |
+
f1 = f1_score(y_test, y_pred, average='weighted')
|
| 155 |
+
|
| 156 |
+
print(f"Metrik Performa:")
|
| 157 |
+
print(f" • Akurasi: {accuracy:.4f} ({accuracy*100:.2f}%)")
|
| 158 |
+
print(f" • Presisi (terbobot): {precision:.4f}")
|
| 159 |
+
print(f" • Recall (terbobot): {recall:.4f}")
|
| 160 |
+
print(f" • F1-Score (terbobot): {f1:.4f}")
|
| 161 |
+
|
| 162 |
+
# Detailed classification report
|
| 163 |
+
print(f"\nLaporan Klasifikasi Detail:")
|
| 164 |
+
print(classification_report(y_test, y_pred,
|
| 165 |
+
target_names=['Tidak Diabetes', 'Diabetes Tipe 1', 'Diabetes Tipe 2']))
|
| 166 |
+
|
| 167 |
+
# Confusion Matrix
|
| 168 |
+
cm = confusion_matrix(y_test, y_pred)
|
| 169 |
+
print(f"\nMatriks Konfusi:")
|
| 170 |
+
print(cm)
|
| 171 |
+
|
| 172 |
+
# Visualization
|
| 173 |
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
|
| 174 |
+
|
| 175 |
+
# Confusion Matrix Heatmap
|
| 176 |
+
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', ax=ax1,
|
| 177 |
+
xticklabels=['Tidak Diabetes', 'Diabetes Tipe 1', 'Diabetes Tipe 2'],
|
| 178 |
+
yticklabels=['Tidak Diabetes', 'Diabetes Tipe 1', 'Diabetes Tipe 2'])
|
| 179 |
+
ax1.set_title('Matriks Konfusi', fontsize=14, fontweight='bold')
|
| 180 |
+
ax1.set_xlabel('Prediksi')
|
| 181 |
+
ax1.set_ylabel('Aktual')
|
| 182 |
+
|
| 183 |
+
# Feature Importance
|
| 184 |
+
feature_importance = pd.DataFrame({
|
| 185 |
+
'feature': feature_columns,
|
| 186 |
+
'importance': rf_classifier.feature_importances_
|
| 187 |
+
}).sort_values('importance', ascending=False)
|
| 188 |
+
|
| 189 |
+
# Top 10 features
|
| 190 |
+
top_features = feature_importance.head(10)
|
| 191 |
+
ax2.barh(top_features['feature'], top_features['importance'], color='skyblue')
|
| 192 |
+
ax2.set_title('10 Fitur Terpenting', fontsize=14, fontweight='bold')
|
| 193 |
+
ax2.set_xlabel('Tingkat Kepentingan')
|
| 194 |
+
|
| 195 |
+
plt.tight_layout()
|
| 196 |
+
plt.show()
|
| 197 |
+
|
| 198 |
+
# Display feature importance table
|
| 199 |
+
print(f"\nTingkat Kepentingan Fitur (10 Teratas):")
|
| 200 |
+
display(feature_importance.head(10))
|
| 201 |
+
|
| 202 |
+
"""## 6. Model Inference Example
|
| 203 |
+
|
| 204 |
+
"""
|
| 205 |
+
|
| 206 |
+
# Example prediction
|
| 207 |
+
print("Contoh: Memprediksi diabetes untuk pasien baru...")
|
| 208 |
+
|
| 209 |
+
# Sample patient data
|
| 210 |
+
sample_patient = {
|
| 211 |
+
'HighBP': 1.0, # Tekanan darah tinggi: Ya
|
| 212 |
+
'HighChol': 0.0, # Kolesterol tinggi: Tidak
|
| 213 |
+
'CholCheck': 1.0, # Pengecekan kolesterol: Ya
|
| 214 |
+
'BMI': 28.5, # BMI: 28.5 (kelebihan berat badan)
|
| 215 |
+
'Smoker': 0.0, # Perokok: Tidak
|
| 216 |
+
'Stroke': 0.0, # Riwayat stroke: Tidak
|
| 217 |
+
'HeartDiseaseorAttack': 0.0, # Penyakit jantung: Tidak
|
| 218 |
+
'PhysActivity': 1.0, # Aktivitas fisik: Ya
|
| 219 |
+
'Fruits': 1.0, # Konsumsi buah: Ya
|
| 220 |
+
'Veggies': 1.0, # Konsumsi sayuran: Ya
|
| 221 |
+
'HvyAlcoholConsump': 0.0, # Konsumsi alkohol berat: Tidak
|
| 222 |
+
'AnyHealthcare': 1.0, # Akses layanan kesehatan: Ya
|
| 223 |
+
'NoDocbcCost': 0.0, # Tidak ke dokter karena biaya: Tidak
|
| 224 |
+
'GenHlth': 3.0, # Kesehatan umum: 3 (cukup)
|
| 225 |
+
'MentHlth': 5.0, # Hari kesehatan mental buruk: 5
|
| 226 |
+
'PhysHlth': 5.0, # Hari kesehatan fisik buruk: 5
|
| 227 |
+
'DiffWalk': 0.0, # Kesulitan berjalan: Tidak
|
| 228 |
+
'Sex': 0.0, # Jenis kelamin: Perempuan
|
| 229 |
+
'Age': 9.0, # Kategori usia: 9 (45-49)
|
| 230 |
+
'Education': 4.0, # Pendidikan: 4 (kuliah sebagian)
|
| 231 |
+
'Income': 3.0 # Pendapatan: 3 ($15k-$20k)
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
print(f"Data pasien contoh:")
|
| 235 |
+
for key, value in sample_patient.items():
|
| 236 |
+
print(f" • {key}: {value}")
|
| 237 |
+
|
| 238 |
+
# Create DataFrame for prediction
|
| 239 |
+
patient_df = pd.DataFrame([sample_patient])
|
| 240 |
+
patient_scaled = scaler.transform(patient_df)
|
| 241 |
+
patient_scaled_df = pd.DataFrame(patient_scaled, columns=feature_columns)
|
| 242 |
+
|
| 243 |
+
# Make prediction
|
| 244 |
+
prediction = rf_classifier.predict(patient_scaled_df)[0]
|
| 245 |
+
prediction_proba = rf_classifier.predict_proba(patient_scaled_df)[0]
|
| 246 |
+
|
| 247 |
+
print(f"\nHasil Prediksi:")
|
| 248 |
+
print(f" • Kelas yang diprediksi: {prediction}")
|
| 249 |
+
print(f" • Nama kelas: {['Tidak Diabetes', 'Diabetes Tipe 1', 'Diabetes Tipe 2'][int(prediction)]}")
|
| 250 |
+
|
| 251 |
+
print(f"\nProbabilitas Prediksi:")
|
| 252 |
+
for i, prob in enumerate(prediction_proba):
|
| 253 |
+
class_name = ['Tidak Diabetes', 'Diabetes Tipe 1', 'Diabetes Tipe 2'][i]
|
| 254 |
+
print(f" • {class_name}: {prob:.4f} ({prob*100:.2f}%)")
|
| 255 |
+
|
| 256 |
+
"""## 7. Save Model & Summary
|
| 257 |
+
|
| 258 |
+
"""
|
| 259 |
+
|
| 260 |
+
# Save model and scaler
|
| 261 |
+
import joblib
|
| 262 |
+
|
| 263 |
+
print("💾 Menyimpan model dan scaler...")
|
| 264 |
+
|
| 265 |
+
# Save the trained model
|
| 266 |
+
model_filename = 'diabetes_rf_model.joblib'
|
| 267 |
+
joblib.dump(rf_classifier, model_filename)
|
| 268 |
+
print(f" Model disimpan sebagai: {model_filename}")
|
| 269 |
+
|
| 270 |
+
# Save the scaler
|
| 271 |
+
scaler_filename = 'diabetes_scaler.joblib'
|
| 272 |
+
joblib.dump(scaler, scaler_filename)
|
| 273 |
+
print(f"Scaler disimpan sebagai: {scaler_filename}")
|
| 274 |
+
|
| 275 |
+
print(f"\n🎉 Pelatihan dan evaluasi model berhasil diselesaikan!")
|
| 276 |
+
print(f" File yang dibuat:")
|
| 277 |
+
print(f" • {model_filename}")
|
| 278 |
+
print(f" • {scaler_filename}")
|
| 279 |
+
|
| 280 |
+
# Summary
|
| 281 |
+
print(f"\n Ringkasan Performa Model:")
|
| 282 |
+
print(f" • Dataset: {df.shape[0]:,} sampel, {df.shape[1]} fitur")
|
| 283 |
+
print(f" • Model: Random Forest Classifier")
|
| 284 |
+
print(f" • Akurasi: {accuracy:.4f} ({accuracy*100:.2f}%)")
|
| 285 |
+
print(f" • F1-Score: {f1:.4f}")
|
| 286 |
+
print(f" • Kelas: 3 (Tidak Diabetes, Diabetes Tipe 1, Diabetes Tipe 2)")
|
| 287 |
+
|
| 288 |
+
print(f"\n 5 Fitur Terpenting:")
|
| 289 |
+
for i, (_, row) in enumerate(feature_importance.head(5).iterrows()):
|
| 290 |
+
print(f" {i+1}. {row['feature']}: {row['importance']:.4f}")
|
| 291 |
+
|
| 292 |
+
print(f"\n Model siap untuk deployment!")
|