---
title: "functions"
subtitle: "Chapter 15"
theme: flatly 
date: today
toc: true
format:
  html: 
    code-overflow: wrap
    toc: true
    toc-title: "Contents"
    # hide code?

execute:
  warning: false
  message: false
---

## General format for writing a function
     
```{r, eval = FALSE}
 name <- function(arguments) {
   body
 }
```
 
 
 We'll discuss **3 types of functions:**
 
 1. Vector
 
 2. Data
 
 3. Plotting
 
### Vector Functions
 
 Motivation for functions
 
 1. Create 4 vectors, each containing 5 random numbers with mean = 2, and standard deviation = 3.
 2. *Normalize* each vector to have min = 0 and max = 1.
 3. Notice any inefficency?
 4. Write a function to normalize a vector and use it.
 
```{r}
 n <- function(a) {
 rng <- range(a, na.rm = TRUE)
 (a - rng[1])/(rng[2] - rng[1])
 }
```
 
 5. Use the function inside `mutate` like this:
 
```{r, eval = FALSE}
library(tidyverse)
 # using a function within mutate
 df |> mutate(
   a = rescale01(a),
   b = rescale01(b),
   c = rescale01(c),
   d = rescale01(d))
```

 We can use `across()` to make the above even more efficient
 
 ### How to compute the mean of many columns
 

```{r}
 library(tidyverse)
 # get the mean of columns a - d.
 df <- tibble(
   a = rnorm(10),
   b = rnorm(10),
   c = rnorm(10),
   d = rnorm(10)
 )
 
 print(df)
 df |> summarize(across(a:d, mean))

```
 
 ### How to compute the median of numeric columns
 
```{r}
 glimpse(diamonds)
 diamonds |> summarize(across(where(is.numeric), median))
```
 
 ## The `range` function
 
 Use the range of a vector to minimize redundancy
```{r}
 rescale01 <- function(x) {
   rng <- range(x, na.rm = TRUE)
   (x - rng[1]) / (rng[2] - rng[1])
 }
```
 
 ### The z-score
```{r}
 z_score <- function(x) {
   (x - mean(x, na.rm = TRUE)) / sd(x, na.rm = TRUE)
 }
```
 
 
 ### Clamp
 
 What happens if you remove the `.default` line?
 
```{r}
 clamp <- function(x, min, max) {
   case_when(
     x < min ~ min,
     x > max ~ max,
     .default = x
   )
 }
 
 clamp(1:10, min = 3, max = 7)
```
 
 ### A function on strings
```{r}
 # notice what is gettings assigned TO
 first_upper <- function(x) {
   str_sub(x, 1, 1) <- str_to_upper(str_sub(x, 1, 1))
   x
 }
 
 first_upper("hello")
```

 ### A string stripper
```{r}
 # the order matters in the str_remove_all's below
 clean_number <- function(x) {
   is_pct <- str_detect(x, "%")
   num <- x |> 
     str_remove_all("%") |> 
     str_remove_all(",") |> 
     str_remove_all(fixed("$")) |> 
     as.numeric()
   if_else(is_pct, num / 100, num)
 }
 
 clean_number("$12,300")
 clean_number("45%")
```

 ### Summarize functions
 
 
 Here's a somewhat advanced version.  Observe the importance of the `:=`
```{r}
f <- function(x,cat_var, num_var){
     x |> group_by({{cat_var}}) |> 
         summarize("{{num_var}}" := mean({{num_var}}))
 }
```
 
 
 