File size: 9,203 Bytes
ed42c5c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import streamlit as st
import pandas as pd
import numpy as np
import joblib

# Configured for wide mode to utilize all available screen space beautifully
st.set_page_config(
    page_title='Cancer Risk Predictor', 
    layout='wide', 
    initial_sidebar_state='collapsed'
)

@st.cache_resource
def load_artifacts():
    model = joblib.load('Models/model_xgb_new.pkl')
    le = joblib.load('Models/Label_encoder.pkl')
    feature_name = joblib.load('Models/Feature_names.pkl')
    return model, le, feature_name

model, le, FEATURE_NAMES = load_artifacts()

# --- HEADER SECTION ---
st.title("🧬 Cancer Risk Level Predictor")
st.markdown("Assess patient risk levels using advanced machine learning diagnostics. Choose a processing mode below.")

# Native Tabs look much cleaner and more professional than radio buttons for application routing
tab_batch, tab_manual = st.tabs(["πŸ“ Batch Processing (CSV Upload)", "πŸ‘€ Individual Patient Intake"])

def preprocess_input(df):
    missing = [c for c in FEATURE_NAMES if c not in df.columns]
    if missing:
        st.warning(f"⚠️ Missing Columns in input - Filling {len(missing)} fields with zero : {missing}")
        for c in missing:
            df[c] = 0
    df = df[FEATURE_NAMES].copy()
    df = df.apply(pd.to_numeric, errors='coerce').fillna(0)
    return df

# ==========================================
# πŸ“ BATCH PROCESSING MODE
# ==========================================
with tab_batch:
    st.subheader("Batch Dataset Analysis")
    st.markdown("Upload a patient population roster to parse risk profiles simultaneously.")
    
    uploaded_file = st.file_uploader("Drop your dataset here", type=['csv'], label_visibility="collapsed")
    
    if uploaded_file is not None:
        input_df = pd.read_csv(uploaded_file)
        
        with st.spinner("Processing framework algorithms..."):
            x = preprocess_input(input_df)
            pred_enc = model.predict(x)
            probs = model.predict_proba(x)
            preds = le.inverse_transform(pred_enc)
            
            result = x.copy()
            result['Predicted_Risk_Level'] = preds

            for i, cls in enumerate(le.classes_):
                result[f'prob_{cls}'] = probs[:, i]
                
        st.success("βœ… Analytics Engine Execution Complete")
        
        # Native interactive data frames allow users to filter, sort, and search right out of the box
        st.dataframe(result, use_container_width=True)
        
        st.download_button(
            label="πŸ“₯ Download Structured Predictions CSV", 
            data=result.to_csv(index=False), 
            file_name='predictions.csv', 
            mime='text/csv',
            type='secondary'
        )

# ==========================================
# πŸ‘€ INDIVIDUAL PATIENT INTAKE MODE
# ==========================================
with tab_manual:
    st.subheader("Manual Clinical Intake Form")
    
    # Using a native bordered container to logically isolate the entry parameters
    with st.container(border=True):
        st.markdown("#### 🩺 Demographics & Administrative Meta")
        c_meta1, c_meta2, c_meta3, c_meta4 = st.columns(4)
        input_data = {}
        
        with c_meta1:
            input_data['Patient_ID'] = st.text_input("Patient Identification ID", value="LU0005")
        with c_meta2:
            input_data['Cancer_Type'] = st.selectbox("Suspected Target System", ['Breast', 'Prostate', 'Skin', 'Colon', 'Lung'])
        with c_meta3:
            input_data['Age'] = st.number_input("Biological Age (Years)", min_value=0, max_value=120, value=50)
        with c_meta4:
            input_data['Gender'] = st.selectbox("Biological Sex Assigned", [0, 1], format_func=lambda x: "Female" if x == 0 else "Male")

    with st.container(border=True):
        st.markdown("#### βš–οΈ Physiological Vitals & Laboratory Scoring")
        c_phys1, c_phys2, c_phys3 = st.columns(3)
        
        with c_phys1:
            input_data['BMI'] = st.number_input("Body Mass Index (BMI)", min_value=10.0, max_value=60.0, value=25.0, step=0.1)
        with c_phys2:
            input_data['Overall_Risk_Score'] = st.number_input("Pre-evaluation Baseline Risk Score", min_value=0.0, max_value=1.0, value=0.4, step=0.01)
        with c_phys3:
            input_data['Calcium_Intake'] = st.slider("Dietary Calcium Scaling (0-10)", 0, 10, 5)

    with st.container(border=True):
        st.markdown("#### 🧬 Genetic & Pathogenic Pre-dispositions")
        c_gen1, c_gen2, c_gen3 = st.columns(3)
        
        with c_gen1:
            input_data['Family_History'] = st.selectbox("Family Oncological History", [0, 1], format_func=lambda x: "No History" if x == 0 else "Positive History")
        with c_gen2:
            input_data['BRCA_Mutation'] = st.selectbox("BRCA Variant Mutation Status", [0, 1], format_func=lambda x: "Negative / Normal" if x == 0 else "Positive Marker Present")
        with c_gen3:
            input_data['H_Pylori_Infection'] = st.selectbox("Active H. Pylori Infection Status", [0, 1], format_func=lambda x: "Negative" if x == 0 else "Positive Exposure")

    with st.container(border=True):
        st.markdown("#### 🚬 Behavioral Habits & Environmental Exposures")
        c_beh1, c_beh2 = st.columns(2)
        
        with c_beh1:
            input_data['Smoking'] = st.slider("Tobacco / Smoking Exposure Severity (0-10)", 0, 10, 0)
            input_data['Alcohol_Use'] = st.slider("Alcohol Consumption Volume Scale (0-10)", 0, 10, 0)
            input_data['Obesity'] = st.slider("Clinical Obesity Stratification Index (0-10)", 0, 10, 0)
            input_data['Physical_Activity'] = st.slider("Physical Activity Engagement Metric (0-10)", 0, 10, 5)
        with c_beh2:
            input_data['Diet_Red_Meat'] = st.slider("Red Meat Consumption Frequency (0-10)", 0, 10, 0)
            input_data['Diet_Salted_Processed'] = st.slider("Processed / Sodium Food Prevalence (0-10)", 0, 10, 0)
            input_data['Fruit_Veg_Intake'] = st.slider("Nutritional Fruit & Vegetable Density (0-10)", 0, 10, 5)
            input_data['Physical_Activity_Level'] = st.slider("Cardio / Physical Exertion Intensity Level (0-10)", 0, 10, 5)

    with st.container(border=True):
        st.markdown("#### 🏭 Ecological & Occupational Conditions")
        c_eco1, c_eco2 = st.columns(2)
        with c_eco1:
            input_data['Air_Pollution'] = st.slider("Particulate Air Pollution Hazard Scale (0-10)", 0, 10, 2)
        with c_eco2:
            input_data['Occupational_Hazards'] = st.slider("Workplace Carcinogen Exposure Scale (0-10)", 0, 10, 2)

    # Centered Primary Call to Action Button
    _, btn_col, _ = st.columns([2, 1, 2])
    with btn_col:
        predict_triggered = st.button("πŸ”¬ Compute Comprehensive Risk Profile", type="primary", use_container_width=True)

    if predict_triggered:
        x_single = pd.DataFrame([input_data])
        x_proc = preprocess_input(x_single)
        
        pred_enc = model.predict(x_proc)[0]
        probs = model.predict_proba(x_proc)[0]
        pred = le.inverse_transform([pred_enc])[0]

        st.markdown("---")
        st.subheader("πŸ“‹ Core Diagnostic Output Results")
        
        # UI Upgrade: Using native high-impact metric cards instead of just plain text
        c_res1, c_res2 = st.columns([2, 3])
        
        with c_res1:
            st.metric(label="Calculated Stratified Risk Target Level", value=f"{pred}")
            
            # Extract High risk threshold probability safely
            high_prob_val = probs[list(le.classes_).index('High')] if 'High' in le.classes_ else 0.0
            
            st.metric(label="Absolute High-Risk Probability Node Index", value=f"{high_prob_val:.2%}")
            
            if high_prob_val >= 0.5:
                st.warning("⚠️ **ALERT:** Patient assessment metrics exceed the preset danger threshold parameters. Immediate triage or secondary clinical review is strongly advised.")
            else:
                st.success("βœ… **STABLE:** Calculated biomarkers indicate the individual falls within normalized operating action baselines.")

        with c_res2:
            st.markdown("**Categorical Confidence Vector Matrix**")
            prob_df = pd.DataFrame({
                'Risk Classification Stratum': list(le.classes_),
                'Confidence Interval Probability': probs
            }).sort_values('Confidence Interval Probability', ascending=False).reset_index(drop=True)
            
            # Map values to neat percentage layout matrices
            prob_df['Confidence Interval Probability'] = prob_df['Confidence Interval Probability'].map(lambda x: f"{x:.2%}")
            st.table(prob_df)

st.markdown("---")
st.caption("βš™οΈ Diagnostic Engine: Class-Weighted Extreme Gradient Boosting (XGBoost Architecture optimized via Optuna framework). Check your input array configurations against standard evaluation models before deploying to clinical trials.")