In the print dialog, choose "Save as PDF" as the destination.
Machine Learning, Week 4
Predict whether a Titanic passenger survives, and how sure the model is.
z, a probability p and a classLogisticRegression and read accuracy, the confusion matrix, precision, recall and F1Week 4 of the plan
| Part | What we do | Time |
|---|---|---|
| 1 | The idea, and a passenger by hand | 25 min |
| 2 | Notebook 1: prepare, train, score | 25 min |
| 3 | Evaluating: matrix, precision, recall, threshold | 20 min |
| 4 | Notebook 2: explore, fill in, tune; your project | 20 min |
| 5 | Takeaways, then practice with answers | 30 min |
Part 1
A score, a squash, a decision
0 or 1, and yields the probability of class 1 as well.zz into a probability p between 0 and 1p with a threshold; predict uses 0.5| Term | In the Titanic data |
|---|---|
Features x | input columns: age, sex, passenger class |
Target y | Survived: 1 survived, 0 perished |
| Positive class | class 1, whose probability the model reports |
Probability p | the model's estimate that y = 1 |
Threshold t | the cut on p: p ≥ t gives 1, else 0 |
x_1 to x_n are the n features of one passengerw_1 to w_n are the learned weights, in model.coef_b is the bias, in model.intercept_e is the constant 2.71828z, the value σ(z) lies between 0 and 1: a probabilityσ(0) = 0.5: a score of zero means no preferencez gives p near 1; large negative z gives p near 0ŷ is the predicted class and t the thresholdpredict uses t = 0.5, and σ(0) = 0.5, so that is the same as asking whether z ≥ 0predict and predict_proba ≥ 0.5 agree on all 143 test passengersBy hand
LogisticRegression(random_state=0) on six features, weights rounded to 3 decimals
| Feature | Weight |
|---|---|
bias b | 1.212 |
Age | -0.039 |
Sex_female | 1.149 |
Sex_male | -1.150 |
| Feature | Weight |
|---|---|
Pclass_1 | 1.200 |
Pclass_2 | 0.007 |
Pclass_3 | -1.207 |
A 30-year-old female traveling in first class
female = [[30, 1, 0, 1, 0, 0]]male = [[60, 0, 1, 0, 0, 1]]
Part 2
Four columns, one model, real probabilities
https://colab.research.google.com/github/
jeffprosise/Machine-Learning/blob/master/
Titanic%20(Logistic%20Regression).ipynbimport pandas as pd
url = ("https://raw.githubusercontent.com/"
"jeffprosise/Machine-Learning/master/Data/titanic.csv")
df = pd.read_csv(url) # 891 rows, 12 columnsdf = df[['Survived', 'Age', 'Sex', 'Pclass']]
df = pd.get_dummies(df, columns=['Sex', 'Pclass'])
df.dropna(inplace=True) # 714 rows remainSurvived and three features: Age, Sex, Pclassget_dummies one-hot encodes: one new 0/1 column per value, because a model needs numbersdropna removes the 177 rows with no age: 714 remain, 424 perished and 290 survived| Sex | Sex_female | Sex_male |
|---|---|---|
| male (row 0) | 0 | 1 |
| female (row 1) | 1 | 0 |
| Pclass | Pclass_1 | Pclass_2 | Pclass_3 |
|---|---|---|---|
| 3 (row 0) | 0 | 0 | 1 |
| 1 (row 1) | 1 | 0 | 0 |
x = df.drop('Survived', axis=1)
y = df['Survived']
x_train, x_test, y_train, y_test = train_test_split(
x, y, test_size=0.2, stratify=y, random_state=0)
model = LogisticRegression(random_state=0)
model.fit(x_train, y_train)
model.score(x_test, y_test) # 0.8322stratify=y keeps the survivor share at 0.406 in bothPart 3
Which mistakes, and how many

from sklearn.metrics import ConfusionMatrixDisplay
ConfusionMatrixDisplay.from_estimator(
model, x_test, y_test,
display_labels=['Perished', 'Survived'],
cmap='Blues')A: accuracy, N: all test passengers, TN and TP: the correct cells
| Predicted 0 | Predicted 1 | |
|---|---|---|
| Actual 0 | 78 (TN) | 7 (FP) |
| Actual 1 | 17 (FN) | 41 (TP) |
| Predicted 0 | Predicted 1 | |
|---|---|---|
| Actual 0 | 78 (TN) | 7 (FP) |
| Actual 1 | 17 (FN) | 41 (TP) |
| Predicted 0 | Predicted 1 | |
|---|---|---|
| Actual 0 | 78 (TN) | 7 (FP) |
| Actual 1 | 17 (FN) | 41 (TP) |
P = 0.854 and R = 0.707 from the last two slides precision recall f1-score support
0 0.82 0.92 0.87 85
1 0.85 0.71 0.77 58
accuracy 0.83 143
macro avg 0.84 0.81 0.82 143
weighted avg 0.83 0.83 0.83 1431 holds our three values, rounded to two decimals0 treats perished as positive: precision 78/95 = 0.821, recall 78/85 = 0.918support counts the test passengers of each class; notebook 2 reads the weighted avg F1
from sklearn.metrics import RocCurveDisplay
RocCurveDisplay.from_estimator(
model, x_test, y_test)| Threshold | TN, FP, FN, TP | Precision | Recall |
|---|---|---|---|
| 0.3 | 68, 17, 7, 51 | 0.750 | 0.879 |
| 0.5 | 78, 7, 17, 41 | 0.854 | 0.707 |
| 0.7 | 83, 2, 30, 28 | 0.933 | 0.483 |
Part 4
The same 891 passengers, cleaned more carefully
https://colab.research.google.com/github/
tirthajyoti/Machine-Learning-with-Python/blob/master/
Classification/Logistic_Regression_Classification.ipynburl = ("https://raw.githubusercontent.com/tirthajyoti/"
"Machine-Learning-with-Python/master/Datasets/titanic_train.csv")
train = pd.read_csv(url) # the same 891 rows

a = list(train.groupby('Pclass')['Age'].mean())
def impute_age(cols):
Age = cols['Age']
Pclass = cols['Pclass']
if pd.isnull(Age):
if Pclass == 1:
return a[0]
elif Pclass == 2:
return a[1]
else:
return a[2]
else:
return Age
train['Age'] = train[['Age', 'Pclass']].apply(impute_age, axis=1)| Pclass | Mean age | Missing ages filled |
|---|---|---|
| 1 | 38.23 | 30 |
| 2 | 29.88 | 11 |
| 3 | 25.14 | 136 |
train.drop('Cabin', axis=1, inplace=True)
train.dropna(inplace=True) # 889 rows
train.drop(['PassengerId', 'Name', 'Ticket'], axis=1, inplace=True)
sex = pd.get_dummies(train['Sex'], drop_first=True)
embark = pd.get_dummies(train['Embarked'], drop_first=True)
train.drop(['Sex', 'Embarked'], axis=1, inplace=True)
train = pd.concat([train, sex, embark], axis=1)Cabin is missing in 687 rows: drop the columndrop_first=True: Sex keeps only male; Embarked keeps Q and S, and port C is Q = 0, S = 0Survived and 8 featuresA few hundredths between two models can come from the split alone


C is a strong penalty on the weights; at 1/C = 1000, F1 drops to 0.63pandas 3.0.6 and scikit-learn 1.9.1
| In the notebook | What happens now | Fix |
|---|---|---|
cols[0] | KeyError: 0 | cols['Age'] |
n_jobs=4 | FutureWarning: no effect | remove it |
max_iter=100 | ConvergenceWarning in 183 of 200 fits | max_iter=1000 |
l[len(l)-2] | F1 is text: the axis is scrambled | float(...) |
Before you practise
Sex to the model without encoding itPassengerId or Name as featurespredict_proba returns two columns: [:, 1] is class 1Your team project
Survived, or a number, like a pricedf.info(): drop the column, drop the rows, or imputepd.get_dummiesz, the sigmoid, then a thresholdσ(0) = 0.5, so at threshold 0.5 the class is 1 exactly when z ≥ 0Part 5
About 30 minutes, answers follow each task
About 10 minutes
b = 1.212, Age -0.039, Sex_female 1.149, Sex_male -1.150, Pclass_1 1.200, Pclass_2 0.007, Pclass_3 -1.207z, p and the class at threshold 0.5Answers
| Passenger | Vector x | Score z | p and class |
|---|---|---|---|
| boy, 8, class 2 | [8, 0, 1, 0, 1, 0] | 1.212 - 0.312 - 1.150 + 0.007 = -0.243 | 1 / (1 + 1.2751) = 0.440, class 0 |
| man, 30, class 1 | [30, 0, 1, 1, 0, 0] | 1.212 - 1.170 - 1.150 + 1.200 = 0.092 | 1 / (1 + 0.9121) = 0.523, class 1 |
About 5 minutes
| Predicted 0 | Predicted 1 | |
|---|---|---|
| Actual 0 | 68 | 17 |
| Actual 1 | 7 | 51 |
Answers
About 5 minutes
| Passenger | Pclass | Age | Embarked |
|---|---|---|---|
| A | 1 | 40 | C |
| B | 1 | missing | S |
| C | 1 | 50 | S |
| D | 2 | 30 | S |
| Passenger | Pclass | Age | Embarked |
|---|---|---|---|
| E | 2 | missing | Q |
| F | 3 | 20 | S |
| G | 3 | missing | S |
| H | 3 | 28 | Q |
About 10 minutes
model.score, reading the data by URL[[8, 0, 1, 0, 1, 0]]1 went up?| Question | Answer |
|---|---|
| Probability for the boy | 43.9%, class 0 |
| Matrix at 0.4 | [[75, 10], [10, 48]] |
Recall of class 1 | up, 0.71 to 0.83 |
Precision of class 1 | down, 0.85 to 0.83 |
Mahmoud Abas|Logistic Regression