mirror of
https://github.com/andwati/student-retention.git
synced 2026-10-18 08:52:53 +00:00
added model training file
This commit is contained in:
Generated
+5
@@ -0,0 +1,5 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
Generated
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.13 (student-retention)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (student-retention)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/student-retention.iml" filepath="$PROJECT_DIR$/.idea/student-retention.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+17
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.13 (student-retention)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="PyDocumentationSettings">
|
||||
<option name="format" value="PLAIN" />
|
||||
<option name="myDocStringFormat" value="Plain" />
|
||||
</component>
|
||||
<component name="TestRunnerService">
|
||||
<option name="PROJECT_TEST_RUNNER" value="py.test" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1 +1,3 @@
|
||||
# student retention
|
||||
# student retention
|
||||
|
||||
A beautiful Streamlit application that predicts student academic outcomes (Graduate, Dropout, or Enrolled) using a Random Forest model trained on 36 features including academic performance, demographics, and economic indicators.
|
||||
@@ -0,0 +1,166 @@
|
||||
"""
|
||||
Model Training and Pickle Export Script
|
||||
This script recreates the Random Forest model training process and saves the model and preprocessing pipeline.
|
||||
"""
|
||||
|
||||
import pickle
|
||||
|
||||
import pandas as pd
|
||||
from sklearn.ensemble import RandomForestClassifier
|
||||
from sklearn.model_selection import train_test_split
|
||||
|
||||
|
||||
def load_and_preprocess_data():
|
||||
"""Load and preprocess the data exactly as done in the notebook"""
|
||||
# Load data
|
||||
data_file_name_path = "./data/data.csv"
|
||||
master_raw_data = pd.read_csv(data_file_name_path)
|
||||
data = master_raw_data.copy()
|
||||
|
||||
# Fix column name typo
|
||||
data.rename(columns={'Nacionality': 'Nationality'}, inplace=True)
|
||||
|
||||
# Remove apostrophes from column names
|
||||
for column_name in data.columns:
|
||||
if "'" in column_name:
|
||||
new_column_name = column_name.replace("'", "")
|
||||
data.rename(columns={column_name: new_column_name}, inplace=True)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def encode_target_variable(data):
|
||||
"""Encode the target variable as done in the notebook"""
|
||||
# Label mapping from the notebook analysis
|
||||
target_mapping = {'Dropout': 0, 'Enrolled': 1, 'Graduate': 2}
|
||||
data['Target_encoded'] = data['Target'].map(target_mapping)
|
||||
return data
|
||||
|
||||
|
||||
def prepare_features_for_modeling(data):
|
||||
"""Prepare features exactly as done in the notebook"""
|
||||
# Get all categorical columns that need one-hot encoding
|
||||
categorical_columns = [
|
||||
'Marital status', 'Application mode', 'Course', 'Daytime/evening attendance',
|
||||
'Previous qualification', 'Nationality', 'Mothers qualification',
|
||||
'Fathers qualification', 'Mothers occupation', 'Fathers occupation',
|
||||
'Gender', 'Displaced', 'Educational special needs', 'Debtor',
|
||||
'Tuition fees up to date', 'Scholarship holder', 'International'
|
||||
]
|
||||
|
||||
# Additional columns that might be categorical (from notebook analysis)
|
||||
for col in data.columns:
|
||||
if col not in categorical_columns and col not in ['Target', 'Target_encoded']:
|
||||
unique_vals = data[col].nunique()
|
||||
# If low unique values, likely categorical
|
||||
if unique_vals <= 20 and col not in ['Age at enrollment']:
|
||||
categorical_columns.append(col)
|
||||
|
||||
# Create a copy for processing
|
||||
processed_data = data.copy()
|
||||
|
||||
# Perform one-hot encoding for categorical columns
|
||||
for column in categorical_columns:
|
||||
if column in processed_data.columns:
|
||||
# Get dummies with prefix
|
||||
dummies = pd.get_dummies(processed_data[column], prefix=column)
|
||||
# Concatenate with original data
|
||||
processed_data = pd.concat([processed_data, dummies], axis=1)
|
||||
# Drop original column
|
||||
processed_data.drop(columns=[column], inplace=True)
|
||||
|
||||
# Drop the original Target column, keep Target_encoded
|
||||
processed_data.drop(columns=['Target'], inplace=True)
|
||||
|
||||
return processed_data
|
||||
|
||||
|
||||
def train_and_save_model():
|
||||
"""Train the Random Forest model and save both model and preprocessing info"""
|
||||
|
||||
# Load and preprocess data
|
||||
print("Loading and preprocessing data...")
|
||||
data = load_and_preprocess_data()
|
||||
|
||||
# Encode target variable
|
||||
data = encode_target_variable(data)
|
||||
|
||||
# Prepare features
|
||||
processed_data = prepare_features_for_modeling(data)
|
||||
|
||||
# Separate features and target
|
||||
X = processed_data.drop('Target_encoded', axis=1)
|
||||
y = processed_data['Target_encoded']
|
||||
|
||||
print(f"Final dataset shape: {X.shape}")
|
||||
print(f"Features: {X.columns.tolist()}")
|
||||
|
||||
# Split data (using 30% test size as in the notebook)
|
||||
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.30, random_state=42)
|
||||
|
||||
# Train Random Forest model
|
||||
print("Training Random Forest model...")
|
||||
rf_classifier = RandomForestClassifier(n_estimators=100, random_state=42)
|
||||
rf_classifier.fit(X_train, y_train)
|
||||
|
||||
# Evaluate model
|
||||
train_accuracy = rf_classifier.score(X_train, y_train)
|
||||
test_accuracy = rf_classifier.score(X_test, y_test)
|
||||
|
||||
print(f"Training Accuracy: {train_accuracy:.4f}")
|
||||
print(f"Test Accuracy: {test_accuracy:.4f}")
|
||||
|
||||
# Save the trained model
|
||||
with open('random_forest_model.pkl', 'wb') as f:
|
||||
pickle.dump(rf_classifier, f)
|
||||
|
||||
# Save feature names for consistency
|
||||
feature_names = X.columns.tolist()
|
||||
with open('feature_names.pkl', 'wb') as f:
|
||||
pickle.dump(feature_names, f)
|
||||
|
||||
# Save preprocessing information
|
||||
preprocessing_info = {
|
||||
'target_mapping': {'Dropout': 0, 'Enrolled': 1, 'Graduate': 2},
|
||||
'target_reverse_mapping': {0: 'Dropout', 1: 'Enrolled', 2: 'Graduate'},
|
||||
'categorical_columns': [
|
||||
'Marital status', 'Application mode', 'Course', 'Daytime/evening attendance',
|
||||
'Previous qualification', 'Nationality', 'Mothers qualification',
|
||||
'Fathers qualification', 'Mothers occupation', 'Fathers occupation',
|
||||
'Gender', 'Displaced', 'Educational special needs', 'Debtor',
|
||||
'Tuition fees up to date', 'Scholarship holder', 'International',
|
||||
'Application order' # Adding this based on notebook analysis
|
||||
],
|
||||
'feature_names': feature_names,
|
||||
'original_columns': [
|
||||
'Marital status', 'Application mode', 'Application order', 'Course',
|
||||
'Daytime/evening attendance', 'Previous qualification',
|
||||
'Previous qualification (grade)', 'Nationality', 'Mothers qualification',
|
||||
'Fathers qualification', 'Mothers occupation', 'Fathers occupation',
|
||||
'Admission grade', 'Displaced', 'Educational special needs', 'Debtor',
|
||||
'Tuition fees up to date', 'Gender', 'Scholarship holder',
|
||||
'Age at enrollment', 'International', 'Curricular units 1st sem (credited)',
|
||||
'Curricular units 1st sem (enrolled)', 'Curricular units 1st sem (evaluations)',
|
||||
'Curricular units 1st sem (approved)', 'Curricular units 1st sem (grade)',
|
||||
'Curricular units 1st sem (without evaluations)',
|
||||
'Curricular units 2nd sem (credited)', 'Curricular units 2nd sem (enrolled)',
|
||||
'Curricular units 2nd sem (evaluations)', 'Curricular units 2nd sem (approved)',
|
||||
'Curricular units 2nd sem (grade)', 'Curricular units 2nd sem (without evaluations)',
|
||||
'Unemployment rate', 'Inflation rate', 'GDP'
|
||||
]
|
||||
}
|
||||
|
||||
with open('preprocessing_info.pkl', 'wb') as f:
|
||||
pickle.dump(preprocessing_info, f)
|
||||
|
||||
print("Model and preprocessing info saved successfully!")
|
||||
print("Files created:")
|
||||
print("- random_forest_model.pkl")
|
||||
print("- feature_names.pkl")
|
||||
print("- preprocessing_info.pkl")
|
||||
|
||||
return rf_classifier, preprocessing_info
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
train_and_save_model()
|
||||
Reference in New Issue
Block a user