diff --git a/streamlit_app.py b/streamlit_app.py index 2478d4b..e19a180 100644 --- a/streamlit_app.py +++ b/streamlit_app.py @@ -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(""" """, unsafe_allow_html=True) @@ -252,7 +486,10 @@ def main(): # Header st.markdown('

Student Success Predictor

', unsafe_allow_html=True) - st.markdown("**Predict whether a student will Graduate, Dropout, or remain Enrolled based on academic and demographic factors.**") + st.markdown('

Predict whether a student will Graduate, Dropout, or remain Enrolled based on academic and demographic factors using advanced machine learning.

', unsafe_allow_html=True) + + # Progress indicator (shows completion percentage) + progress_placeholder = st.empty() # Sidebar for input st.sidebar.markdown('

Student Information

', unsafe_allow_html=True) @@ -260,10 +497,12 @@ def main(): # Create input form with st.sidebar: # Quick presets - st.markdown("### Quick Start") + st.markdown('', 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'
โœ… Loading {preset} preset values. You can modify any field below.
', 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('
', unsafe_allow_html=True) + st.markdown("### ๐Ÿ‘ค Personal Information") + st.markdown('
Basic demographic information about the student
', 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('
', unsafe_allow_html=True) + st.markdown("### ๐ŸŽ“ Academic Background") + st.markdown('
Information about the student\'s application and academic history
', 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('
', unsafe_allow_html=True) + st.markdown("### ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Family Background") + st.markdown('
Parent education and occupation information
', 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('
', unsafe_allow_html=True) + st.markdown("### ๐Ÿ’ฐ Financial & Social") + st.markdown('
Student financial status and special circumstances
', 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('
', unsafe_allow_html=True) + st.markdown("### ๐Ÿ“š 1st Semester Performance") + st.markdown('
โš ๏ธ Important: Academic performance is a key predictor of student success
', 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('
', unsafe_allow_html=True) + st.markdown("### ๐Ÿ“– 2nd Semester Performance") + st.markdown('
Second semester data helps improve prediction accuracy
', 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('
', unsafe_allow_html=True) + st.markdown("### ๐Ÿ“Š Economic Indicators") + st.markdown('
๐Ÿ“ˆ Economic context data - typically set by institution based on current conditions
', unsafe_allow_html=True) col1, col2, col3 = st.columns(3) with col1: @@ -465,30 +719,93 @@ def main(): with col1: st.markdown('

Prediction Results

', 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'''
+ ๐ŸŽ“ GRADUATE +
Confidence: {confidence_level:.1%} ({confidence_text}) +
''', unsafe_allow_html=True) + st.balloons() + elif predicted_outcome == "Dropout": + st.markdown(f'''
+ โš ๏ธ AT RISK OF DROPOUT +
Confidence: {confidence_level:.1%} ({confidence_text}) +
''', unsafe_allow_html=True) + else: + st.markdown(f'''
+ ๐Ÿ“š LIKELY TO STAY ENROLLED +
Confidence: {confidence_level:.1%} ({confidence_text}) +
''', 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'
Predicted Outcome: GRADUATE
', unsafe_allow_html=True) + st.markdown('
๐ŸŽฏ Success Indicators: This student shows strong potential for graduation. Continue supporting their academic journey.
', unsafe_allow_html=True) elif predicted_outcome == "Dropout": - st.markdown(f'
Predicted Outcome: DROPOUT
', 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('
๐ŸŽฏ Intervention Strategies:
' + '
'.join(recommendations) + '
', unsafe_allow_html=True) else: - st.markdown(f'
Predicted Outcome: ENROLLED
', unsafe_allow_html=True) + st.markdown('
๐Ÿ“ˆ Monitoring Needed: This student may benefit from regular check-ins and academic support.
', 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('

About the Model

', unsafe_allow_html=True) + st.markdown('

๐Ÿ“Š Model Insights

', unsafe_allow_html=True) - st.info(""" - **Model Details:** + # Dynamic model information based on current inputs + st.markdown('
', 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('
', 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('
', 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('

๐ŸŽ“ Empowering educational institutions with data-driven insights for student success

', unsafe_allow_html=True) if __name__ == "__main__": main() \ No newline at end of file