Titanic Survival Prediction
Download public Titanic CSV files, clean missing values, encode categorical features, train a classifier, and produce a submission-style CSV.
Final deliverable: A full Titanic classification notebook with validation metrics and submission.csv.
Dataset: Titanic public CSV mirror
The notebook downloads public Titanic CSV mirrors directly. The target is Survived in train.csv.
- Survived: target label, 1 means survived
- Pclass, Sex, Age, SibSp, Parch, Fare, Embarked: modeling features
- Name, Ticket, Cabin: high-cardinality/text fields learners may engineer later
- PassengerId: required for submission
Download Titanic Data
Download public train.csv and test.csv files.
Run the public download cell and confirm train.csv and test.csv exist.
# Run this cell in Colab, Kaggle, or a local notebook.
# It downloads public dataset files directly, so you do not need Kaggle credentials.
from pathlib import Path
from urllib.request import urlretrieve
import zipfile
DATA_DIR = Path("data/titanic")
DATA_DIR.mkdir(parents=True, exist_ok=True)
def find_file(name):
possible_roots = [DATA_DIR, Path("/kaggle/input")]
for root in possible_roots:
if root.exists():
matches = list(root.rglob(name))
if matches:
return matches[0]
raise FileNotFoundError(f"Could not find {name}. Run the dataset download cell first.")
files = {
"train.csv": "https://raw.githubusercontent.com/agconti/kaggle-titanic/master/data/train.csv",
"test.csv": "https://raw.githubusercontent.com/agconti/kaggle-titanic/master/data/test.csv"
}
for filename, url in files.items():
target = DATA_DIR / filename
if target.exists() and target.stat().st_size > 0:
print(f"already exists: {target}")
continue
print(f"downloading {filename} ...")
urlretrieve(url, target)
print(f"saved: {target}")
for zip_path in DATA_DIR.glob("*.zip"):
extract_dir = DATA_DIR / zip_path.stem
extract_dir.mkdir(exist_ok=True)
if any(extract_dir.iterdir()):
print(f"already extracted: {extract_dir}")
continue
with zipfile.ZipFile(zip_path, "r") as zf:
zf.extractall(extract_dir)
print(f"extracted: {zip_path} -> {extract_dir}")
print("Files:")
all_files = [path for path in sorted(DATA_DIR.rglob("*")) if path.is_file()]
for path in all_files[:40]:
print(path)
if len(all_files) > 40:
print(f"... {len(all_files) - 40} more files not shown")Show reference solution
# Run this cell in Colab, Kaggle, or a local notebook.
# It downloads public dataset files directly, so you do not need Kaggle credentials.
from pathlib import Path
from urllib.request import urlretrieve
import zipfile
DATA_DIR = Path("data/titanic")
DATA_DIR.mkdir(parents=True, exist_ok=True)
def find_file(name):
possible_roots = [DATA_DIR, Path("/kaggle/input")]
for root in possible_roots:
if root.exists():
matches = list(root.rglob(name))
if matches:
return matches[0]
raise FileNotFoundError(f"Could not find {name}. Run the dataset download cell first.")
files = {
"train.csv": "https://raw.githubusercontent.com/agconti/kaggle-titanic/master/data/train.csv",
"test.csv": "https://raw.githubusercontent.com/agconti/kaggle-titanic/master/data/test.csv"
}
for filename, url in files.items():
target = DATA_DIR / filename
if target.exists() and target.stat().st_size > 0:
print(f"already exists: {target}")
continue
print(f"downloading {filename} ...")
urlretrieve(url, target)
print(f"saved: {target}")
for zip_path in DATA_DIR.glob("*.zip"):
extract_dir = DATA_DIR / zip_path.stem
extract_dir.mkdir(exist_ok=True)
if any(extract_dir.iterdir()):
print(f"already extracted: {extract_dir}")
continue
with zipfile.ZipFile(zip_path, "r") as zf:
zf.extractall(extract_dir)
print(f"extracted: {zip_path} -> {extract_dir}")
print("Files:")
all_files = [path for path in sorted(DATA_DIR.rglob("*")) if path.is_file()]
for path in all_files[:40]:
print(path)
if len(all_files) > 40:
print(f"... {len(all_files) - 40} more files not shown")A project notebook should own its data setup so learners can reproduce the workflow.
Load and Inspect Titanic Data
Read train.csv and inspect missing values and target balance.
Load train.csv, print shape, missing counts, and survival rate.
from pathlib import Path
import pandas as pd
possible_roots = [
Path("data/titanic"),
Path("/kaggle/input"),
]
def find_file(name):
for root in possible_roots:
if root.exists():
matches = list(root.rglob(name))
if matches:
return matches[0]
raise FileNotFoundError(f"Could not find {name}. Run the dataset download/load cell first.")
train_path = find_file("train.csv")
df = pd.read_csv(train_path)
print(train_path)
print(df.shape)
df.head()
# Inspect missing values
# Inspect survival rateShow reference solution
from pathlib import Path
import pandas as pd
possible_roots = [
Path("data/titanic"),
Path("/kaggle/input"),
]
def find_file(name):
for root in possible_roots:
if root.exists():
matches = list(root.rglob(name))
if matches:
return matches[0]
raise FileNotFoundError(f"Could not find {name}. Run the dataset download/load cell first.")
train_path = find_file("train.csv")
df = pd.read_csv(train_path)
print(train_path)
print(df.shape)
df.head()
display(df.isna().sum().sort_values(ascending=False))
print("survival rate:", round(df["Survived"].mean(), 3))Titanic is a cleaning project as much as a modeling project. Missing Age and Cabin values influence feature choices.
Choose Features and Preprocessing
Build a clean feature matrix with numeric and categorical preprocessing.
Choose simple starting features and create a ColumnTransformer for imputation and one-hot encoding.
from sklearn.compose import ColumnTransformer from sklearn.impute import SimpleImputer from sklearn.pipeline import Pipeline from sklearn.preprocessing import OneHotEncoder # Define feature columns # Build preprocessing transformer
Show reference solution
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
numeric_features = ["Pclass", "Age", "SibSp", "Parch", "Fare"]
categorical_features = ["Sex", "Embarked"]
features = numeric_features + categorical_features
numeric_pipeline = Pipeline([
("imputer", SimpleImputer(strategy="median")),
])
categorical_pipeline = Pipeline([
("imputer", SimpleImputer(strategy="most_frequent")),
("onehot", OneHotEncoder(handle_unknown="ignore")),
])
preprocess = ColumnTransformer([
("num", numeric_pipeline, numeric_features),
("cat", categorical_pipeline, categorical_features),
])Pipelines keep train/test preprocessing consistent. This prevents common leakage and submission-time column mismatch bugs.
Train and Validate a Classifier
Fit a baseline model and evaluate accuracy on a validation split.
Train LogisticRegression inside a Pipeline and calculate validation accuracy.
from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score, classification_report from sklearn.model_selection import train_test_split # Split train/validation # Build model pipeline # Fit and evaluate
Show reference solution
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report
from sklearn.model_selection import train_test_split
X = df[features]
y = df["Survived"]
X_train, X_val, y_train, y_val = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
model = Pipeline([
("preprocess", preprocess),
("clf", LogisticRegression(max_iter=1000)),
])
model.fit(X_train, y_train)
val_preds = model.predict(X_val)
print("accuracy:", accuracy_score(y_val, val_preds))
print(classification_report(y_val, val_preds))A validation split gives feedback before submitting to Kaggle. The class report shows whether the model ignores one class.
Add Simple Feature Engineering
Create family-size and alone features that are common in Titanic notebooks.
Add FamilySize and IsAlone, then retrain with those features.
# Create FamilySize and IsAlone in train data # Update feature lists # Retrain model
Show reference solution
df["FamilySize"] = df["SibSp"] + df["Parch"] + 1
df["IsAlone"] = (df["FamilySize"] == 1).astype(int)
numeric_features = ["Pclass", "Age", "SibSp", "Parch", "Fare", "FamilySize", "IsAlone"]
categorical_features = ["Sex", "Embarked"]
features = numeric_features + categorical_features
preprocess = ColumnTransformer([
("num", numeric_pipeline, numeric_features),
("cat", categorical_pipeline, categorical_features),
])
X = df[features]
X_train, X_val, y_train, y_val = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
model = Pipeline([
("preprocess", preprocess),
("clf", LogisticRegression(max_iter=1000)),
])
model.fit(X_train, y_train)
val_preds = model.predict(X_val)
print("accuracy:", accuracy_score(y_val, val_preds))Feature engineering should be motivated by domain logic: family size may affect survival because evacuation happened in groups.
Create Submission-Style CSV
Apply identical preprocessing to test.csv and save PassengerId/Survived predictions.
Load test.csv, create the same engineered features, predict, and save submission.csv.
# Load test.csv # Create the same engineered features # Predict and save submission.csv
Show reference solution
test_df = pd.read_csv(find_file("test.csv"))
test_df["FamilySize"] = test_df["SibSp"] + test_df["Parch"] + 1
test_df["IsAlone"] = (test_df["FamilySize"] == 1).astype(int)
test_preds = model.predict(test_df[features])
submission = pd.DataFrame({
"PassengerId": test_df["PassengerId"],
"Survived": test_preds,
})
submission.to_csv("submission.csv", index=False)
display(submission.head())Submission code tests whether the whole workflow is reproducible on unseen rows.