class: middle, inverse .leftcol30[ <center> <img src="https://github.com/emse-p4a-gwu/emse-p4a-gwu.github.io/raw/master/images/p4a_hex_sticker.png" width=250> </center> ] .rightcol70[ # Week 6: .fancy[Vectors] ###
EMSE 4571: Intro to Programming for Analytics ###
John Paul Helveston ###
February 23, 2023 ] --- class: inverse, middle # Week 6: .fancy[Vectors] ### 1. Making vectors ### 2. Vector operations ### 3. Comparing vectors ### BREAK ### 4. Slicing vectors ### 5. Lists --- class: inverse, middle # Week 6: .fancy[Vectors] ### 1. .orange[Making vectors] ### 2. Vector operations ### 3. Comparing vectors ### BREAK ### 4. Slicing vectors ### 5. Lists --- # We've already been using vectors! .code80[ ```r x <- 1 x ``` ``` #> [1] 1 ``` ] -- .code80[ ```r is.vector(x) ``` ``` #> [1] TRUE ``` ] -- .code80[ ```r length(x) ``` ``` #> [1] 1 ``` ] --- # The universal vector generator: `c()` -- .cols3[ ## Numeric vectors ```r x <- c(1, 2, 3) x ``` ``` #> [1] 1 2 3 ``` ] -- .cols3[ ## Character vectors ```r y <- c('a', 'b', 'c') y ``` ``` #> [1] "a" "b" "c" ``` ] -- .cols3[ ## Logical vectors ```r z <- c(TRUE, FALSE, TRUE) z ``` ``` #> [1] TRUE FALSE TRUE ``` ] --- # Elements in vectors must be the same type ### Type hierarchy: - `character` > `numeric` > `logical` - `double` > `integer` -- .cols3[ Coverts to characters: ```r c(1, "foo", TRUE) ``` ``` #> [1] "1" "foo" "TRUE" ``` ] -- .cols3[ Coverts to numbers: ```r c(7, TRUE, FALSE) ``` ``` #> [1] 7 1 0 ``` ] -- .cols3[ Coverts to double: ```r c(1L, as.integer(2), 3.14) ``` ``` #> [1] 1.00 2.00 3.14 ``` ] --- # Other ways to make a vector -- .leftcol[ Sequences (we saw these last week): ```r seq(1, 5) ``` ``` #> [1] 1 2 3 4 5 ``` ```r 1:5 ``` ``` #> [1] 1 2 3 4 5 ``` ] -- .rightcol[ Repeating a value: ```r rep(5, 3) ``` ``` #> [1] 5 5 5 ``` ```r rep("snarf", 3) ``` ``` #> [1] "snarf" "snarf" "snarf" ``` ] --- # Repeating a vector .leftcol[.code80[ Repeating a sequence ```r x <- rep(seq(1, 3), times = 3) x ``` ``` #> [1] 1 2 3 1 2 3 1 2 3 ``` ```r length(x) ``` ``` #> [1] 9 ``` ]] -- .rightcol[.code80[ Note what the `each` argument does: ```r x <- rep(seq(1, 3), each = 3) x ``` ``` #> [1] 1 1 1 2 2 2 3 3 3 ``` ```r length(x) ``` ``` #> [1] 9 ``` ]] --- # You can name vector elements ```r x <- seq(5) x ``` ``` #> [1] 1 2 3 4 5 ``` -- ```r names(x) ``` ``` #> NULL ``` --- # You can name vector elements ```r x <- seq(5) x ``` ``` #> [1] 1 2 3 4 5 ``` -- .leftcol[ 1) Add names with the `names()` function: ```r names(x) <- c('a', 'b', 'c', 'd', 'e') x ``` ``` #> a b c d e #> 1 2 3 4 5 ``` ] -- .rightcol[ 2) Create a named vector: ```r y <- c('a'=1, 'b'=2, 'c'=3, 'd'=4, 'e'=5) y ``` ``` #> a b c d e #> 1 2 3 4 5 ``` ] --- # Quick code tracing
02
:
00
.code80[ What will each of these lines produce? ```r rep(c(TRUE, FALSE, "TRUE"), 2) ``` ```r seq(FALSE, 3) ``` ```r rep(c(seq(3), seq(2)), each = 2) ``` ] --- class: inverse, middle # Week 6: .fancy[Vectors] ### 1. Making vectors ### 2. .orange[Vector operations] ### 3. Comparing vectors ### BREAK ### 4. Slicing vectors ### 5. Lists --- ## Math on vectors is done **by element** ```r x <- 1:10 ``` -- ```r x + 2 ``` ``` #> [1] 3 4 5 6 7 8 9 10 11 12 ``` -- ```r x - 2 ``` ``` #> [1] -1 0 1 2 3 4 5 6 7 8 ``` -- ```r x * 2 ``` ``` #> [1] 2 4 6 8 10 12 14 16 18 20 ``` -- ```r x / 2 ``` ``` #> [1] 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 ``` --- ## Math on vectors is done **by element** ```r x ``` ``` #> [1] 1 2 3 4 5 6 7 8 9 10 ``` ```r x %% 2 ``` ``` #> [1] 1 0 1 0 1 0 1 0 1 0 ``` --- ## Math on vectors is done **by element** -- ```r x1 <- c(1, 2, 3) x2 <- c(4, 5, 6) ``` -- ```r x1 + x2 # Returns (1+4, 2+5, 3+6) ``` ``` #> [1] 5 7 9 ``` -- ```r x1 - x2 # Returns (1-4, 2-5, 3-6) ``` ``` #> [1] -3 -3 -3 ``` -- ```r x1 * x2 # Returns (1*4, 2*5, 3*6) ``` ``` #> [1] 4 10 18 ``` -- ```r x1 / x2 # Returns (1/4, 2/5, 3/6) ``` ``` #> [1] 0.25 0.40 0.50 ``` --- # If dimensions don't match, R "wraps" the vector -- ```r x1 <- c(1, 2, 3, 4) x2 <- c(4, 5) ``` ```r x1 + x2 ``` -- ``` #> [1] 5 7 7 9 ``` -- ```r x1 <- c(1, 2, 3, 4) x2 <- c(1) ``` ```r x1 + x2 ``` -- ``` #> [1] 2 3 4 5 ``` --- # Most R functions work on vectors -- .leftcol[.code80[ ```r x <- c(3.1415, 1.618, 2.718) x ``` ``` #> [1] 3.1415 1.6180 2.7180 ``` ```r round(x, 2) ``` ``` #> [1] 3.14 1.62 2.72 ``` ```r sqrt(x) ``` ``` #> [1] 1.772428 1.272006 1.648636 ``` ]] -- .rightcol[.code80[ Works with your own functions too: ```r isEven <- function(x) { return((x %% 2) == 0) } ``` ```r x <- c(1, 4, 5, 10) isEven(x) ``` ``` #> [1] FALSE TRUE FALSE TRUE ``` ]] --- # Using vectors instead of a loop: **Summation** Example: Sum the integers from 1 to 10 -- .leftcol[.code80[ Summing with a loop: ```r x <- seq(1, 10) total <- 0 for (i in x) { total <- total + i } total ``` ``` #> [1] 55 ``` ]] -- .rightcol[.code80[ Use a _summary function_ on the vector: ```r sum(x) ``` ``` #> [1] 55 ``` ]] --- ## **Summary functions** return one value -- ```r x <- 1:10 ``` -- .leftcol[ ```r length(x) ``` ``` #> [1] 10 ``` ```r sum(x) ``` ``` #> [1] 55 ``` ```r prod(x) ``` ``` #> [1] 3628800 ``` ] -- .rightcol[ ```r min(x) ``` ``` #> [1] 1 ``` ```r max(x) ``` ``` #> [1] 10 ``` ```r mean(x) ``` ``` #> [1] 5.5 ``` ```r median(x) ``` ``` #> [1] 5.5 ``` ] --- # Quick code tracing
03
:
00
.leftcol[.code80[ Consider this function: ```r f <- function(x) { m <- x n <- sum(x + 4) m <- m + 5 return(c(m, n)) } ``` ]] .rightcol[.code80[ What will each of these lines return? ```r x <- c(1, 3) f(x) ``` ```r y <- c(TRUE, FALSE, 1) f(y) ``` ]] --- class: inverse, middle # Week 6: .fancy[Vectors] ### 1. Making vectors ### 2. Vector operations ### 3. .orange[Comparing vectors] ### BREAK ### 4. Slicing vectors ### 5. Lists --- # Comparing vectors Check if 2 vectors are the same: .code80[ ```r x <- c(1, 2, 3) y <- c(1, 2, 3) ``` ```r x == y ``` ] -- .code80[ ``` #> [1] TRUE TRUE TRUE ``` ] --- # Comparing vectors with `all()` and `any()` `all()`: Check if _all_ elements are the same -- .leftcol[.code80[ ```r x <- c(1, 2, 3) y <- c(1, 2, 3) x == y ``` ``` #> [1] TRUE TRUE TRUE ``` ```r all(x == y) ``` ``` #> [1] TRUE ``` ]] -- .rightcol[.code80[ ```r x <- c(1, 2, 3) y <- c(-1, 2, 3) x == y ``` ``` #> [1] FALSE TRUE TRUE ``` ```r all(x == y) ``` ``` #> [1] FALSE ``` ]] --- # Comparing vectors with `all()` and `any()` `any()`: Check if _any_ elements are the same -- .leftcol[.code80[ ```r x <- c(1, 2, 3) y <- c(1, 2, 3) x == y ``` ``` #> [1] TRUE TRUE TRUE ``` ```r any(x == y) ``` ``` #> [1] TRUE ``` ]] -- .rightcol[.code80[ ```r x <- c(1, 2, 3) y <- c(-1, 2, 3) x == y ``` ``` #> [1] FALSE TRUE TRUE ``` ```r any(x == y) ``` ``` #> [1] TRUE ``` ]] --- # `all()` vs. `identical()` -- .code80[ ```r x <- c(1, 2, 3) y <- c(1, 2, 3) names(x) <- c('a', 'b', 'c') names(y) <- c('one', 'two', 'three') ``` ] -- .leftcol[.code80[ `all()` only compares the element _values_: ```r all(x == y) ``` ``` #> [1] TRUE ``` ]] -- .rightcol[.code80[ `identical()` compares _values_ and _names_: ```r identical(x, y) ``` ``` #> [1] FALSE ``` ```r names(y) <- c('a', 'b', 'c') identical(x, y) ``` ``` #> [1] TRUE ``` ]] --- class: inverse
10
:
00
## Your turn Re-write `isPrime(n)` from last week, but **without loops!**. Remember, `isPrime(n)` takes a non-negative integer, `n`, and returns `TRUE` if it is a prime number and `FALSE` otherwise. Here are some test cases: - `isPrime(1) == FALSE` - `isPrime(2) == TRUE` - `isPrime(7) == TRUE` - `isPrime(13) == TRUE` - `isPrime(14) == FALSE` (If you're stuck, go to the next slide for a hint) --- class: inverse ## Hint Loop solution: .code80[ ```r isPrime <- function(n) { if (n <= 1) { return(FALSE) } if (n == 2) { return(TRUE) } for (i in seq(2, (n - 1))) { if ((n %% i) == 0) { return(FALSE) } } return(TRUE) } ``` ] --- class: inverse, center # .fancy[Break]
05
:
00
--- class: inverse, middle # Week 6: .fancy[Vectors] ### 1. Making vectors ### 2. Vector operations ### 3. Comparing vectors ### BREAK ### 4. .orange[Slicing vectors] ### 5. Lists --- # Use brackets `[]` to get elements from a vector ```r x <- seq(1, 10) ``` -- .leftcol[ Indices start at 1: ```r x[1] # Returns the first element ``` ``` #> [1] 1 ``` ```r x[3] # Returns the third element ``` ``` #> [1] 3 ``` ```r x[length(x)] # Returns the last element ``` ``` #> [1] 10 ``` ] -- .rightcol[ Slicing with a vector of indices: ```r x[1:3] # Returns the first three elements ``` ``` #> [1] 1 2 3 ``` ```r x[c(2, 7)] # Returns the 2nd and 7th elements ``` ``` #> [1] 2 7 ``` ] --- # Use negative integers to _remove_ elements ```r x <- seq(1, 10) ``` -- ```r x[-1] # Drops the first element ``` ``` #> [1] 2 3 4 5 6 7 8 9 10 ``` -- ```r x[-1:-3] # Drops the first three elements ``` ``` #> [1] 4 5 6 7 8 9 10 ``` -- ```r x[-c(2, 7)] # Drops the 2nd and 7th elements ``` ``` #> [1] 1 3 4 5 6 8 9 10 ``` -- ```r x[-length(x)] # Drops the last element ``` ``` #> [1] 1 2 3 4 5 6 7 8 9 ``` --- # Slicing with logical indices -- ```r x <- seq(1, 20, 3) x ``` ``` #> [1] 1 4 7 10 13 16 19 ``` -- Create a logical vector based on some condition: ```r x > 10 ``` ``` #> [1] FALSE FALSE FALSE FALSE TRUE TRUE TRUE ``` -- Slice `x` with logical vector - only `TRUE` indices will be returned: ```r x[x > 10] ``` ``` #> [1] 13 16 19 ``` --- # You can also use `which()` to find indices ```r x <- seq(1, 20, 3) x ``` ``` #> [1] 1 4 7 10 13 16 19 ``` -- Use `which()` around a condition to get the indices where condition is `TRUE`: ```r which(x > 10) ``` ``` #> [1] 5 6 7 ``` -- ```r x[which(x > 10)] ``` ``` #> [1] 13 16 19 ``` --- # Using names to slice a vector ```r names(x) <- c('a', 'b', 'c', 'd', 'e', 'f', 'g') x ``` ``` #> a b c d e f g #> 1 4 7 10 13 16 19 ``` -- ```r x['a'] ``` ``` #> a #> 1 ``` -- ```r x[c('a', 'c')] ``` ``` #> a c #> 1 7 ``` --- # Sorting vectors with `sort()` -- ```r a = c(2, 4, 6, 3, 1, 5) a ``` ``` #> [1] 2 4 6 3 1 5 ``` -- ```r sort(a) ``` ``` #> [1] 1 2 3 4 5 6 ``` -- ```r sort(a, decreasing = TRUE) ``` ``` #> [1] 6 5 4 3 2 1 ``` --- ## `order()` returns the indices of the sorted vector ```r a ``` ``` #> [1] 2 4 6 3 1 5 ``` ```r order(a) ``` ``` #> [1] 5 1 4 2 6 3 ``` -- This does the same thing as `sort(a)`: ```r a[order(a)] ``` ``` #> [1] 1 2 3 4 5 6 ``` --- # Look for membership with `%in%` ```r cities <- c("atlanta", "dc", "nyc", "sf") cities ``` ``` #> [1] "atlanta" "dc" "nyc" "sf" ``` -- ```r "chicago" %in% cities ``` ``` #> [1] FALSE ``` -- ```r "dc" %in% cities ``` ``` #> [1] TRUE ``` --- # Quick code tracing
02
:
00
.leftcol[.code80[ Consider this function: ```r f <- function(x) { for (i in seq(length(x))) { x[i] <- x[i] + sum(x) + max(x) } return(x) } ``` ]] .rightcol[.code80[ What will this code return? ```r x <- c(1, 2, 3) f(x) ``` ]] --- class: inverse
15
:
00
## Your turn .font80[ 1) `reverse(x)`: Write a function that returns the vector in reverse order. You cannot use the `rev()` function. - `all(reverseVector(c(5, 1, 3)) == c(3, 1, 5))` - `all(reverseVector(c('a', 'b', 'c')) == c('c', 'b', 'a'))` - `all(reverseVector(c(FALSE, TRUE, TRUE)) == c(TRUE, TRUE, FALSE))` 2) `alternatingSum(a)`: Write a function that takes a vector of numbers `a` and returns the alternating sum, where the sign alternates from positive to negative or vice versa. - `alternatingSum(c(5,3,8,4)) == (5 - 3 + 8 - 4)` - `alternatingSum(c(1,2,3)) == (1 - 2 + 3)` - `alternatingSum(c(0,0,0)) == 0` - `alternatingSum(c(-7,5,3)) == (-7 - 5 + 3)` **Challenge**: For each function, try writing a solution that uses loops and another that only uses vectors. ] --- class: inverse, middle # Week 6: .fancy[Vectors] ### 1. Making vectors ### 2. Vector operations ### 3. Comparing vectors ### BREAK ### 4. Slicing vectors ### 5. .orange[Lists] --- # Elements in lists can be any object -- .leftcol[.code80[ Vectors force things to one type: ```r c(1, "foo", TRUE) ``` ``` #> [1] "1" "foo" "TRUE" ``` ]] -- .rightcol[.code80[ Lists store any type: ```r list(1, "foo", TRUE) ``` ``` #> [[1]] #> [1] 1 #> #> [[2]] #> [1] "foo" #> #> [[3]] #> [1] TRUE ``` ]] --- ## .center[Subsetting lists] <center> <img src="list-train.png" width=900> </center> .font87[source: https://shannonpileggi.github.io/iterating-well-with-purrr/#/subsetting-lists] --- # Slice list with indices or names .leftcol[.code80[ Slice with index using `[[]]` ```r x <- list( c(1, 2, 3), c("foo", "bar"), TRUE ) ``` ```r x[[1]] ``` ``` #> [1] 1 2 3 ``` ```r x[[2]] ``` ``` #> [1] "foo" "bar" ``` ]] -- .rightcol[.code80[ Slice with name using ``[[]]` or `$` ```r x <- list( numbers = c(1, 2, 3), chars = c("foo", "bar"), logical = TRUE ) ``` ```r x[['numbers']] ``` ``` #> [1] 1 2 3 ``` ```r x$numbers ``` ``` #> [1] 1 2 3 ``` ]] --- # [HW 6](https://p4a.seas.gwu.edu/2023-Spring/hw/6-vectors.html) -- - Next week is Quiz 4 - the last quiz before the midterm. -- - Midterm is during class period on 3/9.