MC³ LabCUHK Psychology

Lesson 6 · Working with data

Change data

Make new columns, recode values and deal with missing data.

In this lesson

  • Add columns with mutate()
  • Recode with if_else() and case_when()
  • Handle missing values

You need

Datastudents.csvStudent Life Survey: 300 students, with their study habits, sleep, stress, wellbeing and exam results.
Scriptlesson-06.RAll the code in this lesson, ready to run.

Set up

R code
library(tidyverse)
students <- read_csv("data/students.csv", show_col_types = FALSE)

mutate(): add a column

IDWellbeing_T1Wellbeing_T2Change
S0015.005.000.00
S0021.331.330.00
S0033.334.331.00
mutate(Change = Wellbeing_T2 - Wellbeing_T1)

The new column is calculated from other columns, for every row.

R code
students %>%
  mutate(Change = Wellbeing_T2 - Wellbeing_T1) %>%
  select(ID, Wellbeing_T1, Wellbeing_T2, Change) %>%
  head(3)
Output
# A tibble: 3 × 4
  ID    Wellbeing_T1 Wellbeing_T2 Change
  <chr>        <dbl>        <dbl>  <dbl>
1 S001          5            5         0
2 S002          1.33         1.33      0
3 S003          3.33         4.33      1

Wellbeing_T1 and _T2 are wellbeing scores (1 to 7) at the start and end of semester.

Keep your changes

The code above only prints a result. To keep a new column, save it back with <-:

R code
students <- students %>%
  mutate(Change = Wellbeing_T2 - Wellbeing_T1)

if_else(): two groups

R code
students <- students %>%
  mutate(Age_Group = if_else(Age >= 21, "21 and over", "Under 21"))

students %>% count(Age_Group)
Output
# A tibble: 2 × 2
  Age_Group       n
  <chr>       <int>
1 21 and over   159
2 Under 21      141

if_else(question, value if yes, value if no). count() counts each value.

case_when(): recode

LearningStyle is stored as codes. Turn them into words:

0123
case_when()→
VisualKinaestheticAuditoryReading/Writing
R code
students <- students %>%
  mutate(LearningStyle = case_when(
    LearningStyle == 0 ~ "Visual",
    LearningStyle == 1 ~ "Kinaesthetic",
    LearningStyle == 2 ~ "Auditory",
    LearningStyle == 3 ~ "Reading/Writing"
  ))

students %>% count(LearningStyle)
Output
# A tibble: 4 × 2
  LearningStyle       n
  <chr>           <int>
1 Auditory           48
2 Kinaesthetic       61
3 Reading/Writing    80
4 Visual            111

Each line is question ~ new value. It also works with ranges; .default catches everything else:

R code
students %>%
  mutate(Exam_Band = case_when(
    ExamScore >= 70 ~ "High",
    ExamScore >= 50 ~ "Middle",
    .default = "Low"
  )) %>%
  count(Exam_Band)
Output
# A tibble: 3 × 2
  Exam_Band     n
  <chr>     <int>
1 High        135
2 Low          27
3 Middle      138

Missing values

R code
sum(is.na(students$Sleep))
students %>% filter(is.na(Sleep)) %>% select(ID, Sleep)
students %>% drop_na(Sleep) %>% nrow()
Output
[1] 10
# A tibble: 10 × 2
   ID    Sleep
   <chr> <dbl>
 1 S003     NA
 2 S051     NA
 3 S054     NA
 4 S136     NA
 5 S173     NA
 6 S178     NA
 7 S205     NA
 8 S250     NA
 9 S285     NA
10 S298     NA
[1] 290
  • is.na() finds missing values.
  • drop_na(Sleep) removes rows where Sleep is missing.
  • Usually it is enough to add na.rm = TRUE when you summarise (next lesson).

Exercises

Exercise 6.1 Dataset: students.csv

Two groups

Add a column Short_Sleep: "Yes" if a student sleeps less than 6 hours, otherwise "No". Save it and count each group. What happens to students with no sleep answer?

Show answerHide answer
R code
students <- students %>%
  mutate(Short_Sleep = if_else(Sleep < 6, "Yes", "No"))
students %>% count(Short_Sleep)
Output
# A tibble: 3 × 2
  Short_Sleep     n
  <chr>       <int>
1 No            214
2 Yes            76
3 <NA>           10

Students with a missing Sleep get NA, which is right: we don't know.

Exercise 6.2 Dataset: students.csv

Recode stress

Make Stress_Level: "Low" for stress 1 to 3, "Medium" for 4 to 7, "High" for 8 to 10. Count each level.

Show hintHide hint

Start with the highest: Stress >= 8 ~ "High", then Stress >= 4 ~ "Medium", then .default = "Low".

Show answerHide answer
R code
students <- students %>%
  mutate(Stress_Level = case_when(
    Stress >= 8 ~ "High",
    Stress >= 4 ~ "Medium",
    .default = "Low"
  ))
students %>% count(Stress_Level)
Output
# A tibble: 3 × 2
  Stress_Level     n
  <chr>        <int>
1 High            62
2 Low             30
3 Medium         208

Key points

  • mutate() adds or changes columns. Save with students <- students %>% ...
  • if_else() for two outcomes, case_when() for more.
  • is.na() finds missing values; drop_na() removes them.