class: center, middle, inverse, title-slide # Logic in R ### Colin Rundel ### 2019-01-15 --- exclude: true --- class: middle count: false # (Almost) <br/> Everything is a Vector --- ## Vectors The fundamental building block of data in R are vectors (collections of related values, objects, other data structures, etc). -- <br/> R has two types of vectors: * **atomic** vectors - homogeneous collections of the *same* type (e.g. all logical values, all numbers, or all character strings). * **generic** vectors - heterogeneous collections of *any* type of R object, even other lists (meaning they can have a hierarchical/tree-like structure). --- ## Atomic Vectors R has six atomic vector types: <br/> .center[ `logical`, `double`, `integer`, `character`, `complex`, `raw` ] <br/> For today we'll mostly worry about the first type, we'll discuss the remainder over the next couple of lextures (note that the last two almost never come up). --- count: false class: middle # Conditionals --- ## Logical (boolean) operators | Operator | Operation | Vectorized? |:-----------------------------:|:-------------:|:------------: | <code>x | y</code> | or | Yes | `x & y` | and | Yes | `!x` | not | Yes | <code>x || y</code> | or | No | `x && y` | and | No |`xor(x,y)` | exclusive or | Yes --- ## Vectorized? ```r x = c(TRUE,FALSE,TRUE) y = c(FALSE,TRUE,TRUE) ``` .pull-left[ ```r x | y ``` ``` ## [1] TRUE TRUE TRUE ``` ```r x || y ``` ``` ## [1] TRUE ``` ] .pull-right[ ```r x & y ``` ``` ## [1] FALSE FALSE TRUE ``` ```r x && y ``` ``` ## [1] FALSE ``` ] --- ## Vectorization and arithmatic Almost all of the basic mathematical operations (and many other functions) in R are vectorized as well. .pull-left[ ```r c(1,2,3) + c(3,2,1) ``` ``` ## [1] 4 4 4 ``` ```r c(1,2,3) / c(3,2,1) ``` ``` ## [1] 0.3333333 1.0000000 3.0000000 ``` ] .pull-right[ ```r log(c(1, 3, 0)) ``` ``` ## [1] 0.000000 1.098612 -Inf ``` ```r sin(c(1,2,3)) ``` ``` ## [1] 0.8414710 0.9092974 0.1411200 ``` ] --- ## Length coercion ```r x = c(TRUE,FALSE,TRUE) y = c(TRUE) z = c(FALSE,TRUE) ``` -- .pull-left[ ```r x | y ``` ``` ## [1] TRUE TRUE TRUE ``` ```r x & y ``` ``` ## [1] TRUE FALSE TRUE ``` ] -- .pull-right[ ```r y | z ``` ``` ## [1] TRUE TRUE ``` ```r y & z ``` ``` ## [1] FALSE TRUE ``` ] -- ```r x | z ``` ``` ## Warning in x | z: longer object length is not a multiple of shorter object ## length ``` ``` ## [1] TRUE TRUE TRUE ``` --- ## Comparisons Operator | Comparison | Vectorized? :----------:|:--------------------------:|:----------------: `x < y` | less than | Yes `x > y` | greater than | Yes `x <= y` | less than or equal to | Yes `x >= y` | greater than or equal to | Yes `x != y` | not equal to | Yes `x == y` | equal to | Yes `x %in% y` | contains | Yes (over `x`) --- ## Comparisons ```r x = c("A","B","C") z = c("A") ``` .pull-left[ ```r x == z ``` ``` ## [1] TRUE FALSE FALSE ``` ```r x != z ``` ``` ## [1] FALSE TRUE TRUE ``` ```r x > z ``` ``` ## [1] FALSE TRUE TRUE ``` ] -- .pull-right[ ```r x %in% z ``` ``` ## [1] TRUE FALSE FALSE ``` ```r z %in% x ``` ``` ## [1] TRUE ``` ] --- ## Conditional Control Flow Conditional execution of code blocks is achieved via `if` statements. ```r x = c(1,3) ``` -- ```r if (3 %in% x) print("This!") ``` ``` ## [1] "This!" ``` -- ```r if (1 %in% x) print("That!") ``` ``` ## [1] "That!" ``` -- ```r if (5 %in% x) print("Other!") ``` --- ## `if` is not vectorized ```r x = c(1,3) ``` -- ```r if (x %in% 3) print("Now Here!") ``` ``` ## Warning in if (x %in% 3) print("Now Here!"): the condition has length > 1 and ## only the first element will be used ``` -- ```r if (x %in% 1) print("Now Here!") ``` ``` ## Warning in if (x %in% 1) print("Now Here!"): the condition has length > 1 and ## only the first element will be used ``` ``` ## [1] "Now Here!" ``` --- ## Collapsing logical vectors There are a couple of helper functions for collapsing a logical vector down to a single value: `any`, `all` ```r x = c(3,4,1) ``` .pull-left[ ```r x >= 2 ``` ``` ## [1] TRUE TRUE FALSE ``` ```r any(x >= 2) ``` ``` ## [1] TRUE ``` ```r all(x >= 2) ``` ``` ## [1] FALSE ``` ] .pull-right[ ```r x <= 4 ``` ``` ## [1] TRUE TRUE TRUE ``` ```r any(x <= 4) ``` ``` ## [1] TRUE ``` ```r all(x <= 4) ``` ``` ## [1] TRUE ``` ] --- ## Nesting Conditionals .pull-left[ ```r x = 3 if (x < 0) { "Negative" } else if (x > 0) { "Positive" } else { "Zero" } ``` ``` ## [1] "Positive" ``` ] .pull-right[ ```r x = 0 if (x < 0) { "Negative" } else if (x > 0) { "Positive" } else { "Zero" } ``` ``` ## [1] "Zero" ``` ] --- class: middle count: false # Error Checking --- ## `stop` and `stopifnot` Often we want to validate user input or function arguments - if our assumptions are not met then we often want to report the error and stop execution. ```r ok = FALSE if (!ok) stop("Things are not ok.") ``` ``` ## Error in eval(expr, envir, enclos): Things are not ok. ``` ```r stopifnot(ok) ``` ``` ## Error in eval(expr, envir, enclos): ok is not TRUE ``` *Note* - an error (like the one generated by `stop`) will prevent an RMarkdown document from compiling unless `error=TRUE` is set for that code chunk --- ## Style choices .pull-left[ Do stuff: ```r if (condition_one) { ## ## Do stuff ## } else if (condition_two) { ## ## Do other stuff ## } else if (condition_error) { stop("Condition error occured") } ``` ] .pull-right[ Do stuff (better): ```r # Do stuff better if (condition_error) { stop("Condition error occured") } if (condition_one) { ## ## Do stuff ## } else if (condition_two) { ## ## Do other stuff ## } ``` ] --- ## Exercise 1 Write a set of conditional(s) that satisfies the following requirements, * If `x` is greater than 3 and `y` is less than or equal to 3 then print "Hello world!" * Otherwise if `x` is greater than 3 print "!dlrow olleH" * If `x` is less than or equal to 3 then print "Something else ..." * Stop execution if x is odd and y is even and report an error, don't print any of the text strings above. Test out your code by trying various values of `x` and `y`. --- class: middle count: false # Loops --- ## `for` loops Simplest, and most common type of loop in R - given a vector iterate through the elements and evaluate the code block for each. ```r res = c() for(x in 1:10) { res = c(res, x^2) } res ``` ``` ## [1] 1 4 9 16 25 36 49 64 81 100 ``` -- ```r res = c() for(y in list(1:3, LETTERS[1:7], c(TRUE,FALSE))) { res = c(res, length(y)) } res ``` ``` ## [1] 3 7 2 ``` <br/> *Note* - the code above is terrible for several reasons, you should never write anything that looks like this --- ## `while` loops Repeat until the given condition is **not** met (i.e. evaluates to `FALSE`) ```r i = 1 res = rep(NA,10) while (i <= 10) { res[i] = i^2 i = i+1 } res ``` ``` ## [1] 1 4 9 16 25 36 49 64 81 100 ``` --- ## `repeat` loops Repeat until `break` ```r i = 1 res = rep(NA,10) repeat { res[i] = i^2 i = i+1 if (i > 10) break } res ``` ``` ## [1] 1 4 9 16 25 36 49 64 81 100 ``` --- class: split-50 ## Special keywords - `break` and `next` These are special actions that only work *inside* of a loop * `break` - ends the current *loop* (inner-most) * `next` - ends the current *iteration* .pull-left[ ```r res = c() for(i in 1:10) { if (i %% 2 == 0) break res = c(res, i) print(res) } ``` ``` ## [1] 1 ``` ] .pull-right[ ```r res = c() for(i in 1:10) { if (i %% 2 == 0) next res = c(res,i) print(res) } ``` ``` ## [1] 1 ## [1] 1 3 ## [1] 1 3 5 ## [1] 1 3 5 7 ## [1] 1 3 5 7 9 ``` ] --- ## Some helper functions Often we want to use a loop across the indexes of an object and not the elements themselves. There are several useful functions to help you do this: `:`, `length`, `seq`, `seq_along`, `seq_len`, etc. .pull-left[ ```r 4:7 ``` ``` ## [1] 4 5 6 7 ``` ```r length(4:7) ``` ``` ## [1] 4 ``` ```r seq(4,7) ``` ``` ## [1] 4 5 6 7 ``` ] .pull-right[ ```r seq_along(4:7) ``` ``` ## [1] 1 2 3 4 ``` ```r seq_len(length(4:7)) ``` ``` ## [1] 1 2 3 4 ``` ```r seq(4,7,by=2) ``` ``` ## [1] 4 6 ``` ] --- ## Exercise 2 Below is a vector containing all prime numbers between 2 and 100: .center[ ```r primes = c( 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97) ``` ] If you were given the vector `x = c(3,4,12,19,23,51,61,63,78)`, write the R code necessary to print only the values of `x` that are *not* prime (without using subsetting or the `%in%` operator). Your code should use *nested* loops to iterate through the vector of primes and `x`. --- count: false # Acknowledgments Above materials are derived in part from the following sources: * Hadley Wickham - [Advanced R](http://adv-r.had.co.nz/) * [R Language Definition](http://stat.ethz.ch/R-manual/R-devel/doc/manual/R-lang.html)