Titanic Survival Model Training¶
This notebook runs the training pipeline from train_model.py one step at a time inside the Docker training container (quay.io/jupyter/base-notebook:python-3.13). The trained model and its files are saved to models/ and then copied into the serving container.
In [1]:
import train_model as tm
1. Load and explore the data¶
The data is Kaggle's Titanic train.csv (891 passengers), saved as data/titanic.csv.
In [2]:
df = tm.load_and_explore_data()
Loading Titanic dataset...
Dataset shape: (891, 12)
First few rows:
PassengerId Survived Pclass \
0 1 0 3
1 2 1 1
2 3 1 3
3 4 1 1
4 5 0 3
Name Sex Age SibSp \
0 Braund, Mr. Owen Harris male 22.0 1
1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1
2 Heikkinen, Miss. Laina female 26.0 0
3 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1
4 Allen, Mr. William Henry male 35.0 0
Parch Ticket Fare Cabin Embarked
0 0 A/5 21171 7.2500 NaN S
1 0 PC 17599 71.2833 C85 C
2 0 STON/O2. 3101282 7.9250 NaN S
3 0 113803 53.1000 C123 S
4 0 373450 8.0500 NaN S
Dataset info:
<class 'pandas.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PassengerId 891 non-null int64
1 Survived 891 non-null int64
2 Pclass 891 non-null int64
3 Name 891 non-null str
4 Sex 891 non-null str
5 Age 714 non-null float64
6 SibSp 891 non-null int64
7 Parch 891 non-null int64
8 Ticket 891 non-null str
9 Fare 891 non-null float64
10 Cabin 204 non-null str
11 Embarked 889 non-null str
dtypes: float64(2), int64(5), str(5)
memory usage: 83.7 KB
Missing values:
PassengerId 0
Survived 0
Pclass 0
Name 0
Sex 0
Age 177
SibSp 0
Parch 0
Ticket 0
Fare 0
Cabin 687
Embarked 2
dtype: int64
Survival rate by gender:
Sex
female 0.742038
male 0.188908
Name: Survived, dtype: float64
Survival rate by class:
Pclass
1 0.629630
2 0.472826
3 0.242363
Name: Survived, dtype: float64
2. Clean the data and create new features¶
Missing ages and fares are filled with the median, and missing ports with the most common port. Then I add family size, traveling alone, title (from the name), age group, and fare group.
In [3]:
processed_data = tm.preprocess_data(df)
processed_data[['Age', 'Embarked', 'Fare']].isnull().sum()
Preprocessing data... Preprocessed data shape: (891, 17) New features created: - FamilySize: SibSp + Parch + 1 - IsAlone: Whether passenger traveled alone - Title: Title extracted from name - AgeGroup: Age categories - FareGroup: Fare categories
Out[3]:
Age 0 Embarked 0 Fare 0 dtype: int64
3. Turn the text columns into numbers¶
In [4]:
model_data, label_encoders = tm.encode_features(processed_data)
Encoding categorical features... Encoded Sex: ['female', 'male'] Encoded Embarked: ['C', 'Q', 'S'] Encoded Title: ['Master', 'Miss', 'Mr', 'Mrs', 'Other'] Encoded AgeGroup: ['Adult', 'Child', 'Middle', 'Senior', 'Teen'] Encoded FareGroup: ['High', 'Low', 'Medium', 'VeryHigh']
4. Train and evaluate the Random Forest¶
20% of the passengers are held out to test the model.
In [5]:
model, accuracy, feature_importance, feature_names = tm.train_model(model_data)
Training Random Forest model...
Training set size: 712
Test set size: 179
Model Accuracy: 0.8156
Classification Report:
precision recall f1-score support
0 0.83 0.88 0.85 110
1 0.79 0.71 0.75 69
accuracy 0.82 179
macro avg 0.81 0.80 0.80 179
weighted avg 0.81 0.82 0.81 179
Top 10 Most Important Features:
feature importance
1 Sex 0.281493
5 Fare 0.171489
9 Title 0.126609
2 Age 0.122544
0 Pclass 0.091813
7 FamilySize 0.051470
11 FareGroup 0.043369
3 SibSp 0.030373
6 Embarked 0.026624
10 AgeGroup 0.023146
5. Save the model files¶
In [6]:
metadata = tm.save_model_artifacts(model, label_encoders, feature_names, accuracy)
print(f"Final model accuracy: {accuracy:.4f}")
Saving model artifacts... Model saved to: models/titanic_model.joblib Label encoders saved to: models/label_encoders.joblib Model metadata saved to: models/model_metadata.json Sample input saved to: models/sample_input.json All model artifacts saved successfully! Final model accuracy: 0.8156