DSCI 100 Week 3 : Cleaning and Wrangling Data

Sky (Kehan) Sheng

Lecture 3 Slides

www.skysheng.io/dsci_100_sky_slides/slides/slides_03.html#/title-slide

🏠 Housekeeping

  • Do not remove, delete or rename your files on Jupyter Server.
  • iClicker attendence do not count towards your grade. Answering questions gets you 50% of the points, and answering it correctly gets you the other 50%.
  • My OH is Thursday, 4-5pm, in my office: ICCS room 187

🏠 Housekeeping: Debugging Guide on Piazza

Check out Julia’s how to debug guide on Piazza. Most errors are quick to fix once you know what to look for.

Week 2 Recap: Reading in data

Recap: Tabs look like spaces

Recap: The backslash is a secret code

  • Backlash is escape character, or escape sequence introducer.
  • Inside quotes, \ tells R: the next character is special, don’t read it normally.
  • \t a tab
  • \n a new line
  • \\ a real backslash
  • print() will “ignore” escape characters like \n and print out escape characters as strings
  • cat() will honor the rules of escape characters and turn \t into a tab, \n into a new line, etc.

iClicker: Why read from a database?

  • (Optional note, will not be tested during exams):
    • RAM = Random Access Memory.
    • Short-term memory: It stores data your computer needs right now to run open apps and files.

🔬 Demo: . and .. in relative paths

home/
└── skysheng/
    ├── images/
    └── story_of_otter/ ⬅️ cwd
        ├── clown_dungeon/
        │   └── ollie.txt
        ├── home_of_ollie/
        └── ocean/
  • . means here, the folder I am in
  • .. means one folder up
  • ../images go up to skysheng/, then into images/
  • ../.. go up twice, to home/
  • Optional terminal commands (you will not be tested on them, for now!):
    • ls list files and folders in the current folder
    • pwd print the current working directory (where am I?)
    • cd change directory (go to a different folder)
    • cat print the contents of a file (print the text of a file)
  • Additional resources about command line (you will not be tested on this!): Otter Rescue for Command Line Warriors

iClicker: Someone hands you a data file

🔄 Where are we in the workflow?

Week 2 was import. Today is tidy and transform.

🐄 Real data from the UBC Dairy Farm

Two screenshots from the same file. What problems do you spot?

  • The header row and the ===== line repeat in the middle of the file, every time a new day starts.
  • The columns change partway through: the right screenshot has two new columns, PEN and PPEN.
  • no description of the columns, no metadata
  • this is written in a weried file format, not csv, tsv or anything you learnt!
  • the file name is not informative at all!

🐄 My first real R script: 5000 lines

🔥 Roast my repo: Sky’s first R script for data cleaning

  • ❌ slow, repetitive code
  • ❌ only worked for this one dataset
  • ✅ you will learn tidyverse: the same cleaning skills work on any dataset

Rewritten with tidyverse as an R package: moo4feed

Today’s dataset: the penguins!

344 penguins from 3 islands

Dr. Kristen Gorman and the Palmer Station team measured 344 penguins of three species on three islands in Antarctica.

🐧 Let’s meet the data

  • 🤔 What is the difference between Character and Factor?

🗑️ But data rarely arrives this way

Somebody hands you “the data”.

  • inconsistent formats: commas, tabs, semicolons, blank lines
  • inconcsistent number of columns and column names across files
  • spelling mistakes, “Febuurrrary”, “Feb”, “Febarary”, “Feburary” … 🤯
  • missing values written as NA, -999, n/a, or nothing at all

Reading it in successfully does not mean it is ready to analyze.

🧹 What makes data tidy?

🧹 What is Tidy Data?

📋 Tidy data example

student major year
Ama CPSC 2
Bo STAT 1
Cai BIOL 3

One row per student. One column per thing about them. One value per box.

Is this data tidy?

Goal: compare tuberculosis rates, taking population into account.

country year rate
Afghanistan 1999 745/19987071
Afghanistan 2000 2666/20595360
Brazil 1999 37737/172006362
Brazil 2000 80488/174504898
China 1999 212258/1272915272
China 2000 213766/1280428583
  • (A) True, this is tidy
  • (B) False, this is not tidy

Answer: B, false. The rate box holds two values, cases and population, glued together with a slash. R sees text, not two numbers. You cannot take a mean of it, plot it, or filter on it.

Follow up: what would you do about it? Split it into a cases column and a population column.

Is this one tidy?

country cases (1999) cases (2000) population (1999) population (2000)
Afghanistan 745 2666 19987071 20595360
Brazil 37737 80488 172006362 174504898
China 212258 213766 1272915272 1280428583
  • (A) True, this is tidy
  • (B) False, this is not tidy
  • Answer: B, false. year is a variable, and it has been smeared across four column names instead of living in a column of its own.
  • Don’t store data in your column name!

This shape has a name: wide. pivot_longer() is what turns it back into tidy. That is the worksheet’s job this week.

Is this data tidy?

country 1999 2000
Afghanistan 745 2666
Brazil 37737 80488
China 212258 213766
  • (A) True, this is tidy
  • (B) False, this is not tidy

Answer: B, false. Same problem as the last one. year is a variable, and it is smeared across the column names 1999 and 2000 instead of living in a column of its own.

Column name also needs to be informative!

Is this one tidy?

country year key value
Afghanistan 1999 cases 745
Afghanistan 1999 population 19987071
Afghanistan 2000 cases 2666
Afghanistan 2000 population 20595360
Brazil 1999 cases 37737
Brazil 1999 population 172006362
Brazil 2000 cases 80488
Brazil 2000 population 174504898
China 1999 cases 212258
China 1999 population 1272915272
China 2000 cases 213766
China 2000 population 1280428583
  • (A) True, this is tidy
  • (B) False, this is not tidy

Answer: B, false. Each observation, one country in one year, is split across two rows here: one for cases and one for population. A tidy table needs one row per observation, so cases and population should each get their own column.

✅ This one is tidy

country year cases population
Afghanistan 1999 745 19987071
Afghanistan 2000 2666 20595360
Brazil 1999 37737 172006362
Brazil 2000 80488 174504898
China 1999 212258 1272915272
China 2000 213766 1280428583

🧰 Your data wrangling toolbox

All of this lives inside tidyverse, the one package you already load every time:

  • dplyr reshapes the rows and columns: select, filter, mutate, group_by, summarize
  • tidyr changes the shape itself: pivot_longer, pivot_wider
  • purrr repeats a job across many columns: map_dfr
  • Remember week 2: a package is the box of tools, a function is one tool, an argument is what you feed to functions to customize the tool to do work for you!
  • Tidyverse is a collection of packages including dplyr, tidyr, and purrr.

🔎 select(): choose columns

🔎 select() one column

select() keeps a subset of the columns (variables) and drops the rest.

🔎 select() many columns

🔎 select() and keep the result

🔎 select() everything except some columns

🔎 (Bonus Slide) select() by a pattern in the name

  • Helpers that select by name pattern: starts_with(), ends_with(), contains(), matches(), num_range().

  • Note the quotation marks here. "bill_" is a piece of text to match, not a column name, so it does need quotes.

🎯 filter(): choose rows

🎯 filter() with one condition

filter() keeps a subset of the rows (observations) and drops the rest.

Goal: keep only penguins with flippers longer than 190 mm.

  • How about “keep only penguins with flippers equal to 190 mm”?
  • What is the difference between == and =?

🎯 filter() with two conditions

Goal: Chinstrap penguins and flippers longer than 190 mm.

  • “A and B” : A & B
  • “A or B” : A | B
  • “not A” : !A
  • “A is equal to B” : A == B
  • “A is not equal to B” : A != B
  • “A is greater than B” : A > B
  • “A is less than B” : A < B
  • “A is greater than or equal to B” : A >= B
  • “A is less than or equal to B” : A <= B

🎯 filter() and keep the result

➕ mutate(): add a column

➕ mutate()

mutate() builds a new column out of the columns you already have.

Goal: body mass in pounds instead of grams, saved as penguins_lbs. 454 g is 1 lb.

Three ways to chain steps together

You often need several data cleaning steps in a row. Three ways to write it:

  1. Save an intermediate object after each step
  2. Nest the functions inside each other
  3. Use the pipe |>

1️⃣ Save intermediate objects

  • A reader has to hunt for where penguins_1 and penguins_2 get used
  • The names suggest those objects matter. They don’t
  • Three copies of a big data set now sit in memory (waste of memory)

2️⃣ Nest the functions

  • You have to start reading from the middle of the code
  • Hard to read! 🤯

3️⃣ Pipe it with |>

The pipe takes whatever is on its left and hands it to the first argument of the function on its right.

  • Reads top to bottom, in the order it happens
  • No intermediate names to invent or remember
  • The data set is not repeated inside each call
  • %>% is also a pipe operator, but was used in the previous versions of R.

🍳 The pipe is a kitchen line

veggies → cut it up → keep the big pieces → fry everything in a pan

Each station does one job and slides the bowl to the next.

💪 Try it yourself

Using the avocado sales data, write a pipeline that:

  1. adds a column total_volume (the sum of small_hass_volume, large_hass_volume and extra_l_hass_volume)
  2. keeps only organic avocados
  3. keeps only the Date, average_price and total_volume columns

📊 group_by() + summarize()

Grouping and Summarizing

Grouping splits the rows into piles based on the value in a column.

Summarizing combines data from each pile into a few summary values.

How heavy is each species on average?

📊 Watch 344 penguins become 3 numbers

🔁 Iteration: The same job, over and over

You want the average of four columns. You could write this:

  • Four chances to create a typo writing typing out column names. Now imagine if you have 40 columns…
  • Iteration is when you need to do something repeatedly (e.g., ringing in and bagging groceries at the till)
  • In data science, it’s doing the same thing over and over again
    • Important to reduce duplication of code
    • easier to see the intent of your code
    • likely have fewer bugs

🔁 map_dfr() does it once

map_dfr() is a function that iterates over columns. For example, below we are calculating the mean of each column in the penguins data frame.

  • bill_length_mm:body_mass_g means “these two columns and everything between them”
  • map_dfr() applies one function to every column and returns a data frame of the results
  • ⚠️ Be careful: There are a lot of map_… functions that you could use (map, map_lgl, map_chr, etc). Usually in this course we’ll only use map_dfr, but you should investigate the others yourself!

📅 Upcoming Due Dates

  • worksheet_wrangling due SATURDAY, Sep 26, 11:59pm
  • tutorial_wrangling due SATURDAY, Sep 26, 11:59pm

There are NO late submissions for worksheets. We drop the lowest worksheet and the lowest tutorial score. See the policy for late registrants.

❓ Questions?

If not, let’s work on this week’s worksheet together.

  • Want to save these slides? Right click → Print → Save to PDF.
  • Your code and notes only save if you save as a PDF!