Spaces:
Running
Running
| # ============================================ | |
| # HEART ATTACK PREDICTION APP | |
| # Random Forest & XGBoost | |
| # ============================================ | |
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import joblib | |
| import os | |
| # Konfigurasi halaman | |
| st.set_page_config( | |
| page_title="Prediksi Serangan Jantung", | |
| page_icon="❤️", | |
| layout="wide" | |
| ) | |
| # ============================================ | |
| # LOAD MODEL (dengan cache) | |
| # ============================================ | |
| def load_models(): | |
| rf_model = joblib.load('random_forest_model.pkl') | |
| xgb_model = joblib.load('xgboost_model.pkl') | |
| label_encoders = joblib.load('label_encoders.pkl') | |
| return rf_model, xgb_model, label_encoders | |
| def load_feature_names(): | |
| # Sesuaikan dengan dataset kamu | |
| features = [ | |
| 'age', 'gender', 'region', 'income_level', 'hypertension', | |
| 'diabetes', 'cholesterol_level', 'obesity', 'waist_circumference', | |
| 'family_history', 'smoking_status', 'alcohol_consumption', | |
| 'physical_activity', 'dietary_habits', 'air_pollution_exposure', | |
| 'stress_level', 'sleep_hours', 'blood_pressure_systolic', | |
| 'blood_pressure_diastolic', 'fasting_blood_sugar', | |
| 'cholesterol_hdl', 'cholesterol_ldl', 'triglycerides', | |
| 'EKG_results', 'previous_heart_disease', 'medication_usage', | |
| 'participated_in_free_screening' | |
| ] | |
| return features | |
| # ============================================ | |
| # FUNGSI PREPROCESSING INPUT | |
| # ============================================ | |
| def preprocess_input(data, label_encoders): | |
| """Convert input form menjadi dataframe yang siap prediksi""" | |
| df = pd.DataFrame([data]) | |
| # Kolom kategorikal yang perlu di-encode | |
| categorical_cols = ['gender', 'region', 'income_level', 'smoking_status', | |
| 'alcohol_consumption', 'physical_activity', | |
| 'dietary_habits', 'air_pollution_exposure', | |
| 'stress_level', 'EKG_results'] | |
| for col in categorical_cols: | |
| if col in df.columns and col in label_encoders: | |
| try: | |
| df[col] = label_encoders[col].transform(df[col].astype(str)) | |
| except: | |
| df[col] = 0 | |
| # Pastikan tipe data numerik | |
| for col in df.columns: | |
| df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0) | |
| return df | |
| # ============================================ | |
| # MAIN APP | |
| # ============================================ | |
| def main(): | |
| st.title("🫀 Prediksi Risiko Serangan Jantung") | |
| st.markdown(""" | |
| ### Aplikasi Prediksi Menggunakan: | |
| - **Random Forest Classifier** | |
| - **XGBoost Classifier** | |
| Masukkan data pasien di bawah ini untuk mengetahui risiko serangan jantung. | |
| """) | |
| # Load model | |
| try: | |
| rf_model, xgb_model, label_encoders = load_models() | |
| except Exception as e: | |
| st.error(f"❌ Gagal load model: {e}") | |
| st.info("Pastikan file model (random_forest_model.pkl, xgboost_model.pkl, label_encoders.pkl) ada di folder yang sama.") | |
| return | |
| # ============================================ | |
| # FORM INPUT | |
| # ============================================ | |
| with st.form("prediction_form"): | |
| st.subheader("📋 Data Pasien") | |
| col1, col2, col3 = st.columns(3) | |
| with col1: | |
| age = st.number_input("Usia (tahun)", min_value=20, max_value=100, value=55) | |
| gender = st.selectbox("Jenis Kelamin", ["Male", "Female"]) | |
| region = st.selectbox("Wilayah", ["Urban", "Rural"]) | |
| income_level = st.selectbox("Tingkat Pendapatan", ["Low", "Middle", "High"]) | |
| hypertension = st.selectbox("Hipertensi", [0, 1], format_func=lambda x: "Ya" if x == 1 else "Tidak") | |
| diabetes = st.selectbox("Diabetes", [0, 1], format_func=lambda x: "Ya" if x == 1 else "Tidak") | |
| cholesterol_level = st.number_input("Kolesterol Total (mg/dL)", min_value=100, max_value=350, value=200) | |
| obesity = st.selectbox("Obesitas", [0, 1], format_func=lambda x: "Ya" if x == 1 else "Tidak") | |
| waist_circumference = st.number_input("Lingkar Pinggang (cm)", min_value=20, max_value=180, value=90) | |
| with col2: | |
| family_history = st.selectbox("Riwayat Keluarga", [0, 1], format_func=lambda x: "Ya" if x == 1 else "Tidak") | |
| smoking_status = st.selectbox("Status Merokok", ["Never", "Past", "Current"]) | |
| alcohol_consumption = st.selectbox("Konsumsi Alkohol", ["None", "Moderate", "Heavy"]) | |
| physical_activity = st.selectbox("Aktivitas Fisik", ["Low", "Moderate", "High"]) | |
| dietary_habits = st.selectbox("Kebiasaan Makan", ["Unhealthy", "Healthy"]) | |
| air_pollution_exposure = st.selectbox("Paparan Polusi Udara", ["Low", "Moderate", "High"]) | |
| stress_level = st.selectbox("Tingkat Stres", ["Low", "Moderate", "High"]) | |
| sleep_hours = st.number_input("Jam Tidur (jam)", min_value=3.0, max_value=9.0, value=7.0, step=0.1) | |
| with col3: | |
| blood_pressure_systolic = st.number_input("Tekanan Darah Sistolik", min_value=90, max_value=200, value=120) | |
| blood_pressure_diastolic = st.number_input("Tekanan Darah Diastolik", min_value=60, max_value=130, value=80) | |
| fasting_blood_sugar = st.number_input("Gula Darah Puasa (mg/dL)", min_value=70, max_value=250, value=100) | |
| cholesterol_hdl = st.number_input("Kolesterol HDL (mg/dL)", min_value=10, max_value=100, value=50) | |
| cholesterol_ldl = st.number_input("Kolesterol LDL (mg/dL)", min_value=10, max_value=300, value=130) | |
| triglycerides = st.number_input("Trigliserida (mg/dL)", min_value=50, max_value=400, value=150) | |
| EKG_results = st.selectbox("Hasil EKG", ["Normal", "Abnormal"]) | |
| previous_heart_disease = st.selectbox("Riwayat Serangan Jantung", [0, 1], format_func=lambda x: "Ya" if x == 1 else "Tidak") | |
| medication_usage = st.selectbox("Penggunaan Obat", [0, 1], format_func=lambda x: "Ya" if x == 1 else "Tidak") | |
| participated_in_free_screening = st.selectbox("Ikut Skrining Gratis", [0, 1], format_func=lambda x: "Ya" if x == 1 else "Tidak") | |
| submitted = st.form_submit_button("🔮 Prediksi", type="primary") | |
| # ============================================ | |
| # PROSES PREDIKSI | |
| # ============================================ | |
| if submitted: | |
| with st.spinner("🔮 Memproses prediksi..."): | |
| # Kumpulkan data | |
| input_data = { | |
| 'age': age, | |
| 'gender': gender, | |
| 'region': region, | |
| 'income_level': income_level, | |
| 'hypertension': hypertension, | |
| 'diabetes': diabetes, | |
| 'cholesterol_level': cholesterol_level, | |
| 'obesity': obesity, | |
| 'waist_circumference': waist_circumference, | |
| 'family_history': family_history, | |
| 'smoking_status': smoking_status, | |
| 'alcohol_consumption': alcohol_consumption, | |
| 'physical_activity': physical_activity, | |
| 'dietary_habits': dietary_habits, | |
| 'air_pollution_exposure': air_pollution_exposure, | |
| 'stress_level': stress_level, | |
| 'sleep_hours': sleep_hours, | |
| 'blood_pressure_systolic': blood_pressure_systolic, | |
| 'blood_pressure_diastolic': blood_pressure_diastolic, | |
| 'fasting_blood_sugar': fasting_blood_sugar, | |
| 'cholesterol_hdl': cholesterol_hdl, | |
| 'cholesterol_ldl': cholesterol_ldl, | |
| 'triglycerides': triglycerides, | |
| 'EKG_results': EKG_results, | |
| 'previous_heart_disease': previous_heart_disease, | |
| 'medication_usage': medication_usage, | |
| 'participated_in_free_screening': participated_in_free_screening | |
| } | |
| # Preprocess | |
| df_input = preprocess_input(input_data, label_encoders) | |
| # Prediksi (konversi ke float) | |
| rf_pred = rf_model.predict(df_input)[0] | |
| rf_proba = float(rf_model.predict_proba(df_input)[0][1]) # <- tambahkan float() | |
| xgb_pred = xgb_model.predict(df_input)[0] | |
| xgb_proba = float(xgb_model.predict_proba(df_input)[0][1]) # <- tambahkan float() | |
| # ============================================ | |
| # TAMPILKAN HASIL | |
| # ============================================ | |
| st.subheader("📊 Hasil Prediksi") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown("### 🌲 Random Forest") | |
| if rf_pred == 1: | |
| st.error(f"⚠️ **BERISIKO** (Probabilitas: {rf_proba:.2%})") | |
| else: | |
| st.success(f"✅ **TIDAK BERISIKO** (Probabilitas: {rf_proba:.2%})") | |
| # Sekarang aman karena sudah float | |
| st.progress(rf_proba) | |
| st.caption(f"Probabilitas risiko: {rf_proba:.2%}") | |
| with col2: | |
| st.markdown("### ⚡ XGBoost") | |
| if xgb_pred == 1: | |
| st.error(f"⚠️ **BERISIKO** (Probabilitas: {xgb_proba:.2%})") | |
| else: | |
| st.success(f"✅ **TIDAK BERISIKO** (Probabilitas: {xgb_proba:.2%})") | |
| st.progress(xgb_proba) # Sekarang aman | |
| st.caption(f"Probabilitas risiko: {xgb_proba:.2%}") | |
| with col2: | |
| st.markdown("### ⚡ XGBoost") | |
| if xgb_pred == 1: | |
| st.error(f"⚠️ **BERISIKO** (Probabilitas: {xgb_proba:.2%})") | |
| else: | |
| st.success(f"✅ **TIDAK BERISIKO** (Probabilitas: {xgb_proba:.2%})") | |
| st.progress(xgb_proba) | |
| st.caption(f"Probabilitas risiko: {xgb_proba:.2%}") | |
| # Interpretasi | |
| st.markdown("---") | |
| st.subheader("📝 Interpretasi") | |
| avg_proba = (rf_proba + xgb_proba) / 2 | |
| if avg_proba >= 0.7: | |
| st.error("🚨 **RISIKO TINGGI!** Segera konsultasikan ke dokter.") | |
| elif avg_proba >= 0.4: | |
| st.warning("⚠️ **RISIKO SEDANG.** Perhatikan gaya hidup dan rutin cek kesehatan.") | |
| else: | |
| st.success("✅ **RISIKO RENDAH.** Tetap jaga pola makan dan olahraga teratur.") | |
| if __name__ == "__main__": | |
| main() |