Day 18 - Debugging and Conditions

Fall 2022

Dr. Jared Joseph

October 19, 2022

Overview

Timeline

  • Errors
  • Errors in Functions
  • Conditions

Goal

To teach some starter debugging skills and how to use conditionals.

Errors

Common Error Messages

object X not found / could not find X
R couldn’t find something you tried to use
subscript out of bounds
You tried to sub-set something, but you selected for something that doesn’t exist
non-numeric argument to binary operator
You tried to do math on something you can’t do math on
replacement has...
You tried to put values somewhere and there are too many/not enough values for that space

Errors in Functions

Error Messages in Functions are Difficult

#| echo: fenced

example = c(1, 2, 3, 3, 4, 5, 7)

error_example = function(numeric_vector) {
  
  # Sum it up!
  vec_sum = sum(example)
  
  # divide by sum!
  percents = example / vec_sum
  
  # Get a table!
  vec_table = table(example)
  
  # Sum the possibilities!
  sum_names = sum(names(vec_table))
  
  # return the table!
  return(vec_table)
}

error_example(example)

Error Messages in Functions are Difficult

#| echo: fenced

example = c(1, 2, 3, 3, 4, 5, 7)

error_example = function(numeric_vector) {
  
  # Sum it up!
  vec_sum = sum(example)
  
  # divide by sum!
  percents = example / vec_sum
  
  # Get a table!
  vec_table = table(example)
  
  # Sum the possibilities!
  sum_names = sum(names(vec_table))
  
  # return the table!
  return(vec_table)
}

error_example(example)

Error in sum(names(vec_table)): invalid 'type' (character) of argument

Errors WITHOUT Messages are Worse

```{r}
#| output-location: column-fragment

# Make example
example = c(1, 2, 3, 3, 4, 5, 7)

# re-create my failed mode from Monday
mode_fail = function(numeric_vector) {
  
  # Get frequency
  num_table = table(numeric_vector)
  
  # Find most common
  mode_num = num_table[which(num_table == max(num_table))]
  
  # get the name of most common
  mode_name = unname(mode_num)
  
  # return result
  return(mode_name)
}

# Bad result!
mode_fail(example)
```
[1] 2

Figure out the Why (Debugging Tools)

traceback()
Show me all the code run when the error happened.
debug() / undebug() / debugonce()
Let me explore the mini-R universe inside the function
browser()
Let me explore inside the function right here!

Example 1

```{r}
#| output-location: column-fragment
#| error: true

example = c(1, 2, 3, 3, 4, 5, 7)

error_example = function(numeric_vector) {
  
  # Sum it up!
  vec_sum = sum(example)
  
  # divide by sum!
  percents = example / vec_sum
  
  # Get a table!
  vec_table = table(example)
  
  # Sum the possibilities!
  sum_names = sum(names(vec_table))
  
  # return the table!
  return(vec_table)
}

error_example(example)
```
Error in sum(names(vec_table)): invalid 'type' (character) of argument

Example 2

```{r eval=FALSE}
#| output-location: column-fragment

# Make example vector
example = c(1, 2, 3, 3, 4, 5, 7)

# re-create my failed mode from Monday
mode_fail = function(numeric_vector) {
  
  # Get frequency
  num_table = table(numeric_vector)
  
  # Find most common
  mode_num = num_table[which(num_table == max(num_table))]
  
  # get the name of most common
  mode_name = unname(mode_num)
  
  # return result
  return(mode_name)
}

# Bad result!
mode_fail(example)
```

Why is it giving us “2”?

Conditions

A Review of Conditionals

Conditionals help you ask for things when a condition is TRUE.

  • == - Equal to
  • != - Not equal to
  • > - Greater than
  • >= - Greater than or equal to
  • < - Less than
  • <= - Less than or equal to

For example:

vector <- c(1, 3, 5, 7, 9, 11)

  • vector[vector > 5]: c(7, 9, 11)
  • vector[vector <= 5]: c(1, 3, 5)
  • vector[vector == 5]: c(5)
  • vector[vector != 5]: c(1, 3, 7, 9, 11)

ifelse

```{r, eval=FALSE}
ifelse(TEST, IF TEST IS TRUE, IF TEST IS FALSE)
```
```{r}
#| output-location: column-fragment

ifelse(10 > 5,
       "Yes, it is greater.",
       "No, it is not greater.")
```
[1] "Yes, it is greater."

if then else

```{r, eval=FALSE}
if(TEST) {
  IF TEST IS TRUE
  DO THIS
  AND TIHS
  ETC
} else {
  ELSE, DO TIHS
  AND THIS
  ETC
}
```
```{r}
#| output-location: column-fragment

if(10 > 5) {
  
  print("Yes, it is greater.")
  
} else {
  
  print("No, it is not greater.")
  
}
```
[1] "Yes, it is greater."

Conditions Let Functions React

```{r}
#| output-location: column-fragment
#| error: true

add_me <- function(x, y) {
  
  if(!is.numeric(x)) {stop("X isn't numeric!")}
  if(!is.numeric(y)) {stop("Y isn't numeric!")}
  
  # Step 1
  result = x + y
  
  # Return Results
  return(result)
}

add_me("8", 1)
```
Error in add_me("8", 1): X isn't numeric!

Conditions Help Functions Flex

```{r}
#| output-location: column-fragment
#| error: true

add_me <- function(x, y) {
  
  if(!is.numeric(x)) {
    print("Your X wasn't numeric! I tried to fix it.")
    x = as.numeric(x)
  }
  
  if(!is.numeric(y)) {
    print("Your Y wasn't numeric! I tried to fix it.")
    y = as.numeric(y)
  }
  
  # Step 1
  result = x + y
  
  # Return Results
  return(result)
}

add_me("8", 1)
```
[1] "Your X wasn't numeric! I tried to fix it."
[1] 9

A Useful Example

```{r}
#| output-location: column-fragment

pet_years = function(pet_age, type) {
  
  # set default human_age if type not found
  human_age = NA
  
  # if pet is a dog
  if(type == "dog"){
    human_age = (16 * log(pet_age)) + 31
  }
  
  # if pet is a cat
  if(type == "cat"){
    human_age = -14.4 + 21.58275*pet_age - 2.98951*pet_age^2 + 0.1550117*pet_age^3
  }
  
  # return
  return(human_age)
}

print("Your dog is __ years old.")
pet_years(6, "dog")
print("Your cat is __ years old.")
pet_years(4, "cat")
```
[1] "Your dog is __ years old."
[1] 59.66815
[1] "Your cat is __ years old."
[1] 34.01959

For Next Time

Topic

Lab 5

To-Do

Finish Worksheet