Data Cleaning

A shipwreck

../_images/titanic.png

Andromé, the navigator, and her captain Aarla are on the submarine bridge during the night watch.

"Captain, the sonar shows a shipwreck ahead of us!"

"That must be the Titanic, a ship of the Furless. It was one of their big tragedies. They were quite surprised to learn that icebergs are actually dangerous. On top of it, most of them were not used to swimming in cold water. No wonder their civilization disappeared."

"I wonder who they were. The poor people on the ship, I mean."

"We should have some records in our computer. The data is a bit raggy, this could be good practice. We haven't got much work in the next two days. Why don't you grab Min Min and see whether you can clean up the data."


Load the Data

You can load the Titanic dataset with seaborn:

import polars as pl
import seaborn as sns

df = pl.from_pandas(sns.load_dataset("titanic"))

Inspect

Inspect the columns of the DataFrame and see what data is in there. Make sure to check the following:

  • check the unique values in the categorical columns

  • check how frequent values are, e.g. the passenger classes

  • count the null values in all columns

Replace values

Use the commands from the Data Wrangling chapter to replace the 'alive' column by integer values 0 and 1. Use the following expression:

df = df.with_columns(df[...].replace({"male": 0, ...}).alias("new_name"))

Do the same for the 'sex' column.

Integer encoding

Let's also encode a categorical column with multiple values by integers. Compare the following two approaches.

First convert the colunmn to a categorical type:

cat = df["who"].cast(pl.Categorical)

Then create the first representation:

cat.to_physical()

and

cat.to_dummies()

Which one would you prefer and why?

Fill missing category

Fill the missing values in the 'deck' by the constant 'unknown'.

df["deck"].fill_null(...)

Fill by median

Fill the missing age values by the median age:

median = df["age"].median()  # ignores missing entries

...

Fill by grouped medians

If you inspect the histogram of the new age column, you should recognize a problem:

sns.histplot(df["age_filled"])

Let's try something more sophisticated: use the median age of the respective passenger class:

pclass_ages = df.group_by("pclass").agg(pl.col("age").median())

Create a replacement dictionary:

pclass_dict = pg.to_dicts()
rep_dict = {x["pclass"]: x["age"] for x in pclass_dict}

Now roll out the median ages along the entire colunm and fill the missing values:

rep = df["pclass"].replace(rep_dict)
df["age"].fill_null(rep)

The histogram should look nicer now.

Hint

An even more sophisticated approach would be to use Machine Learning. Sometimes, k-Nearest-Neighbors is a good method for filling missing values.

Advanced challenges

Here is a couple of things you might try if you are already familiar with plotting:

Create a bar plot indicating the number of first, second and third class passengers

  • plot a histogram of the age column with 20 bins

  • create a boxplot of the age column

  • create a scatterplot of fare over age

  • create a bar plot that shows the survived vs. dead passengers with one bar group for each gender

  • create a heatmap from the correlation matrix of all columns

See also

For many years, the Titanic Dataset Challenge was a kind of entry challenge for machine learning.

More recently, the data has been resampled, removing the references to natural persons. The result is known as the Spaceship Titanic Challenge