Conditionals, errors, tests, debugging Steve Bagley somgen223.stanford.edu 1
Conditional execution somgen223.stanford.edu 2
Writing a function to compute the sign of a number • Let’s write a function to compute the sign of a number: • Return -1 if the number is < 0 . • Return 0 if the number is 0 . • Return 1 if the number is > 0 . somgen223.stanford.edu 3
if , simple version • if is a basic control flow construct in R. It is not the same as ifelse . • Simple version: if(x == 0) 0 • The simple version takes a test, x == 0 , and an expression, 0 . • If the test is true, the value of the expression is returned. • If the test is false, NULL is returned. somgen223.stanford.edu 4
compute_sign1 <- function (x) { if (x < 0) -1 } compute_sign version 1 • What is the result of compute_sign1(-2) ? • What is the result of compute_sign1(2) ? somgen223.stanford.edu 5
compute_sign2 <- function (x) { if (x < 0) -1 if (x == 0) 0 } compute_sign version 2 • What is the result of compute_sign2(-2) ? somgen223.stanford.edu 6
if (x < 0) { -1 } else { 1 } if , complex version • If x < 0 , this returns -1. • Else (because x >= 0 ), this returns 1. • if ... then ... else is a very common programming idiom. • Important: put the } and else on the same line . somgen223.stanford.edu 7
{ print (1) x <- 2 x + 1 } [1] 1 [1] 3 Braces { } • Braces { } can contain one or more R expressions, one per line. • The value of the last expression will be returned, unless you have done something that alters control flow. somgen223.stanford.edu 8
compute_sign3 <- function (x) { if (x < 0) { -1 } else { 0 } } compute_sign version 3 • What is the result of compute_sign3(-2) ? • What is the result of compute_sign3(2) ? somgen223.stanford.edu 9
1 } } } [1] 1 if (x < 0) { -1 } else { if (x == 0) { 0 } else { compute_sign4 <- function (x) { compute_sign4 ( - 2) [1] -1 compute_sign4 (0) [1] 0 compute_sign4 (2) compute_sign version 4 somgen223.stanford.edu 10
compute_sign4 ("abc") [1] 1 What about values that are not numbers? • If the user supplies an argument that is not a number, we’d like to get an error, not an incorrect result. somgen223.stanford.edu 11
Errors, warnings somgen223.stanford.edu 12
stop • The stop function raises an error. This interrupts the regular flow of computation. It takes an argument, the error message that you want printed. somgen223.stanford.edu 13
0 Error in compute_sign5 ("abc") : Hey, x is not a number. if ( !is.numeric (x)) { stop ("Hey, x is not a number.") } if (x < 0) { -1 } else { if (x == 0) { compute_sign5 <- function (x) { } else { 1 } } } compute_sign5 ( - 2) [1] -1 compute_sign5 ("abc") compute_sign version 5 somgen223.stanford.edu 14
warning • warning prints a message, but the computation continues without interruption. somgen223.stanford.edu 15
} else { [1] 1 if ( !is.numeric (x)) { warning ("Hey, x is not a number.") } if (x < 0) { -1 } else { if (x == 0) { 0 compute_sign6 <- function (x) { 1 } } } compute_sign6 ( - 2) [1] -1 compute_sign6 ("abc") Warning in compute_sign6 ("abc") : Hey, x is not a number. compute_sign version 6 somgen223.stanford.edu 16
Assertions • Assertions are conditions that you expect to be true at a certain point in the code. • You can put if statements with stop to make sure that a condition is true, and cause an error if it is not true. • There are several R packages for writing assertions that make this kind of checking slightly easier. somgen223.stanford.edu 17
library (assertthat) x <- 2 assert_that (x > 0) [1] TRUE assert_that (x < 0) Error : x not less than 0 package assertthat • assert_that takes an expression, a test. • If it is TRUE then the function does nothing. • If it is FALSE then the function causes an error with a readable error message. • You can put assertions throughout your functions and scripts. somgen223.stanford.edu 18
compute_sign7 <- function (x) { assert_that ( is.numeric (x)) if (x < 0) { -1 } else { if (x == 0) { 0 } else { 1 } } } compute_sign7 ( - 2) [1] -1 compute_sign7 ("abc") Error : x is not a numeric or integer vector compute_sign version 7 somgen223.stanford.edu 19
Debugging somgen223.stanford.edu 20
Programs have bugs • All long, and many short, programs have bugs in them. • Nearly always an error is detected at some point after the initial mistake. Working backwards from the error message to the ultimate site of the error is an acquired skill. • Defensive programming uses assertions to make sure that data have the proper structure and values. (Eg, weight should be > 0 .) somgen223.stanford.edu 21
Using print for debugging in R • The simplest way to debug is to put print statements in your code, showing intermediate values. somgen223.stanford.edu 22
iris %>% as_tibble () %>% print () %>% filter (Petal.Length > 1.5) %>% print () Using print in a pipe • print does the printing, but also returns its argument as the result. somgen223.stanford.edu 23
library (magrittr) iris %>% ## note use of Tee pipe: %T>% as_tibble () %T>% View () %>% filter (Petal.Length > 1.5) %T>% View () Super fancy way using View • View does not return its argument as the result, so you need to work around that using the %T>% operator from the package magrittr . This does the function on the right, but then returns the value on the left. somgen223.stanford.edu 24
Debugging in RStudio • RStudio has some powerful and easy to use debugging features. • Download https://somgen223.stanford.edu/files/debug_demo.r • Then open that file in the script window. • (live demo in RStudio) somgen223.stanford.edu 25
How to set a breakpoint • Click in the left margin at the line where you want to pause execution. • Click again in the same place to remove the breakpoint. somgen223.stanford.edu 26
c Q Commands inside a breakpoint Command Action continue running code quit running variable name print value of variable somgen223.stanford.edu 27
Reading • Read: 19 Functions | R for Data Science (section 19.4 conditional execution) • Read: 19 Functions | R for Data Science (section 19.5.2 checking values) • Optional/advanced: Chapter 8 Testing and Error Handling | The Tidynomicon somgen223.stanford.edu 28
Recommend
More recommend