{ "cells": [ { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "bc1eb3913b65a9403e2b7d0119f2aebf", "grade": false, "grade_id": "cell-441786adbe710cac", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "# Worksheet B-3: Nesting, List Columns, and `purrr`\n", "\n", "\n", "From this topic, students are anticipated to be able to:\n", "\n", "- Use the `map` family of functions from the purrr package to iteratively apply a function.\n", "- Create and operate on list columns in a tibble using `nest()`, `unnest()`, and the `map` family of functions.\n", "- Define functions on-the-fly within a `map` function using shortcuts.\n", "- Apply list columns to cases in data analysis: columns of models, columns of nested lists (JSON-style data), and operating on entire groups within a tibble.\n", "\n", "Load the worksheet requirements:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "e9cdd0397d1848459e69155e90a7722a", "grade": false, "grade_id": "cell-04b3e77f6b2aa884", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "suppressPackageStartupMessages(library(testthat))\n", "suppressPackageStartupMessages(library(digest))\n", "suppressPackageStartupMessages(library(tidyverse))\n", "suppressPackageStartupMessages(library(palmerpenguins))\n", "suppressPackageStartupMessages(library(glue))\n", "suppressPackageStartupMessages(library(gapminder))\n", "suppressPackageStartupMessages(library(broom))\n", "suppressPackageStartupMessages(library(repurrrsive))" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "08eb017cf8b0ec73ede37fdb92dc82f0", "grade": false, "grade_id": "cell-8cc5ec4510ee55b3", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "The following code chunk has been unlocked, to give you the flexibility to start this document with some of your own code. Remember, it's bad manners to keep a call to `install.packages()` in your source code, so don't forget to delete these lines if you ever need to run them. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# An unlocked code chunk." ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "27868ca7100c39aa8b141db8769e683b", "grade": false, "grade_id": "cell-b8ef43336df77928", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "# Part 1: Exploring `purrr` Fundamentals\n", "\n", "The `purrr` package is also part of the `tidyverse`.\n", "\n", "Apply a function to each element in a list/vector with `map`.\n", "\n", "General usage: `purrr::map(VECTOR_OR_LIST, YOUR_FUNCTION)`\n", "\n", "Note:\n", "\n", "- `map` always returns a list.\n", "- `YOUR_FUNCTION` can return anything!\n", "\n", "There are many variations of `map_*`, which you can find in this [cheatsheet](https://github.com/rstudio/cheatsheets/blob/master/purrr.pdf)." ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "b7c4b02883ef58a728c8d47843a522e9", "grade": false, "grade_id": "cell-39402bc67d445e29", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "For the next few tasks, you will be converting for-loop(s) to vectorized expressions that reproduce the output (numbers should be the same, the format can be different).\n", "\n", "## QUESTION 1\n", "\n", "Without using vectorization, take the square root of the following vector:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "b9fd99c626cde4c068997118d3a65d68", "grade": false, "grade_id": "cell-cf14f37393dfb8aa", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "x <- 1:10" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "1a5b1797851d248be569e8e32b93f5d8", "grade": false, "grade_id": "cell-a05a931e588540a5", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "The result should be a list of the calculations. Store your answer in `answer1`.\n", "\n", "```r\n", "answer1 <- map(FILL_THIS_IN, FILL_THIS_IN)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "0baa83c880dc41e0e19ffd73efb8af73", "grade": false, "grade_id": "cell-6284b5e7fedca3b9", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "answer1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "c14040d5e67790c0675608b2aee4add3", "grade": true, "grade_id": "cell-24f033554d4e73c0", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 1', {\n", " expect_known_hash(mode(answer1), '086ebc4c59c08c43e75bae74f1e16897')\n", " expect_known_hash(round(unlist(answer1), 4), 'ad16817e39d61cdf2ce38234f61306de')\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "ce01f1ff01893272ef0dd57689701202", "grade": false, "grade_id": "cell-d71be613854f3101", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## QUESTION 2 \n", "\n", "In Question 1, we used the generic `map` function, and got a list. Let's use a more specific `map_*` function this time.\n", "\n", "Again without using vectorization, square each component of `x`. The result should be a numeric vector. Store your answer in `answer2`:\n", "\n", "```r\n", "answer2 <- map_dbl(FILL_THIS_IN, FILL_THIS_IN)\n", "```\n", "\n", "_Hint:_ The last `FILL_THIS_IN` corresponds to an anonymous function!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "088407d7039474dbf36c2e616aedcfb0", "grade": false, "grade_id": "cell-7ef5e38acec39a45", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "print(answer2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "79604b376a235819403e5d62dde4a748", "grade": true, "grade_id": "cell-e973a44a4a26e248", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 2', {\n", " expect_known_hash(mode(answer2), '46606ee201b428a3fa6c8a0d3d9e671c')\n", " expect_known_hash(round(unlist(answer2), 4), '84a2193460cb35ff884e4c3144abf122')\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "912aedb5d0c62777bf8efbc6e7c088ca", "grade": false, "grade_id": "cell-4b2cd38653067dca", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Now we've used both `map` and a more specific `map_dbl`. Now you can see how they differ, and how the use of one is better justified than the other for our purpose. Now it's your turn to choose! Remember to use the [cheatsheet](https://github.com/rstudio/cheatsheets/blob/master/purrr.pdf) if you need it!\n", "\n", "## QUESTION 3\n", "\n", "Below is sample code that computes the mean of every column in the `mtcars` dataset. Use the appropriate `purrr` function to vectorize this task." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "f4aae378ca91f36516266b3ea5c5871d", "grade": false, "grade_id": "cell-d19221d660e2569f", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "mtcars_means <- numeric()\n", "for (c in seq_along(mtcars)){\n", " mtcars_means[[c]] <- mean(mtcars[[c]])\n", "}\n", "mtcars_means" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "a87413240deefef73769ef0dfdc000ee", "grade": false, "grade_id": "cell-7149931321d1676e", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Store your answer in `answer3`; as above, your answer should be a vector. _Hint_: remember that a tibble / data frame is just a list, where each entry is a column (a vector).\n", "\n", "```r\n", "answer3 <- FILL_THIS_IN(datasets::mtcars, FILL_THIS_IN)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "b8f773d13f9b6239b96ab669bd40750f", "grade": false, "grade_id": "cell-57149cc846945d50", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "print(answer3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "ba2f6312ebcfe24b55ffb8f9058db40c", "grade": true, "grade_id": "cell-4bee819e10679644", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 3', {\n", " expect_known_hash(floor(unname(answer3)), '9a69e180a47954630685d24f403fe3af')\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "b17eb1d452051154af1af8030caa3141", "grade": false, "grade_id": "cell-58c45fca89760512", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## QUESTION 5\n", "\n", "Below is sample code that computes the number of unique values in each column of `mtcars` as a named vector, using for-loops. Use the appropriate `purrr` function to vectorize this task." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "28f025daf9b2193125503ff10f0d7e6c", "grade": false, "grade_id": "cell-575f9f96064b2ff8", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "mtcars_unique <- numeric()\n", "for (c in seq_along(datasets::mtcars)){\n", " mtcars_unique[[c]] <- length(unique(datasets::mtcars[[c]]))\n", "}\n", "names(mtcars_unique) <- names(datasets::mtcars)\n", "mtcars_unique" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "0a80aa0594606fc30267be9e47b6acd1", "grade": false, "grade_id": "cell-90e334b74bac1fa5", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Store your answer in `answer4`:\n", "\n", "```r\n", "answer4 <- datasets::mtcars %>% \n", " FILL_THIS_IN(FILL_THIS_IN) %>% \n", " FILL_THIS_IN(FILL_THIS_IN)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "41181934f8753da5b79840bdf5612b97", "grade": false, "grade_id": "cell-bf6e549fb1e34216", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "print(answer4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "30ce0a8406513d4894dbf8cfc524a785", "grade": true, "grade_id": "cell-01d694fdcf1ee07a", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 4', {\n", " expect_known_hash(mode(answer4), '46606ee201b428a3fa6c8a0d3d9e671c')\n", " expect_known_hash(as.integer(answer4), '1981b33e1151073e1c227fe95218c6f5')\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "5fe018bbdbfdf5bfbc56ed27e916fe00", "grade": false, "grade_id": "cell-220c9bc0fde4d12c", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## QUESTION 4\n", "\n", "Below is sample code that divides the values in each column of the `mtcars` dataset by the maximum in that column. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "e97a58d1fef9764ad8a6843e43769e33", "grade": false, "grade_id": "cell-0b06d241b2c23867", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "for (i in seq_along(mtcars)){\n", " mtcars[[c]] <- mtcars[[i]] / max(mtcars[[i]], na.rm = TRUE)\n", "}\n", "head(mtcars)" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "9160e8464d986658f3a85c4a5f23c7ea", "grade": false, "grade_id": "cell-b686b505db635e53", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Find a way to do this without a loop. Store your answer in `answer5`:\n", "\n", "```r\n", "answer5 <- datasets::mtcars %>%\n", " mutate(FILL_THIS_IN(FILL_THIS_IN, FILL_THIS_IN))\n", " ```\n", " \n", " _Hint_: The last `FILL_THIS_IN` corresponds to an anonymous function.\n", "\n", " _Food for thought_: Here is some sample code that divides the values in each column of the `mtcars` dataset by the maximum in that column using `purrr` instead of a loop or using `mutate`: `map(mtcars, function(x) x/max(x))`. How and why is the output of this code different from `answer5`? " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "15481fa8846ac5a7281b2a843f839b6c", "grade": false, "grade_id": "cell-b23dda8894947ec3", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "head(answer5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "ffff6266bf7a7026052d3ca19bf76ccf", "grade": true, "grade_id": "cell-e910c3a832bde7db", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 5', {\n", " expect_known_hash(class(answer5), '555434c8748e07b094500256087cdcc5')\n", " expect_known_hash(dimnames(answer5), '3a51b37e4731153f63a1f5f9dc188269')\n", " expect_known_hash(round(answer5$mpg, 3), 'af82f570a0aa02d8abcbbd14386e98b0')\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "7c6c287be0d180de2986102c9ad7eb74", "grade": false, "grade_id": "cell-08836080ad992c26", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## QUESTION 6: `map2`\n", "\n", "Let's use `purrr` to calculate some probabilities from negative binomial distributions. One parameterization of the negative binomial distribution has a mean parameter and a dispersion parameter - this parameterization is often used to model highly variable count-valued data. \n", "\n", "We would like to calculate the probability of observing a count of 0 and the probability of observing a count of 1 for a bunch of negative binomial distributions. Here's a function to do this for a single negative binomial distribution: " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "0b4cbcaf8647faa7eeaaedb915605428", "grade": false, "grade_id": "cell-299dd9f3ce5f21a9", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "prob_01_neg_bin <- function(mean, disp) { \n", " dnbinom(x=c(0, 1), mu=mean, size=disp) \n", "}\n", "\n", "prob_01_neg_bin(1, 1) # calculates probability of observing 0 count and probability of observing 1 count" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "d7d98315eae70b6b6cbf2ee45a09efe3", "grade": false, "grade_id": "cell-4bc24e3d1b11049a", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "The `prob_01_neg_bin()` function has two arguments corresponding to the two parameters of the negative binomial distribution, so to calculate probabilities for a bunch of negative binomial distributions, we'd need a `purrr` function to plug in the two parameters. Here are the parameters we would like to plug in: " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "42f9112f85ff3d779faedd5875d7f20f", "grade": false, "grade_id": "cell-4c98a73fa96ac4a0", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "mean_params <- c(1, 5, 10)\n", "disp_params <- c(0.1, 1, 5)" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "2c31b49c9862ce08643bba49a055f7a3", "grade": false, "grade_id": "cell-58f032107ffa80dd", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Store your answer in `answer6`. It should be a list of probabilities.\n", "\n", "```r\n", "answer6 <- map2(FILL_THIS_IN, FILL_THIS_IN, FILL_THIS_IN)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "16cf1db61d3c7394731ef64121691fd7", "grade": false, "grade_id": "cell-2bcd05dc3ff9bfa9", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "print(answer6)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "098bf41de171c96bd8558fcf0e28615f", "grade": true, "grade_id": "cell-4f59cc325554b20f", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 6', {\n", " expect_known_hash(round(unlist(answer6), 4), 'b9facb41d852fe0d051fc0c943d0fc5a')\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "2425441f2f34f3c91006449e5c562d6a", "grade": false, "grade_id": "cell-088dac25a27d3560", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## Question 7\n", "\n", "Introducing the Big Bang `!!!` and `rlang::exec()`.\n", "\n", "Using the ```palmerpenguins::penguins``` tibble: \n", "\n", "Let's use the `recode()` function from the `dplyr` package to rename the levels of the `island` factor variable. The straightforward way to do this would be to do:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "ee265b6fc3cd5ac0f6950fe4a5772684", "grade": false, "grade_id": "cell-2dec91428b3dc3d1", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "penguins %>% mutate(island = \n", " recode(island, Biscoe = \"B\", Dream = \"D\", Torgersen = \"T\"))" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "0a45ea9759c321d86af52e327c3c8ba7", "grade": false, "grade_id": "cell-717cccf175800045", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "But what if you wanted to specify the levels to be renamed and their new names via a list? " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "2969a395e830ff25ea9e4852aaaa2dd1", "grade": false, "grade_id": "cell-6307c11180165611", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "island_level_key <- c(Biscoe = \"B\", Dream = \"D\", Torgersen = \"T\")" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "56289ac7bdf78a35433e59b7e7208918", "grade": false, "grade_id": "cell-08df1b7f473ece7a", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Inputting the list itself via `penguins %>% mutate(island = recode(island, island_level_key))` throws an error, because `dplyr::recode()` is not expecting a list input. What's the alternative?\n", "\n", "Your task: use the big bang operator (`!!!`) in front of the list argument, to get the desired result. This effectively takes the arguments of a list, and puts them as arguments to a function.\n", "\n", "```\n", "answer12 <- penguins %>% mutate(island = recode(island, FILL_THIS_IN))\n", "```\n", "\n", "__FYI__: Conveniently, `dplyr::recode()` recognizes the big bang operator. If you have a function that doesn't recognize it (like `sum()`), use `rlang::exec(function, !!!list_of_arguments)` instead." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "e5aeee95d2ef6a4df4d71f4027d85644", "grade": false, "grade_id": "cell-dad1190a6db2507f", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "print(answer7)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "e307e237f4c511f7841d7534e23d0440", "grade": true, "grade_id": "cell-0439d034ce2a106f", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 7', {\n", " expect_known_hash(answer7 %>% pull(island), \n", " \"ed9cf5d471bb4656bbb8ad65ada2a605\")\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "9f84805efba7a5bae596f85e3c454b01", "grade": false, "grade_id": "cell-3f5f8e1e41f41aaa", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "# Part 2: Nesting and List Columns\n", "\n", "_One_ of the ways a list-column can be made is by using `nest()`." ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "7cb0fe0260378e1884f4f3bdfa6eba03", "grade": false, "grade_id": "cell-b15e31f5618b8b6d", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## QUESTION 8\n", "\n", "Create a tibble that bundles everything in `gapminder` except for `country` and `continent` into a list-column. Name your list column `other` (without using `rename()` or `mutate()`). Store your answer in `answer8`.\n", "\n", "```r\n", "answer8 <- gapminder %>%\n", " nest(FILL_THIS_IN = FILL_THIS_IN)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "7395a871dc4f4f72f29767eb803e203d", "grade": false, "grade_id": "cell-3a01a9b84f3cf2e5", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "head(answer8, n = 3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "8709fabb0dfc9bb659b8665b5d779f67", "grade": true, "grade_id": "cell-36f1c148426a4e9b", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 8', {\n", " expect_known_hash(enc2utf8(sapply(answer8$other, colnames)), 'ceba7fd58def34a537b5b13430a7ec2a')\n", " expect_known_hash(sapply(answer8$other, dim), '388a8eae98b3cb184d3fe8ed8dd46916')\n", " expect_known_hash(sapply(answer8$other, `[[`, 'year'), '0370844f5c0d097891d284949811883e')\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "12e942d327d69052d5da01b9029b10c7", "grade": false, "grade_id": "cell-2aaa2f11e285f2bf", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## QUESTION 9\n", "\n", "_Reproducibly_ sample 5 countries in the `gapminder` tibble at random. Store your answer in `answer9`, and set the seed as 123.\n", "\n", "```r\n", "FILL_THIS_IN(123)\n", "answer9 <- gapminder %>%\n", " nest(FILL_THIS_IN = FILL_THIS_IN) %>% \n", " slice_sample(n=5) %>% \n", " unnest(FILL_THIS_IN)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "f6eee804daba3bfffd86bccdd397aab8", "grade": false, "grade_id": "cell-7d3cc906a94b6b46", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "head(answer9)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "0a909e784e94a393bc0ad1432aaaf137", "grade": true, "grade_id": "cell-7e8ef7ae30e0fd6a", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 9', {\n", " expect_known_hash(sort(enc2utf8(as.character(answer9$country)), method = 'radix'), 'ca060e5983d51a09aeb24c2393462353')\n", " expect_known_hash(round(answer9$gdpPercap[order(enc2utf8(as.character(answer9$country)), method = 'radix')], 3), '75d94ea77a21140b54a374ed59f2253a')\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "94cd61fbd522895fe0e75f070400cefc", "grade": false, "grade_id": "cell-a2de145334d77ffe", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## QUESTION 10\n", "\n", "For each `gapminder` continent, fit a linear model of `lifeExp` from `log(gdpPercap)` and put this as a new column. Store your answer into `answer10`:\n", "\n", "```r\n", "answer10 <- gapminder %>% \n", " select(continent, gdpPercap, lifeExp) %>% \n", " nest(data = c(FILL_THIS_IN, FILL_THIS_IN)) %>% \n", " mutate(model = FILL_THIS_IN(data, ~ lm(FILL_THIS_IN ~ FILL_THIS_IN, data = FILL_THIS_IN)))\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "cd65f2bed13d416d0aca1efa3ea1f8be", "grade": false, "grade_id": "cell-cc531935edea8760", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "print(answer10)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "0c4dc6073d8651c6180ddccc595674a7", "grade": true, "grade_id": "cell-4e29da44162c2305", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 10', {\n", " expect_known_hash(sapply(answer10$model, class), '2fe5bf6c6fb725f272c801e5f7560afe')\n", " expect_known_hash(round(unlist(lapply(answer10$model, coef)), 3), 'e536d3378586d3c54b920504b3238cde')\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "0736e760884754cc0e6efd17fc47379e", "grade": false, "grade_id": "cell-6fb1589fc84effae", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## QUESTION 11\n", "\n", "Using your model from Question 10, make predictions using `augment()` from the `broom` package, and then `unnest`. Store your answer in `answer11`:\n", "\n", "```r\n", "answer11 <- answer10 %>% \n", " mutate(continent, yhat = map(FILL_THIS_IN, FILL_THIS_IN), .keep = \"none\") %>% \n", " unnest(FILL_THIS_IN)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "301b63d8b8eebf3cdf1f30ca99396f5a", "grade": false, "grade_id": "cell-5f6d32b6e1be426a", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "print(answer11)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "ec7877e7adec292cd955e396c9c99ee0", "grade": true, "grade_id": "cell-b3e5f2ec8ef04b91", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 11', {\n", " expect_known_hash(dimnames(answer11), 'f58a9b4d518ca8cb04492350384da646')\n", " expect_known_hash(round(with(answer11, .fitted[order(lifeExp)]), 3), 'f8db1a712fe6b69f7577c88882248dc5')\n", " expect_known_hash(round(with(answer11, .sigma[order(lifeExp)]), 3), '83e927e2f02fd18c293c3a1ddb7a0ed2')\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "a73164421e2dc5bf44fd628009acdc0a", "grade": false, "grade_id": "cell-2207136242a2f439", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## Question 12: `pmap`\n", "\n", "Using the `palmerpenguins::penguins` tibble, calculate a 95% confidence interval based on the one-sample t-test for the mean body mass in grams of each penguin species. Here is code to do this for the Adelie penguins: " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "6ef45b1fa80fbb292e6d3c8568bab256", "grade": false, "grade_id": "cell-80754c8f02205791", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "get_adelie_stats <- penguins %>% \n", " filter(species == \"Adelie\") %>% \n", " summarise(mean = mean(body_mass_g, na.rm = TRUE), \n", " sd = sd(body_mass_g, na.rm = TRUE), \n", " n = n())\n", "\n", "# Given a sample mean, sample standard deviation, and sample size, \n", "# calculate a 95% confidence interval for the population mean\n", "make_95p_conf_int_t <- function(mean, sd, n) { \n", " c(lower_95p_ci = mean - qt(0.975, df=n-1), upper_95p_ci = mean + qt(0.975, df=n-1)) \n", "}\n", "\n", "make_95p_conf_int_t(get_adelie_stats$mean, get_adelie_stats$var, get_adelie_stats$n)" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "11c35a1a8493bb196887aeb8661f3f5d", "grade": false, "grade_id": "cell-462e27829d83d3e1", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "To do this for all three species of penguins, we will need a `purrr` function to plug the three parameters of `make_95p_conf_int_t()` into. \n", "\n", "Starter code:\n", "\n", "```\n", "answer12 <- penguins %>% \n", " group_by(species) %>% \n", " summarise(mean = mean(body_mass_g, na.rm = TRUE),\n", " sd = sd(body_mass_g, na.rm = TRUE), \n", " n = n()) %>% \n", " mutate(ci = pmap(FILL_THIS_IN, FILL_THIS_IN))\n", "```\n", "\n", "Your answer should be a tibble with five columns named `species`, `mean`, `sd`, `n`, and `ci`. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "ae98b77b848619bb4bb0b60d7fe5dbc9", "grade": false, "grade_id": "cell-faf81ee09a07a4b4", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "print(answer12)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "0b15b90a4245e11074f22df197698d42", "grade": true, "grade_id": "cell-7fcc013763786e41", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 12', {\n", " answer12 %>% \n", " pull(ci) %>% \n", " unlist() %>% \n", " round(3) %>%\n", " expect_known_hash('bcdb58de75d3144dcfc728e79860e14d')\n", " expect_true(all(c(\"species\", \"mean\", \"sd\", \"n\", \"ci\") %in% names(answer12)))\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "97f442884e1714ab592ab465ea790d12", "grade": false, "grade_id": "cell-b976fcb86678aeec", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## Question 13 `unnest()`\n", "\n", "`unnest()` need not always be paired with `nest()`. Make a tibble `answer13` that is a longer version of `answer12` where the column `ci` is of double type. \n", "\n", "Starter code:\n", "\n", "```\n", "answer13 <- answer12 %>% unnest(FILL_THIS_IN)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "a858a696b3ad20b3235c2f89ea89a262", "grade": false, "grade_id": "cell-a00906f5aec894e4", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "print(answer13)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "478dd3fc2fd2c659ec5a1fac08bf4c7a", "grade": true, "grade_id": "cell-fe3f5c4c2615d264", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 13', {\n", " answer13 %>% \n", " pull(ci) %>% \n", " round(4) %>% \n", " expect_known_hash(\"790f2dedb437d642c8fdbca63117eac1\")\n", " expect_true(all(c(\"species\", \"mean\", \"sd\", \"n\", \"ci\") %in% names(answer12)))\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "e07cfa4a1e414b28733879f1fa69bd7a", "grade": false, "grade_id": "cell-653ade75b5c1010d", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## Question 14\n", "\n", "Output a list of gapminder tibbles, one for each continent. Do not include the `continent` column in the divided tibbles -- the name of each list entry should be the continent name. \n", "\n", "_Hint_: Check out the `enframe()` and `deframe()` functions. \n", "\n", "Starter code:\n", "\n", "```\n", "answer14 <- gapminder %>% \n", " nest(FILL_THIS_IN) %>% \n", " FILL_THIS_IN()\n", "```\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "507dbbbd851bc85e81570405ac69755c", "grade": false, "grade_id": "cell-059b832f92f8512e", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "print(answer14)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "8cda8c2612088ba409472b28913023d1", "grade": true, "grade_id": "cell-8af823c5c35e01e1", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 14', {\n", " expect_known_hash(names(answer14), '90da4aa25e5abc752edec3d524ea2677')\n", " map(answer14, pull, gdpPercap) %>% \n", " unlist() %>% \n", " unname() %>% \n", " round(4) %>% \n", " expect_known_hash(\"a621bfc9dba8da1f02e4dc19fa4083f6\")\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "62cf840907e0f4541c35f38c05739e51", "grade": false, "grade_id": "cell-2e2dcca21fb850f2", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "## Question 15 \n", "\n", "Sometimes the vector/list we're iterating over has names, and it's useful to use those names. To access these names, use the `imap` family.\n", "\n", "For the list of tibbles made in the above question, save each one to file using the appropriate purrr function, using the names as the file names.\n", "\n", "Starter code:\n", "\n", "```\n", "answer15 <- FILL_THIS_IN(answer14, ~ write_csv(FILL_THIS_IN, glue::glue(FILL_THIS_IN, \".csv\")))\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "1b9f45df4b237f0cc7d7ac95193f260d", "grade": false, "grade_id": "cell-614dfd0842b259c8", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "dir()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "415ee4419d8314d6f37baf2a11c85eb5", "grade": true, "grade_id": "cell-abc180f44f0aabb7", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 15', {\n", " expect_true(\"Africa.csv\" %in% dir())\n", " expect_true(\"Americas.csv\" %in% dir())\n", " expect_true(\"Asia.csv\" %in% dir())\n", " expect_true(\"Europe.csv\" %in% dir())\n", " expect_true(\"Oceania.csv\" %in% dir())\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "ca0b1a06a2d78f301da83a3faadc228c", "grade": false, "grade_id": "cell-efa35d5d0539e9ea", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "# Part 3: Recursive Lists\n", "\n", "We won't focus much on recursive lists in this course, but here is a little taste of it.\n", "\n", "## Question 16: `unnest_wider()` and `unnest_longer()`\n", "\n", "Explore the `repurrrsive::got_chars` nested list. It contains information about Game of Thrones characters." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "3a96aaf242fd3a16c1b94196fa61dca3", "grade": false, "grade_id": "cell-c37d34ac0130b86c", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "str(got_chars, list.len = 4)" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "053e00298f46ea7ae12b7dd4c21b0674", "grade": false, "grade_id": "cell-66f68f131707e56e", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Put the list in a tibble:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "ed020a751cb363019a1e5151c1bd8f5b", "grade": false, "grade_id": "cell-c66bef51ab12f7d8", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "got_chars_tbl <- tibble(character = repurrrsive::got_chars)\n", "print(got_chars_tbl, n = 5)" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "b07d7d6f48f765e1df83f4a4b2c4902a", "grade": false, "grade_id": "cell-12ce31c0bc8833a2", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "Would widening the list column work best, or lengthening? Do it.\n", "\n", "```\n", "answer16 <- FILL_THIS_IN(got_chars_tbl, character)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "nbgrader": { "cell_type": "code", "checksum": "3b658b59c62c9f028ae3cf6db1ef6524", "grade": false, "grade_id": "cell-c2c0d6d323c4f08a", "locked": false, "schema_version": 3, "solution": true, "task": false } }, "outputs": [], "source": [ "# your code here\n", "fail() # No Answer - remove if you provide an answer\n", "print(answer16, n = 5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "code", "checksum": "64cde7ef59f45cab63ce21ee93143551", "grade": true, "grade_id": "cell-94e5bbb953c5b136", "locked": true, "points": 1, "schema_version": 3, "solution": false, "task": false } }, "outputs": [], "source": [ "test_that('Question 16', {\n", " answer16 %>% \n", " pull(culture) %>% \n", " expect_known_hash(\"239b2663946d88db14fb52f017d749da\")\n", " answer16 %>% \n", " pull(url) %>% \n", " expect_known_hash(\"40d4d84edde6c1573c6eef61b2bd49c2\")\n", " answer16 %>% \n", " pull(name) %>% \n", " expect_known_hash(\"9fa482de54b3e866524eff35d7e4dee9\")\n", "})" ] }, { "cell_type": "markdown", "metadata": { "deletable": false, "editable": false, "nbgrader": { "cell_type": "markdown", "checksum": "6bb6994afbaa26ecfb7d2d3e558e62bd", "grade": false, "grade_id": "cell-5410b3507a1e8bfe", "locked": true, "schema_version": 3, "solution": false, "task": false } }, "source": [ "### Attributions\n", "\n", "Thanks to Diana Lin for putting this worksheet together, IcĂ­ar Fernandez Boyano for reviewing, and David Kepplinger for assistance implementing these questions. Thanks to Firas Moosvi for providing a bunch of the questions on this worksheet. Thanks to Andy Tai for implementing the autograder for many of these questions." ] } ], "metadata": { "kernelspec": { "display_name": "R", "language": "R", "name": "ir" }, "language_info": { "codemirror_mode": "r", "file_extension": ".r", "mimetype": "text/x-r-source", "name": "R", "pygments_lexer": "r", "version": "4.3.1" } }, "nbformat": 4, "nbformat_minor": 4 }