class: center, middle, inverse, title-slide .title[ # R preliminaries ] .author[ ### Mikhail Dozmorov ] .institute[ ### Virginia Commonwealth University ] .date[ ### 08-28-2023 ] --- ## Summary statistics - Simple statistical functions: `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.6613988 ## ## [[2]] ## [1] 0.7809725 0.2890047 ## ## [[3]] ## [1] 0.9750386 0.9126572 0.4426588 ## ## [[4]] ## [1] 0.1371049 0.2131381 0.3631762 0.8391314 ``` ```r x <- list(a = 1:4, b = rnorm(10), c = rnorm(20, 1)) sapply(x, mean) ``` ``` ## a b c ## 2.5000000 0.4316981 0.6425093 ``` --- ## 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.5465604 0.2169192 0 ## 75% 0.6352082 0.6831800 2 ``` ```r x <- matrix(rnorm(200), 20, 10) apply(x, 1, sum) ``` ``` ## [1] -0.5304079 -0.5972037 -2.6606938 -2.8838408 0.3941003 -0.3717785 ## [7] -3.8409864 3.3026504 -5.8593790 -0.5654725 1.8405664 -2.0142336 ## [13] 2.0206328 -1.9921137 -1.1564908 -3.3804654 -4.0912262 0.1128053 ## [19] 0.1191976 -2.1736937 ``` ```r apply(x, 2, mean) ``` ``` ## [1] -0.22342942 0.26504695 -0.58887644 -0.34120457 -0.02643448 0.03422735 ## [7] -0.02478491 -0.15240669 -0.22655298 0.06801352 ``` --- ## 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 groups of values of an array defined by 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.6875886 0.5938185 0.9211019 ``` --- ## 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 ``` rep(x, length.out) ] .panel[.panel-name[Example 1] ```r mapply(rnorm, mean = 1:3, sd = 1:3, n = seq(5, 15, by = 5)) ``` ``` ## [[1]] ## [1] 0.3422626 0.3375575 -0.9865531 0.4915086 0.9007827 ## ## [[2]] ## [1] 1.2504410 3.8809501 0.2990560 2.4667924 0.5507652 1.9903515 ## [7] 1.0849272 2.8690489 -0.3300034 -0.3856289 ## ## [[3]] ## [1] 6.1515942 3.9837128 3.7742747 7.3690374 1.9206400 -2.5673208 ## [7] -0.3241062 7.5153275 -1.8900841 1.6612903 7.8748812 2.7873671 ## [13] 9.5156158 3.5991790 2.8167600 ``` rnorm(n, mean = 0, sd = 1) ] ] --- ## 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" ``` `stringr` - functions for string manipulations https://stringr.tidyverse.org/