mirror of
https://github.com/andwati/predictive_analysis.git
synced 2026-10-18 00:32:53 +00:00
deploy to streamlit
This commit is contained in:
+437
-59
@@ -10,6 +10,7 @@ import pickle
|
||||
import plotly.express as px
|
||||
import plotly.graph_objects as go
|
||||
from plotly.subplots import make_subplots
|
||||
import time
|
||||
|
||||
# Configure Streamlit page
|
||||
st.set_page_config(
|
||||
@@ -19,46 +20,279 @@ st.set_page_config(
|
||||
initial_sidebar_state="expanded"
|
||||
)
|
||||
|
||||
# Custom CSS for beautiful styling
|
||||
# Rose Pine Dark Theme CSS
|
||||
st.markdown("""
|
||||
<style>
|
||||
/* Import Google Fonts */
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
|
||||
|
||||
/* Rose Pine Color Palette */
|
||||
:root {
|
||||
--rp-base: #191724;
|
||||
--rp-surface: #1f1d2e;
|
||||
--rp-overlay: #26233a;
|
||||
--rp-muted: #6e6a86;
|
||||
--rp-subtle: #908caa;
|
||||
--rp-text: #e0def4;
|
||||
--rp-love: #eb6f92;
|
||||
--rp-gold: #f6c177;
|
||||
--rp-rose: #ebbcba;
|
||||
--rp-pine: #31748f;
|
||||
--rp-foam: #9ccfd8;
|
||||
--rp-iris: #c4a7e7;
|
||||
}
|
||||
|
||||
/* Global Styles */
|
||||
.stApp {
|
||||
font-family: 'Inter', sans-serif;
|
||||
background-color: var(--rp-base);
|
||||
color: var(--rp-text);
|
||||
}
|
||||
|
||||
/* Override Streamlit's default colors */
|
||||
.main .block-container {
|
||||
background-color: var(--rp-base);
|
||||
color: var(--rp-text);
|
||||
}
|
||||
|
||||
/* Sidebar styling */
|
||||
.css-1d391kg {
|
||||
background-color: var(--rp-surface);
|
||||
}
|
||||
|
||||
.css-1lcbmhc {
|
||||
background-color: var(--rp-surface);
|
||||
}
|
||||
|
||||
/* Header Styles */
|
||||
.main-header {
|
||||
font-size: 3rem;
|
||||
color: #1f77b4;
|
||||
font-size: 3.5rem;
|
||||
background: linear-gradient(135deg, var(--rp-iris), var(--rp-foam));
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
.sub-header {
|
||||
font-size: 1.5rem;
|
||||
color: #2c3e50;
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
.prediction-box {
|
||||
padding: 2rem;
|
||||
border-radius: 10px;
|
||||
|
||||
.subtitle {
|
||||
text-align: center;
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
margin: 1rem 0;
|
||||
font-size: 1.2rem;
|
||||
color: var(--rp-subtle);
|
||||
margin-bottom: 3rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.sub-header {
|
||||
font-size: 1.4rem;
|
||||
color: var(--rp-text);
|
||||
margin-bottom: 1.5rem;
|
||||
font-weight: 600;
|
||||
border-bottom: 2px solid var(--rp-overlay);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
/* Prediction Result Boxes */
|
||||
.prediction-box {
|
||||
padding: 2.5rem 2rem;
|
||||
border-radius: 16px;
|
||||
text-align: center;
|
||||
font-size: 1.8rem;
|
||||
font-weight: 700;
|
||||
margin: 2rem 0;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
|
||||
transform: translateY(0);
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
border: 2px solid;
|
||||
}
|
||||
|
||||
.prediction-box:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 20px 40px rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.graduate-box {
|
||||
background: linear-gradient(135deg, #28a745, #20c997);
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--rp-foam), var(--rp-pine));
|
||||
color: var(--rp-base);
|
||||
border-color: var(--rp-foam);
|
||||
}
|
||||
|
||||
.dropout-box {
|
||||
background: linear-gradient(135deg, #dc3545, #fd7e14);
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--rp-love), #c74665);
|
||||
color: var(--rp-text);
|
||||
border-color: var(--rp-love);
|
||||
}
|
||||
|
||||
.enrolled-box {
|
||||
background: linear-gradient(135deg, #ffc107, #fd7e14);
|
||||
color: white;
|
||||
background: linear-gradient(135deg, var(--rp-gold), #e6a85c);
|
||||
color: var(--rp-base);
|
||||
border-color: var(--rp-gold);
|
||||
}
|
||||
|
||||
/* Metric Cards */
|
||||
.metric-card {
|
||||
background: #f8f9fa;
|
||||
background: linear-gradient(135deg, var(--rp-surface), var(--rp-overlay));
|
||||
padding: 1.5rem;
|
||||
border-radius: 12px;
|
||||
border-left: 4px solid var(--rp-iris);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.metric-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 20px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.metric-card h4 {
|
||||
color: var(--rp-subtle);
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.metric-card h2 {
|
||||
color: var(--rp-iris);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* Sidebar Styling */
|
||||
.sidebar-section {
|
||||
background: var(--rp-overlay);
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid #1f77b4;
|
||||
margin-bottom: 1rem;
|
||||
border-left: 3px solid var(--rp-iris);
|
||||
}
|
||||
|
||||
/* Info boxes */
|
||||
.info-box {
|
||||
background: linear-gradient(135deg, var(--rp-overlay), var(--rp-surface));
|
||||
padding: 1.5rem;
|
||||
border-radius: 12px;
|
||||
border-left: 4px solid var(--rp-foam);
|
||||
margin: 1rem 0;
|
||||
color: var(--rp-text);
|
||||
}
|
||||
|
||||
.warning-box {
|
||||
background: linear-gradient(135deg, var(--rp-overlay), var(--rp-surface));
|
||||
padding: 1.5rem;
|
||||
border-radius: 12px;
|
||||
border-left: 4px solid var(--rp-gold);
|
||||
margin: 1rem 0;
|
||||
color: var(--rp-text);
|
||||
}
|
||||
|
||||
.success-box {
|
||||
background: linear-gradient(135deg, var(--rp-overlay), var(--rp-surface));
|
||||
padding: 1.5rem;
|
||||
border-radius: 12px;
|
||||
border-left: 4px solid var(--rp-pine);
|
||||
margin: 1rem 0;
|
||||
color: var(--rp-text);
|
||||
}
|
||||
|
||||
/* Button Styling */
|
||||
.stButton > button {
|
||||
background: linear-gradient(135deg, var(--rp-iris), var(--rp-love));
|
||||
color: var(--rp-text);
|
||||
border: none;
|
||||
border-radius: 25px;
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
padding: 0.75rem 2rem;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.stButton > button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 20px rgba(196, 167, 231, 0.4);
|
||||
}
|
||||
|
||||
/* Streamlit widget overrides */
|
||||
.stSelectbox > div > div {
|
||||
background-color: var(--rp-surface);
|
||||
color: var(--rp-text);
|
||||
border-color: var(--rp-overlay);
|
||||
}
|
||||
|
||||
.stNumberInput > div > div > input {
|
||||
background-color: var(--rp-surface);
|
||||
color: var(--rp-text);
|
||||
border-color: var(--rp-overlay);
|
||||
}
|
||||
|
||||
.stRadio > div {
|
||||
background-color: var(--rp-surface);
|
||||
border-radius: 8px;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
/* Progress indicator */
|
||||
.progress-container {
|
||||
background: var(--rp-overlay);
|
||||
border-radius: 10px;
|
||||
height: 8px;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
background: linear-gradient(90deg, var(--rp-iris), var(--rp-foam));
|
||||
height: 100%;
|
||||
border-radius: 10px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
/* Section dividers */
|
||||
.section-divider {
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, var(--rp-iris), transparent);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
/* Text color overrides */
|
||||
.markdown-text-container {
|
||||
color: var(--rp-text);
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: var(--rp-text);
|
||||
}
|
||||
|
||||
.stMarkdown {
|
||||
color: var(--rp-text);
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
animation: fadeInUp 0.6s ease forwards;
|
||||
}
|
||||
|
||||
/* Mobile responsiveness */
|
||||
@media (max-width: 768px) {
|
||||
.main-header {
|
||||
font-size: 2.5rem !important;
|
||||
}
|
||||
.prediction-box {
|
||||
font-size: 1.4rem !important;
|
||||
padding: 1.5rem 1rem !important;
|
||||
}
|
||||
.metric-card {
|
||||
padding: 1rem !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
""", unsafe_allow_html=True)
|
||||
@@ -252,7 +486,10 @@ def main():
|
||||
|
||||
# Header
|
||||
st.markdown('<h1 class="main-header">Student Success Predictor</h1>', unsafe_allow_html=True)
|
||||
st.markdown("**Predict whether a student will Graduate, Dropout, or remain Enrolled based on academic and demographic factors.**")
|
||||
st.markdown('<p class="subtitle">Predict whether a student will Graduate, Dropout, or remain Enrolled based on academic and demographic factors using advanced machine learning.</p>', unsafe_allow_html=True)
|
||||
|
||||
# Progress indicator (shows completion percentage)
|
||||
progress_placeholder = st.empty()
|
||||
|
||||
# Sidebar for input
|
||||
st.sidebar.markdown('<h2 class="sub-header">Student Information</h2>', unsafe_allow_html=True)
|
||||
@@ -260,10 +497,12 @@ def main():
|
||||
# Create input form
|
||||
with st.sidebar:
|
||||
# Quick presets
|
||||
st.markdown("### Quick Start")
|
||||
st.markdown('<div class="sidebar-section">', unsafe_allow_html=True)
|
||||
st.markdown("### 🚀 Quick Start")
|
||||
preset = st.selectbox("Load Sample Data",
|
||||
["Custom Entry", "Typical Graduate Student", "At-Risk Student", "International Student"],
|
||||
help="Choose a preset to quickly fill common scenarios")
|
||||
st.markdown('</div>', unsafe_allow_html=True)
|
||||
|
||||
# Set default values based on preset
|
||||
defaults = {
|
||||
@@ -274,10 +513,16 @@ def main():
|
||||
}
|
||||
|
||||
if preset != "Custom Entry":
|
||||
st.info(f"Loading {preset} preset values. You can modify any field below.")
|
||||
st.markdown(f'<div class="success-box">✅ Loading <strong>{preset}</strong> preset values. You can modify any field below.</div>', unsafe_allow_html=True)
|
||||
|
||||
# Form progress tracking
|
||||
form_sections = ["Personal Information", "Academic Background", "Family Background", "Financial & Social", "1st Semester Performance", "2nd Semester Performance", "Economic Indicators"]
|
||||
current_section = 0
|
||||
|
||||
# Personal Information
|
||||
st.markdown("### Personal Information")
|
||||
st.markdown('<div class="section-divider"></div>', unsafe_allow_html=True)
|
||||
st.markdown("### 👤 Personal Information")
|
||||
st.markdown('<div class="info-box">Basic demographic information about the student</div>', unsafe_allow_html=True)
|
||||
|
||||
marital_status = st.selectbox(
|
||||
"Marital Status",
|
||||
@@ -291,7 +536,9 @@ def main():
|
||||
nationality = st.selectbox("Nationality", [1, 2, 6, 11, 13, 14, 17, 21, 22, 24, 25, 26, 32, 41, 62, 100, 101, 103, 105, 108, 109], index=0)
|
||||
|
||||
# Academic Background
|
||||
st.markdown("### Academic Background")
|
||||
st.markdown('<div class="section-divider"></div>', unsafe_allow_html=True)
|
||||
st.markdown("### 🎓 Academic Background")
|
||||
st.markdown('<div class="info-box">Information about the student\'s application and academic history</div>', unsafe_allow_html=True)
|
||||
|
||||
application_mode = st.selectbox(
|
||||
"Application Mode",
|
||||
@@ -324,7 +571,9 @@ def main():
|
||||
admission_grade = st.number_input("Admission Grade", min_value=95, max_value=190, value=defaults[preset]["adm_grade"], step=1)
|
||||
|
||||
# Family Background
|
||||
st.markdown("### Family Background")
|
||||
st.markdown('<div class="section-divider"></div>', unsafe_allow_html=True)
|
||||
st.markdown("### 👨👩👧👦 Family Background")
|
||||
st.markdown('<div class="info-box">Parent education and occupation information</div>', unsafe_allow_html=True)
|
||||
|
||||
mothers_qualification = st.selectbox(
|
||||
"Mother's Qualification",
|
||||
@@ -351,7 +600,9 @@ def main():
|
||||
)
|
||||
|
||||
# Financial and Social Factors
|
||||
st.markdown("### Financial & Social")
|
||||
st.markdown('<div class="section-divider"></div>', unsafe_allow_html=True)
|
||||
st.markdown("### 💰 Financial & Social")
|
||||
st.markdown('<div class="info-box">Student financial status and special circumstances</div>', unsafe_allow_html=True)
|
||||
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
@@ -364,8 +615,9 @@ def main():
|
||||
international = st.radio("International Student", [0, 1], format_func=lambda x: "No" if x == 0 else "Yes", horizontal=True)
|
||||
|
||||
# Academic Performance - 1st Semester
|
||||
st.markdown("### 1st Semester Performance")
|
||||
st.caption("Enter the student's academic performance for their first semester")
|
||||
st.markdown('<div class="section-divider"></div>', unsafe_allow_html=True)
|
||||
st.markdown("### 📚 1st Semester Performance")
|
||||
st.markdown('<div class="warning-box">⚠️ <strong>Important:</strong> Academic performance is a key predictor of student success</div>', unsafe_allow_html=True)
|
||||
|
||||
# Set default academic values based on preset
|
||||
first_sem_defaults = {
|
||||
@@ -386,8 +638,9 @@ def main():
|
||||
curricular_units_1st_sem_without_evaluations = st.number_input("Without Evaluations", min_value=0, max_value=14, value=first_sem_defaults[preset]["without"], step=1, key="1st_without", help="Courses registered but not evaluated")
|
||||
|
||||
# Academic Performance - 2nd Semester
|
||||
st.markdown("### 2nd Semester Performance")
|
||||
st.caption("Enter the student's academic performance for their second semester")
|
||||
st.markdown('<div class="section-divider"></div>', unsafe_allow_html=True)
|
||||
st.markdown("### 📖 2nd Semester Performance")
|
||||
st.markdown('<div class="info-box">Second semester data helps improve prediction accuracy</div>', unsafe_allow_html=True)
|
||||
|
||||
# Set default academic values for 2nd semester based on preset
|
||||
second_sem_defaults = {
|
||||
@@ -408,8 +661,9 @@ def main():
|
||||
curricular_units_2nd_sem_without_evaluations = st.number_input("Without Evaluations", min_value=0, max_value=12, value=second_sem_defaults[preset]["without"], step=1, key="2nd_without", help="Courses registered but not evaluated")
|
||||
|
||||
# Economic Indicators
|
||||
st.markdown("### Economic Indicators")
|
||||
st.caption("These are typically set by the institution based on current economic conditions")
|
||||
st.markdown('<div class="section-divider"></div>', unsafe_allow_html=True)
|
||||
st.markdown("### 📊 Economic Indicators")
|
||||
st.markdown('<div class="info-box">📈 Economic context data - typically set by institution based on current conditions</div>', unsafe_allow_html=True)
|
||||
|
||||
col1, col2, col3 = st.columns(3)
|
||||
with col1:
|
||||
@@ -465,30 +719,93 @@ def main():
|
||||
with col1:
|
||||
st.markdown('<h2 class="sub-header">Prediction Results</h2>', unsafe_allow_html=True)
|
||||
|
||||
# Make prediction
|
||||
if st.button("Predict Student Outcome", type="primary"):
|
||||
with st.spinner("Analyzing student data..."):
|
||||
# Preprocess input
|
||||
processed_input = preprocess_input(user_input, preprocessing_info)
|
||||
# Prediction button with enhanced styling
|
||||
predict_button = st.button("🔬 Analyze Student Data", type="primary", use_container_width=True)
|
||||
|
||||
if predict_button:
|
||||
# Enhanced loading animation
|
||||
progress_bar = st.progress(0)
|
||||
status_text = st.empty()
|
||||
|
||||
# Simulate processing steps
|
||||
steps = [
|
||||
("Loading student data...", 20),
|
||||
("Preprocessing features...", 40),
|
||||
("Running machine learning model...", 70),
|
||||
("Calculating prediction confidence...", 90),
|
||||
("Finalizing results...", 100)
|
||||
]
|
||||
|
||||
for step, progress in steps:
|
||||
status_text.text(step)
|
||||
progress_bar.progress(progress)
|
||||
time.sleep(0.3)
|
||||
|
||||
# Clear progress indicators
|
||||
progress_bar.empty()
|
||||
status_text.empty()
|
||||
|
||||
# Preprocess input
|
||||
processed_input = preprocess_input(user_input, preprocessing_info)
|
||||
|
||||
# Make prediction
|
||||
prediction = model.predict(processed_input)[0]
|
||||
prediction_proba = model.predict_proba(processed_input)[0]
|
||||
|
||||
# Get prediction label
|
||||
target_reverse_mapping = preprocessing_info['target_reverse_mapping']
|
||||
predicted_outcome = target_reverse_mapping[prediction]
|
||||
|
||||
# Store in session state for export
|
||||
st.session_state['last_prediction'] = {
|
||||
'outcome': predicted_outcome,
|
||||
'probabilities': prediction_proba,
|
||||
'timestamp': time.time()
|
||||
}
|
||||
|
||||
# Enhanced prediction display with confidence indicators
|
||||
confidence_level = max(prediction_proba)
|
||||
confidence_text = "High" if confidence_level > 0.7 else "Medium" if confidence_level > 0.5 else "Low"
|
||||
|
||||
# Display prediction with enhanced styling and confidence
|
||||
if predicted_outcome == "Graduate":
|
||||
st.markdown(f'''<div class="prediction-box graduate-box fade-in">
|
||||
🎓 GRADUATE
|
||||
<br><small style="font-size: 1rem; opacity: 0.9;">Confidence: {confidence_level:.1%} ({confidence_text})</small>
|
||||
</div>''', unsafe_allow_html=True)
|
||||
st.balloons()
|
||||
elif predicted_outcome == "Dropout":
|
||||
st.markdown(f'''<div class="prediction-box dropout-box fade-in">
|
||||
⚠️ AT RISK OF DROPOUT
|
||||
<br><small style="font-size: 1rem; opacity: 0.9;">Confidence: {confidence_level:.1%} ({confidence_text})</small>
|
||||
</div>''', unsafe_allow_html=True)
|
||||
else:
|
||||
st.markdown(f'''<div class="prediction-box enrolled-box fade-in">
|
||||
📚 LIKELY TO STAY ENROLLED
|
||||
<br><small style="font-size: 1rem; opacity: 0.9;">Confidence: {confidence_level:.1%} ({confidence_text})</small>
|
||||
</div>''', unsafe_allow_html=True)
|
||||
|
||||
# Make prediction
|
||||
prediction = model.predict(processed_input)[0]
|
||||
prediction_proba = model.predict_proba(processed_input)[0]
|
||||
# Add personalized recommendations based on prediction
|
||||
st.markdown("### 💡 Personalized Recommendations")
|
||||
|
||||
# Get prediction label
|
||||
target_reverse_mapping = preprocessing_info['target_reverse_mapping']
|
||||
predicted_outcome = target_reverse_mapping[prediction]
|
||||
|
||||
# Display prediction with styling
|
||||
if predicted_outcome == "Graduate":
|
||||
st.markdown(f'<div class="prediction-box graduate-box">Predicted Outcome: GRADUATE</div>', unsafe_allow_html=True)
|
||||
st.markdown('<div class="success-box">🎯 <strong>Success Indicators:</strong> This student shows strong potential for graduation. Continue supporting their academic journey.</div>', unsafe_allow_html=True)
|
||||
elif predicted_outcome == "Dropout":
|
||||
st.markdown(f'<div class="prediction-box dropout-box">Predicted Outcome: DROPOUT</div>', unsafe_allow_html=True)
|
||||
recommendations = []
|
||||
if user_input['Curricular units 1st sem (approved)'] == 0:
|
||||
recommendations.append("📚 **Academic Support:** Provide tutoring for struggling courses")
|
||||
if user_input['Scholarship holder'] == 0:
|
||||
recommendations.append("💰 **Financial Aid:** Consider scholarship opportunities")
|
||||
if user_input['Age at enrollment'] > 25:
|
||||
recommendations.append("🕐 **Flexible Scheduling:** Offer evening or part-time options")
|
||||
|
||||
if recommendations:
|
||||
st.markdown('<div class="warning-box">🎯 <strong>Intervention Strategies:</strong><br>' + '<br>'.join(recommendations) + '</div>', unsafe_allow_html=True)
|
||||
else:
|
||||
st.markdown(f'<div class="prediction-box enrolled-box">Predicted Outcome: ENROLLED</div>', unsafe_allow_html=True)
|
||||
st.markdown('<div class="info-box">📈 <strong>Monitoring Needed:</strong> This student may benefit from regular check-ins and academic support.</div>', unsafe_allow_html=True)
|
||||
|
||||
# Display probabilities
|
||||
st.markdown("### Prediction Confidence")
|
||||
st.markdown("### 📊 Prediction Confidence")
|
||||
|
||||
prob_df = pd.DataFrame({
|
||||
'Outcome': ['Dropout', 'Enrolled', 'Graduate'],
|
||||
@@ -539,16 +856,40 @@ def main():
|
||||
""", unsafe_allow_html=True)
|
||||
|
||||
with col2:
|
||||
st.markdown('<h2 class="sub-header">About the Model</h2>', unsafe_allow_html=True)
|
||||
st.markdown('<h2 class="sub-header">📊 Model Insights</h2>', unsafe_allow_html=True)
|
||||
|
||||
st.info("""
|
||||
**Model Details:**
|
||||
# Dynamic model information based on current inputs
|
||||
st.markdown('<div class="info-box">', unsafe_allow_html=True)
|
||||
st.markdown("""
|
||||
**🤖 Model Details:**
|
||||
- **Algorithm:** Random Forest Classifier
|
||||
- **Features:** 36 student characteristics
|
||||
- **Features:** 36 student characteristics
|
||||
- **Training Accuracy:** 100%
|
||||
- **Test Accuracy:** 93.84%
|
||||
- **Classes:** Graduate, Dropout, Enrolled
|
||||
""")
|
||||
st.markdown('</div>', unsafe_allow_html=True)
|
||||
|
||||
# Add input validation feedback
|
||||
st.markdown("### 🔍 Input Validation")
|
||||
validation_container = st.container()
|
||||
|
||||
# Basic validation checks
|
||||
validation_issues = []
|
||||
|
||||
# Check for unrealistic combinations
|
||||
if user_input['Age at enrollment'] < 17:
|
||||
validation_issues.append("⚠️ Age seems too low for enrollment")
|
||||
if user_input['Curricular units 1st sem (approved)'] > user_input['Curricular units 1st sem (enrolled)']:
|
||||
validation_issues.append("⚠️ Approved units exceed enrolled units (1st sem)")
|
||||
if user_input['Curricular units 2nd sem (approved)'] > user_input['Curricular units 2nd sem (enrolled)']:
|
||||
validation_issues.append("⚠️ Approved units exceed enrolled units (2nd sem)")
|
||||
|
||||
if validation_issues:
|
||||
for issue in validation_issues:
|
||||
st.warning(issue)
|
||||
else:
|
||||
st.success("✅ All inputs look valid!")
|
||||
|
||||
st.markdown("### Key Factors")
|
||||
st.markdown("""
|
||||
@@ -593,10 +934,47 @@ def main():
|
||||
)
|
||||
|
||||
st.plotly_chart(fig_perf, use_container_width=True)
|
||||
|
||||
# Add export functionality
|
||||
st.markdown("### 📥 Export Results")
|
||||
|
||||
if st.session_state.get('last_prediction'):
|
||||
export_data = {
|
||||
'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'prediction': st.session_state['last_prediction']['outcome'],
|
||||
'confidence': f"{max(st.session_state['last_prediction']['probabilities']):.1%}",
|
||||
'student_data': user_input
|
||||
}
|
||||
|
||||
# Convert to JSON for download
|
||||
import json
|
||||
json_str = json.dumps(export_data, indent=2, ensure_ascii=False)
|
||||
|
||||
st.download_button(
|
||||
label="📁 Download Prediction Report",
|
||||
data=json_str,
|
||||
file_name=f"student_prediction_{time.strftime('%Y%m%d_%H%M%S')}.json",
|
||||
mime="application/json"
|
||||
)
|
||||
|
||||
# Enhanced Footer with additional info
|
||||
st.markdown('<div class="section-divider"></div>', unsafe_allow_html=True)
|
||||
col1, col2, col3 = st.columns(3)
|
||||
|
||||
with col1:
|
||||
st.markdown("**📊 Data Source**")
|
||||
st.caption("UCI ML Repository - Student Academic Success")
|
||||
|
||||
with col2:
|
||||
st.markdown("**🔬 Model Info**")
|
||||
st.caption("Random Forest with 93.84% accuracy")
|
||||
|
||||
with col3:
|
||||
st.markdown("**🛠️ Built With**")
|
||||
st.caption("Streamlit • scikit-learn • Plotly")
|
||||
|
||||
# Footer
|
||||
st.markdown("---")
|
||||
st.markdown("*Developed using Streamlit and scikit-learn*")
|
||||
st.markdown('<p style="text-align: center; color: #6c757d; font-size: 0.9rem;">🎓 Empowering educational institutions with data-driven insights for student success</p>', unsafe_allow_html=True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user