# ============================================ # 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) # ============================================ @st.cache_resource 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 @st.cache_data 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()