PA 8: The 12 Days of Christmas

library(tidyverse)

Introduction

The song “12 Days of Christmas”, written around 1780, tells the tale of many gifts a person receives in the days leading up to Christmas.

These gifts repeat and compound; on the first day, the narrator receives

A partridge in a pear tree.

On the twelfth day, they receive

Twelve Drummers Drumming
Eleven Pipers Piping
Ten Lords a Leaping
Nine Ladies Waiting
Eight Maids a Milking
Seven Swans a Swimming
Six Geese a Laying
Five Golden Rings
Four Calling Birds
Three French Hens
Two Turtle Doves
And a Partridge in a Pear Tree

This week, your task will be to write functions that automatically sing this very repetitive song. In the practice activity, we will start by writing two helper functions which we will use later to write a function which sings the entire song.

This task is complex. It requires many different types of abilities. Everyone will be good at some of these abilities but nobody will be good at all of them. In order to produce the best product possible, you will need to use the skills of each member of your group.

Data set

Run the code provided to load in a data set called xmas that contains the crucial information about the gifts in the song. We will use this data set to test out our functions as we work on them.

xmas <- read.csv("https://github.com/earobinson95/stat331-calpoly/raw/master/practice-activities/data/xmas.csv") |> 
  janitor::clean_names()

While we’re at it, let’s make a smaller version of the xmas data set. This way we can try out our functions on the small version first before we test them on the full data set.

xmas_small <- slice_sample(xmas, n = 2)

Advice

  1. Your functions can - and should! - reference each other. That is, don’t duplicate code; use earlier, smaller functions inside your larger functions.

  2. Don’t sweat the small stuff, this activity focuses on learning about vectorized and non-vectorized functions not on getting the output to look as nice as possible.

Step 1 – Pluralizing the Gifts

The gifts in the xmas dataset are listed in singular. For example, on day five the narrator receives “five golden rings”, but the entry in the xmas data set for the gift on day five simply says "ring".

Using the skeleton of the pluralize_gift() function, fill in the ____ so that the function takes a gift and returns the appropriate plural.

Here are some tips for completing this task:

  • The gifts on days six (goose) and nine (lady) have unusual pluralization. You may assume that in other data sets, there will be no additional special cases besides these types.

  • Your should absolutely not “hard-code” anything into this function. For example, the word “goose” should not appear anywhere in the function.

# Function that takes a noun and makes it plural
# Arguments -- gift -- A string or vector of strings
# Return -- A string or vector of strings with the pluralized words

pluralize_gift <- function(gift){

  # Check if the word ends in a y
  if(____){
    # Replace the y at the end with an ies
    gift <- str_replace(____)
    } 
  # Check for a oo (goose)
  else if(____){ 
    # Replace the oo with a ee
    gift <- str_replace(____)
    } 
  else{
    # Add an s to the end of the gift
    gift <- str_c(____)
    }

  return(gift)

}

Test Your Function

Try your function out on the smaller and then larger gift data set.

## TESTING ON SMALL DATASET
map_chr(.x = xmas_small$gift_item, 
        .f = ~ pluralize_gift(gift = .x)
        )

## TESTING ON LARGE DATASET
map_chr(.x = xmas$gift_item, 
        .f = ~ pluralize_gift(gift = .x)
        )

Step 2 – Creating sentences

Next we will write a function called make_phrase() that takes as input the necessary information, and returns a phrase. For example,

make_phrase(day_num   = 4, 
            adjective = "calling",
            item      = "birds",  
            verb      = "",
            location  = "")

should return

"four calling birds"

and

make_phrase(day_num  = 10, 
            adjective = NA, 
            item      = "lords", 
            verb      = "a-leaping",
            location  = NA
            )

should return

"ten lords a-leaping"

Here are some tips for completing this task:

  • You will need to use your pluralize_gift() function!
make_phrase <- function(day_num, adjective, gift, verb, location) {
  
  ## Step 1: Replace NAs with empty strings
  adjective <- str_replace_na(adjective, replacement = "")
  ____ <- ____
  ____ <- ____

  ## Step 2: Convert numeric day to English day (1 = one, 2 = two)
  day_word <- english::as.english(day_num) |> 
    as.character()
  
  ## Step 3: If the day number is larger than 1, the gifts need pluralized!
  gift <- if_else(day_num > 1, 
                  ____,
                  ____)
  
  ## Step 4: For the first day, replace day_num with "a" or "an"
  
  # Does the item start in a vowel?
  begin_vowel <- str_detect(gift, pattern = ____) 
  
  day_word <- case_when(
    # If the gift starts with a vowel, add "an" to the beginning
    day_num == 1 & begin_vowel ~ ____,
    # If the gift DOES NOT start with a vowel, add "a" to the beginning
    day_num == 1 & !begin_vowel ~ ____,
    ## If the day IS NOT 1, then day_word should default to what was made before
    .default = ____
    )
  
  ## Step 5: Glue all of the pieces together into one string and return!
  phrase <- glue("{day_word} {adjective} {gift} {verb} {location}")  
  
  # Step 6: Remove whitespace from gluing the string together
  phrase <- str_squish(phrase)

  return(phrase)
}

Test Your Function

Let’s try your function out on the xmas_small data, by making a new variable containing the daily phrases. Notice I’ve provided you with code to iterate through each row of the data set to create a phrase (using your make_phrase() function) with your function’s five inputs (day_num, adjective, item, verb, location).

Because your function has more than two inputs, we need to use a function from the pmap_XXX() family. I specifically chose pmap_chr() because the output of the make_phrase() function is a character (string).

xmas_small |> 
  mutate(full_phrase = pmap_chr(.l = list(day_num   = day,
                                          adjective = adjective, 
                                          gift      = gift_item, 
                                          verb      = verb, 
                                          location  = location
                                          ), 
                                .f = make_phrase
                                )
         )

Once you’ve obtained a successful test on your xmas_small dataset, fill in the necessary inputs to pmap_chr() to create a full_phrase column in the xmas dataset.

xmas <- xmas |> 
  mutate(full_phrase = pmap_chr(.l = list(day_num   = ______,
                                          adjective = ______, 
                                          gift      = ______, 
                                          verb      = ______, 
                                          location  = ______
                                          ), 
                                .f = make_phrase
                                )
         )

Canvas Submission

Your full_phrase column is the answer to this week’s Practice Activity.

Copy and paste your full_phrase column to show me the phrases you made!

xmas |> 
  pull(full_phrase)

If you finished early…

Revise the pluralize_gift() function to be a vectorized function! Hint, you will need to translate the if(). else if(), and else() code into different cases for the case_when() function.

Try out your vectorized function!

pluralize_gift(xmas$gift_item)