---
title: "Miscellaneous Tips and Tricks in .mono[R]"
subtitle: "EC 425/525, Lab 7"
author: "Edward Rubin"
date: "`r format(Sys.time(), '%d %B %Y')`"
output:
  xaringan::moon_reader:
    css: ['default', 'metropolis', 'metropolis-fonts', 'my-css.css']
    # self_contained: true
    nature:
      highlightStyle: github
      highlightLines: true
      countIncrementalSlides: false
---
class: inverse, middle

```{R, setup, include = F}
# devtools::install_github("dill/emoGG")
library(pacman)
p_load(
  broom, tidyverse,
  latex2exp, ggplot2, ggthemes, ggforce, viridis, extrafont, gridExtra,
  kableExtra, snakecase, janitor,
  data.table, dplyr, estimatr,
  lubridate, knitr, parallel, furrr,
  lfe,
  here, magrittr
)
# Define pink color
red_pink <- "#e64173"
turquoise <- "#20B2AA"
orange <- "#FFA500"
red <- "#fb6107"
blue <- "#3b3b9a"
green <- "#8bb174"
grey_light <- "grey70"
grey_mid <- "grey50"
grey_dark <- "grey20"
purple <- "#6A5ACD"
slate <- "#314f4f"
# Dark slate grey: #314f4f
# Knitr options
opts_chunk$set(
  comment = "#>",
  fig.align = "center",
  fig.height = 7,
  fig.width = 10.5,
  warning = F,
  message = F
)
opts_chunk$set(dev = "svg")
options(device = function(file, width, height) {
  svg(tempfile(), width = width, height = height)
})
options(knitr.table.format = "html")
```

# Prologue

---
name: schedule

# Schedule

## Last time

Simulation in .mono[R]

## Today

Helpful tips and tricks in .mono[R]
---
layout: true
# Tips and tricks

---
class: inverse, middle
---
name: applys
## The apply family

In general, `for` loops are not the "preferred" route in .mono[R].

--

1. Many functions are vectorized—you can apply a function over a vector.
--
<br>_E.g._, the square root of the numbers from 1 to 10: `sqrt(1:10)`.

--

1. That said, sometimes you just gotta loop.
--
<br>For these situations, `base` .mono[R] offers a family of `apply` functions.

---
name: lapply
## The apply family

The `apply` family *applies* a function over a vector, list, data frame, *etc.*

--

For example, `lapply()` takes two arguments: `X` and `FUN`.

--
- .purple[`X`] A vector/list of values.

--
- .purple[`FUN`] The function you want to evaluate on each value of `X`.

--

`lapply()` returns a list of the results.

--

.ex[Example] `toupper()` capitalizes characters
--
, _e.g._, `toupper("a")` yields `"A"`.

--

`lapply(X = c("a", "pig"), FUN = toupper)`
--
 returns `list("A", "PIG")`.

--

.note[Note] This is a silly example, as you can directly use `toupper()` on vectors.
---
name: apply
## Plain apply

The related `apply()` function *applies* a given function (`FUN`) along the margins (`MARGIN`) of a given array/matrix (`X`).

--

Your options for `MARGIN` are `1` for rows and `2` for columns.

--

.ex[Example] Let's find the maximum value in each row of a matrix.

```{R, ex-apply}
# Create a matrix
ex_matrix <- matrix(data = 1:16, nrow = 4, byrow = T)
# Find the maximum value in each row.
apply(X = ex_matrix, MARGIN = 1, FUN = max)
```

---
name: mapply
## Multiple apply

Like `lapply()`, `mapply()` repeatedly evaluates a function (`FUN`) for each value in a vector of inputs.

--

However, `mapply()` allows you to evaluate across .b[multiple] vectors.

--

In addition `mapply()` allows you to dictate whether/how the results are simplified (_e.g._, `SIMPLIFY = T` for vector or matrix) or kept as a `list`.

--

.ex[Example] Random normal draws with different means and variances.

```{R, ex-mapply}
mapply(FUN = rnorm, n = 1, mean = c(0, 10, 20), sd = 1:3)
```
---
## Custom apply

All of our examples used already-defined functions for `FUN`, _e.g._,
--
```{R, more-apply, eval = F}
lapply(X = c("a", "pig"), FUN = toupper)
```

--

Alternatively, you define your own function at `FUN`, _e.g._,
--
```{R, more-apply2, eval = T}
lapply(X = 1:2, FUN = function(i) {i > 1})
```
---
name: apply-more
## Other packages


Other packages offer similar (and parallelized) functions.

.left20[
.hi-pink[`base`]
<br>
`lapply()`
<br>
`apply()`
<br>
`mapply()`
]

--

.left25[
.hi-orange[`purrr`/`furrr`]
<br>
`map()`
<br>
?
<br>
`map2()`
]

--

.left30[
.hi-turquoise[`future.apply`]
<br>
`future_lapply()`
<br>
`future_apply()`
<br>
`future_mapply()`
]

--

.left25[
.hi-purple[`parallel`]
<br>
`mclapply()`
<br>
`mcapply()`
<br>
`mcmapply()`
]
---
name: for
## `for()` loops

However, if you're really committed to running for loops, the syntax is

```{R, ex-for, eval = F}
# Create an empty vector
our_vector <- c()
# Run the for loop for some numbers
for (i in c(1, 1, 2, 3, 5, 8)) {
  # Print 'i'
  print(i)
  # Append 'i' to the end of our_vector
  our_vector <- c(our_vector, i)
}
```
---
name: lists
## Lists and unlisting

Lists (_e.g._, as outputted by `lapply()`) can be helpful—but they can also be fairly annoying.
--
 Enter `unlist()`.

--

.col-left[
.b[List output]
```{R, ex-unlist}
lapply(
  X = 1:2,
  FUN = as.character
)
```
]

--

.col-right[
.b[`unlist()`-ing to vector]
```{R, ex-unlist2}
lapply(
  X = 1:2,
  FUN = as.character
) %>% unlist()
```
]
---
name: list-df
## From lists to data frames

Sometimes you don't want to entirely `unlist()` a list.

--

For example, you might have a list of data frames that you want to bind into a new data frame.

--

In this case, you can use `bind_rows()` or `bind_cols()` from `dplyr`.

--

Alternatively, you might be able to make use of `map_dfr()` or `map_dfc()`.

---
name: list-index
## Indexing lists

.note[Also] Don't forget that you can index lists using double-brackets.
```{R, list-index}
# Capitalize the alphabet
our_list <- lapply(X = letters, FUN = toupper)
# The third letter
our_list[[3]]
```
---
name: which
## Logical vectors and `which()`

Finally, the simply function `which()` can be surprisingly helpful.

--

`which()` tells you *which* of the entries in a logical vector are `TRUE`
--
, _i.e._, *which* element—or elements—satisfies your logical condition(s).
---
layout: false
class: clear


```{R, which0}
letters
```

--

```{R, which1}
letters > "m"
```

--

```{R, which2}
which(letters > "m")
```

--

```{R, which3}
letters[which(letters > "m")]
```
---
class: clear, middle

Alternatively, we could have just used the logical vector.
---
class: clear

```{R, logical0}
letters
```

--

```{R, logical1}
letters > "m"
```

--

```{R, logical2}
letters[letters > "m"]
```
---
# Tips and tricks
## Logical vectors, continued

This logic-based selection works on many classes of objects, but it may change the class/structure of the object.

.col-left[
```{R, logical-matrix0}
# Create a matrix
mat <- matrix(1:9, ncol = 3)
# Print it out
mat
```
]
--
.col-right[
```{R, logical-matrix1}
# Is the entry even?
mat %% 2 == 0
```
]
--
.col-right[
```{R, logical-matrix2}
# Print the even entries
mat[mat %% 2 == 0]
```

]
---
layout: false
# Table of contents

.pull-left[
### Tips and tricks
.small[
1. [The apply family](#applys)
  - [`lapply()`](#lapply)
  - [Plain `apply()`](#apply)
  - [`mapply()`](#mapply)
1. [`for()` loops](#for)
1. [Lists](#lists)
  - [`unlist()`-ing](#lists)
  - [Binding to data frame](#list-df)
  - [Indexing](#list-index)
1. [Logical vectors and `which()`](#which)
]]

---
exclude: true

```{R, generate pdfs, include = F, eval = T}
source("../../ScriptsR/unpause.R")
unpause("07RMisc.Rmd", ".", T, T)
```
