class: center, middle, inverse, title-slide # R preliminaries ### Mikhail Dozmorov ### Virginia Commonwealth University ### 09-01-2021 --- ## Summary statistics - Simple statistical functions: `count()`, `min()`, `max()`, `mean()`, `median()`, `sd()`, `cor()`, `summary()`, `quantile()`) - These, and many other functions, have settings to properly handle NAs, e.g., `mean(x, na.rm = FALSE, ...)` - `complete.cases()` on a matrix/data frame returns row-wise logical with TRUE for rows without NAs - `unique()` - unique elements in a vector. Combine with `length()` to get the number of unique elements - `table()` - contingency table for a vector (the number of elements per unique level) --- ## Summary statistics ```r data(mtcars) # simple summary # ?mtcars head(mtcars) ``` ``` ## mpg cyl disp hp drat wt qsec vs am gear carb ## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 ## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 ## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 ## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 ## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 ## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 ``` ```r mean(mtcars$mpg) # Try median, sd, var, min, max ``` ``` ## [1] 20.09062 ``` ```r summary(mtcars$mpg) ``` ``` ## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 10.40 15.43 19.20 20.09 22.80 33.90 ``` --- ## Summary statistics ```r quantile(mtcars$mpg, probs = c(.20, .80)) ``` ``` ## 20% 80% ## 15.20 24.08 ``` ```r cor(mtcars$mpg, mtcars$hp) # sample correlation coeficient ``` ``` ## [1] -0.7761684 ``` ```r table(mtcars$cyl) ``` ``` ## ## 4 6 8 ## 11 7 14 ``` ```r table(mtcars$cyl)/length(mtcars$cyl) # normalized by the total number of observations = 32 ``` ``` ## ## 4 6 8 ## 0.34375 0.21875 0.43750 ``` --- ## Control structures inside R/functions - `if, else` - `for` - `while` - `repeat` - `break` - `next` --- ## If-else statement Conditional code execution ``` r if (condition) { # do something } else { # do something else } ``` - `==`: Equal to - `!=`: Not equal to - `>`, `>=`: Greater than, greater than or equal to - `<`, `<=`: Less than, less than or equal to ```r x <- 1:15 if (sample(x, 1) <= 10) { print("x is less than 10") } else { print("x is greater than 10") } ``` ``` ## [1] "x is less than 10" ``` --- ## For loop Repetitive code execution ```r for (i in 1:5) { cat(i) } ``` ``` ## 12345 ``` Compare with ```r for (i in 1:5) { print(i) } ``` ``` ## [1] 1 ## [1] 2 ## [1] 3 ## [1] 4 ## [1] 5 ``` --- ## More uses of For loops ```r x <- c("apples", "oranges", "bananas", "strawberries") for (i in x) { cat(i); cat(" ") } ``` ``` ## apples oranges bananas strawberries ``` ```r for (i in 1:4) { cat(x[i]); cat(" ") } ``` ``` ## apples oranges bananas strawberries ``` ```r for (i in seq(x)) { cat(x[i]); cat(" ") } ``` ``` ## apples oranges bananas strawberries ``` --- ## Nested For loops ```r m <- matrix(1:10, 2) m ``` ``` ## [,1] [,2] [,3] [,4] [,5] ## [1,] 1 3 5 7 9 ## [2,] 2 4 6 8 10 ``` ```r for (i in seq(nrow(m))) { for (j in seq(ncol(m))) { print(m[i, j]) } } ``` ``` ## [1] 1 ## [1] 3 ## [1] 5 ## [1] 7 ## [1] 9 ## [1] 2 ## [1] 4 ## [1] 6 ## [1] 8 ## [1] 10 ``` --- ## while, repeat loops ```r i <- 1 while (i < 10) { print(i) i <- i + 1 } # Be sure there is a way to exit out of a while loop ``` ``` ## [1] 1 ## [1] 2 ## [1] 3 ## [1] 4 ## [1] 5 ## [1] 6 ## [1] 7 ## [1] 8 ## [1] 9 ``` ``` r repeat { # simulations; generate some value have an expectation if within some range, # then exit the loop if ((value - expectation) <= threshold) { break } } ``` --- ## Combine any statements/functions ```r for (i in 1:20) { if (i%%2 == 1) { next # skip printing over odd numbers } else { print(i) } } ``` ``` ## [1] 2 ## [1] 4 ## [1] 6 ## [1] 8 ## [1] 10 ## [1] 12 ## [1] 14 ## [1] 16 ## [1] 18 ## [1] 20 ``` --- ## Vectorized operation Many operations in R are already vectorized, making code more efficient, concise, and easier to read ```r x <- 1:4; y <- 6:9 x ``` ``` ## [1] 1 2 3 4 ``` ```r y ``` ``` ## [1] 6 7 8 9 ``` ```r x * y ``` ``` ## [1] 6 14 24 36 ``` ```r x / y ``` ``` ## [1] 0.1666667 0.2857143 0.3750000 0.4444444 ``` --- ## Manipulating vectors ```r ages <- c(40, 50, 60, 70, 80) # add a value to end of vector ages <- c(ages, 90) # add value at the beginning ages <- c(30, ages) # extracting second value ages[2] ``` ``` ## [1] 40 ``` ```r # excluding second value ages[-2] ``` ``` ## [1] 30 50 60 70 80 90 ``` ```r # extracting first and third values ages[c(1, 3)] ``` ``` ## [1] 30 50 ``` --- ## `apply` family of functions Writing for, while loops in R are inefficient, and we want to vectorize computation in R. - `apply()` - apply a function over the margins of an array - `lapply()` - loop over a list and evaluate a function on each element - `sapply()` - same as lapply but try to simplify results, if the result is a list where every element is length 1, then a vector is returned - `mapply()` - multivariate version of lapply - `tapply()` - apply a function over subsets of a vector --- ## apply examples ```r x <- 1:4 lapply(x, runif) ``` ``` ## [[1]] ## [1] 0.6999571 ## ## [[2]] ## [1] 0.7955854 0.4125683 ## ## [[3]] ## [1] 0.2328673 0.8489271 0.3013256 ## ## [[4]] ## [1] 0.5576035 0.6193335 0.9416713 0.5645791 ``` ```r x <- list(a = 1:4, b = rnorm(10), c = rnorm(20, 1)) sapply(x, mean) ``` ``` ## a b c ## 2.5000000 -0.1032136 1.0378142 ``` --- ## apply examples ```r #If the result is a list where every element is a vector of the same length (> 1), a matrix is returned. x <- list(rnorm(100), runif(100), rpois(100, 1)) sapply(x, quantile, probs = c(0.25, 0.75)) ``` ``` ## [,1] [,2] [,3] ## 25% -0.8106229 0.2163873 0 ## 75% 0.5144180 0.6999420 1 ``` ```r x <- matrix(rnorm(200), 20, 10) apply(x, 1, sum) ``` ``` ## [1] 4.9116667 2.1055798 -3.8914536 -3.4788586 -5.3450159 -1.4163235 ## [7] -2.3220034 -0.8991211 2.4337448 1.6838857 -1.6034605 -0.8034428 ## [13] -4.3773092 1.2695287 2.1041034 -0.3162727 -2.9455331 -0.7074898 ## [19] -6.5179255 -2.5579397 ``` ```r apply(x, 2, mean) ``` ``` ## [1] 0.24533466 0.02261196 -0.32187919 -0.31931651 0.11146099 -0.07918584 ## [7] -0.71896407 0.02902220 -0.13657525 0.03380904 ``` --- ## apply examples For sums and means of matrix dimensions, we have some shortcuts ```r rowSums = apply(x, 1, sum) rowMeans = apply(x, 1, mean) colSums = apply(x, 2, sum) colMeans = apply(x, 2, mean) ``` Check `?rowSums` help on these base R functions --- ## tapply Apply a function to each cell of a ragged array, that is, to each (non-empty) group of values given by a unique combination of the levels of certain factors. ``` r function (X, INDEX, FUN = NULL, ..., default = NA, simplify = TRUE) X is a vector INDEX is a factor or a list of factors (or else they are coerced to factors) FUN is a function to be applied ... contains other arguments to be passed FUN simplify, should we simplify the result? ``` ```r x <- c(rnorm(10), runif(10), rnorm(10, 1)) f <- gl(3, 10) tapply(x, f, mean) ``` ``` ## 1 2 3 ## 0.04389055 0.44173130 0.59684233 ``` --- ## mapply .panelset[ .panel[.panel-name[mapply] mapply is a multivariate version of sapply. mapply applies FUN to the first elements of each ... argument, the second elements, the third elements, and so on. Arguments are recycled if necessary. ``` r function (FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE) FUN is a function to apply ... contains arguments to apply over MoreArgs is a list of other arguments to FUN. SIMPLIFY indicates whether the result should be simplified ``` ] .panel[.panel-name[Example 1] ```r mapply(rep, 1:4, 4:1) ``` ``` ## [[1]] ## [1] 1 1 1 1 ## ## [[2]] ## [1] 2 2 2 ## ## [[3]] ## [1] 3 3 ## ## [[4]] ## [1] 4 ``` ] .panel[.panel-name[Example 1] ```r mapply(rnorm, mean = 1:3, sd = 1:3, n = seq(5, 15, by = 5)) ``` ``` ## [[1]] ## [1] 2.1558090 2.4309716 0.6884657 3.1994954 2.9252681 ## ## [[2]] ## [1] 4.7301836 2.3093369 2.3742895 2.4623988 0.4974263 1.4877722 ## [7] 2.1168063 -0.3330924 4.7041323 2.0338169 ## ## [[3]] ## [1] -1.1829592 4.6160085 2.3367599 -1.3558627 7.2952608 1.0622329 ## [7] 0.5689258 4.1001359 -0.2127514 6.0450216 8.8583073 0.2490650 ## [13] 2.9993432 2.3854606 6.1836488 ``` ] ] --- ## Formatting ```r round(c(3.14159, 2.71828), digits = 2) ``` ``` ## [1] 3.14 2.72 ``` ```r formatC(c(3.14159, 2.71828), digits = 2, format = "e") ``` ``` ## [1] "3.14e+00" "2.72e+00" ``` --- ## Handling NAs - NAs create problems in calculations. Many functions have built-in mechanism to handle NAs. Check `?mean` and the 'na.rm' argument - Check for presence of NAs in your data using `is.na()` ```r vec_with_NAs <- c(1, 2, NA, 3) sum(is.na(vec_with_NAs)) ``` ``` ## [1] 1 ``` - Remove all **rows** containing NAs from a data frame ```r dat <- dat[complete.cases(dat), ] ``` --- ## Modifying vector elements .can-edit[ ```r a <- c("Heineken", "Tuborg", "Carlsberg") paste("Beer", a) ``` ``` ## [1] "Beer Heineken" "Beer Tuborg" "Beer Carlsberg" ``` ```r paste("Beer", a, sep = ":") ``` ``` ## [1] "Beer:Heineken" "Beer:Tuborg" "Beer:Carlsberg" ``` ```r paste("Beer", a, collapse = ":") ``` ``` ## [1] "Beer Heineken:Beer Tuborg:Beer Carlsberg" ``` ```r paste0("e", "yes") ``` ``` ## [1] "eyes" ``` ] --- ## Modifying vector elements ```r a <- c("but", "cut") sub("u", "a", a) ``` ``` ## [1] "bat" "cat" ``` ```r a <- c("Column.1", "Column.2") strsplit(a, ".", fixed = TRUE) ``` ``` ## [[1]] ## [1] "Column" "1" ## ## [[2]] ## [1] "Column" "2" ``` ```r sapply(a, function(x) strsplit(x, ".", fixed = TRUE)[[1]][2]) ``` ``` ## Column.1 Column.2 ## "1" "2" ```