This section provides optional exercises for those who want to practise and solidify the concepts introduced in the practicals. The exercises focus on subsetting data frames using the penguins dataset, more advanced vector subsetting with conditionals, and control flow with if, else and ifelse().
ImportantThis is entirely optional
Some of the later exercises are quite advanced, so you may choose to skip them for now and revisit them later, after the course, to practise what you’ve learnt.
Subsetting data frames
The penguins dataset contains information about 344 penguins, including 3 different species, collected from 3 islands in the Palmer Archipelago, Antarctica.
Load the penguins dataset by typing data(penguins) and inspect the first few rows.
NoteSolution
data(penguins)head(penguins)
species island bill_len bill_dep flipper_len body_mass sex year
1 Adelie Torgersen 39.1 18.7 181 3750 male 2007
2 Adelie Torgersen 39.5 17.4 186 3800 female 2007
3 Adelie Torgersen 40.3 18.0 195 3250 female 2007
4 Adelie Torgersen NA NA NA NA <NA> 2007
5 Adelie Torgersen 36.7 19.3 193 3450 female 2007
6 Adelie Torgersen 39.3 20.6 190 3650 male 2007
The penguins dataset was added to R in version 4.5.0. If you’re using an earlier version of R, you’ll need to install the palmerpenguins package to access the data:
library(palmerpenguins)head(penguins)
You can check your current R version with sessionInfo(). Note that some of the variable names are different in the package version of the dataset.
Define a character vector containing the months of the year (i.e., January, February, …, December).
NoteSolution
moy <-c("January","February","March","April","May","June","July","August","September","October","November","December")# Or use the built-in constant 'months.name'moy <- month.name# NOTE: I'm using 'moy' as short for 'Months of the year', but you can use any# label you like.
Select the third element of this vector.
NoteSolution
moy[3]
[1] "March"
Select the 6th, 7th, and 8th elements of this vector.
# The above answer will work, but it assumes that# there are always 12 elements in the vector. This# is true for this example, but it's good practice# write code that can handle various input lengths.tail(moy, 5)
Select all months ending in “er” (Hint: str_ends).
TipUse the str_ends function
str_ends is a function that returns a logical value (TRUE or FALSE) indicating whether a string ends with a specified pattern.
To use the function, you’ll first need to load the tidyverse library:
library(tidyverse)
NoteSolution
moy[str_ends(moy, "er")]
[1] "September" "October" "November" "December"
Select all months starting with “A” (Hint: str_starts).
NoteSolution
moy[str_starts(moy, "A")]
[1] "April" "August"
# As always, there are multiple ways of achieving this.# The above method is quite efficient, but you could# also try:# Using regular expressions:moy[str_detect(moy, "^A")]
[1] "April" "August"
# Using purrrkeep(moy, \(x) str_detect(x, "^A"))
[1] "April" "August"
# Or, if you really want to over-complicate it:a_months <-c()for (m in moy) {if (substring(m, 1, 1) =="A") { a_months <-c(a_months, m) }} # You shouldn't do this! But try to see what's happening here.
Control flow
Create an object x containing a single number. Write an if/else statement that prints "positive" if x is greater than zero, and "zero or negative" otherwise. Try it with a few different values of x.
NoteSolution
x <--3if (x >0) {print("positive")} else {print("zero or negative")}
[1] "zero or negative"
Extend your answer to question 1 so that it prints "positive", "negative" or "zero".
Select the body mass (body_mass) of the first penguin in the penguins dataset. Use if/else to create an object called size that is "heavy" if the penguin weighs 4,000 grams or more, and "light" otherwise.
Now try to do the same for every penguin, by replacing penguins$body_mass[1] with penguins$body_mass. What happens, and why?
NoteSolution
if (penguins$body_mass >=4000) { size <-"heavy"} else { size <-"light"}
Error in `if (penguins$body_mass >= 4000) ...`:
! the condition has length > 1
if expects a condition that is a single TRUE or FALSE. Here, the condition penguins$body_mass >= 4000 is a vector with one value per penguin, so R stops with an error.
Use ifelse() to create a new column in penguins called size, containing "heavy" or "light" for every penguin. Tabulate the new column with table().
Two penguins have a missing body mass. What value do they get in your new size column? Check using table(penguins$size, useNA = "ifany").
NoteSolution
table(penguins$size, useNA ="ifany")
heavy light <NA>
177 165 2
They are NA. When the condition is NA, ifelse() can’t decide between "heavy" and "light", so it returns NA. This is usually what you want: it keeps missing values missing.
Use ifelse() with the moy vector you created above to label each month as "summer" (June, July and August) or "not summer".
TipHint
The %in% operator checks whether each element of one vector appears in another, e.g. moy %in% c("June", "July").