class: center, middle, inverse, title-slide # R-Ladies NL Book-Club ## Advanced R: Vectors (Chapter 3) ### Paloma ### 2020-05-11 --- ## Welcome! - This is collaborative effort between RLadies Nijmengen, Rotterdam, Den Bosch and Amsterdam. -- - We meet every 2 weeks to go through a chapter -- - Use the HackMD to present yourself, ask questions and see your breakout room -- - We split in breakout rooms after the presentation, and we return to the main jitsi link after 30 min. -- - Sign up to present a chapter at https://rladiesnl.github.io/book_club/ -- - https://advanced-r-solutions.rbind.io/ has some anwers and we could PR the ones missing. - The R4DS book club repo has a Q&A section.https://github.com/r4ds/bookclub-Advanced_R --- name: title class: center, middle ## Vectors ## --- ## Outline - Atomic vectors - Attributes: names, dimensions, class - Atomic vectors with special attributes (S3 atomic vectors) - Lists - Data frames and tibbles --- ## Atomic vectors .pull-left[ - Vectors can be atomic and lists. - **Atomic** vectors: all elements must have the same type. - **Lists** can have different types. - `NULL` serves as a generic zero ] .pull-right[<img src="https://d33wubrfki0l68.cloudfront.net/2ff3a6cebf1bb80abb2a814ae1cfc67b12817713/ae848/diagrams/vectors/summary-tree.png" width="400" >] --- ### Atomic vectors: Scalars .pull-left[ - Each type has a special sintax to create an individual value, AKA **scalar** - Logicals: `TRUE`, `FALSE` - Doubles: Can be decimals (`0.1234`), scientific (`1.23e4`) or hexadecimal (`0xcafe`), plus special values as `Inf`, `-Inf`, and `NaN` (Not a number.) - Integers: are followed by `L` - Strings are surrounded by `""` or `''` ] .pull-right[ <img src="https://d33wubrfki0l68.cloudfront.net/eb6730b841e32292d9ff36b33a590e24b6221f43/57192/diagrams/vectors/summary-tree-atomic.png" width="400"> ] --- ### Atomic vectors: longer vectors **Combine** = c() ```r lgl_var <- c(TRUE, FALSE) int_var <- c(1L, 6L, 10L) dbl_var <- c(1, 2.5, 4.5) chr_var <- c("these are", "some strings") ``` If input are atomic vectors, `c()` creates another atomic vector ```r c(c(1, 2), c(3, 4)) ``` ``` ## [1] 1 2 3 4 ``` --- <br><br><br> .pull-left[ `typeof()` ```r typeof(lgl_var) ``` ``` ## [1] "logical" ``` `length()` ```r length(int_var) ``` ``` ## [1] 3 ``` ] <br> .pull-right[<img src="https://d33wubrfki0l68.cloudfront.net/8a3d360c80da1186b1373a0ff0ddf7803b96e20d/254c6/diagrams/vectors/atomic.png" width="400">] --- ### Atomic vectors: Missing values - R represents missing values as `NA`: **Not applicable** .pull-left[ Operations with NA tend to return NAs ```r NA > 5 10 * NA !NA ``` ``` ## [1] NA ## [1] NA ## [1] NA ``` ] -- .pull-right[ A few exceptions ```r NA ^0 NA | TRUE NA & FALSE ``` ``` ## [1] 1 ## [1] TRUE ## [1] FALSE ``` ] --- ### Atomic vectors: Missing values .pull-left[ Propagation of missingness leads to a common mistake ```r x <- c(NA, 5, NA, 10) x == NA ``` ``` ## [1] NA NA NA NA ``` ] -- .pull-right[ Use `is.na()` to test for missingness ```r is.na(x) ``` ``` ## [1] TRUE FALSE TRUE FALSE ``` ] There are four types of missing values: `NA` (logical), `NA_integer_`, `NA_real` (double), `NA_character` --- ### Atomic vectors: Testing and coercion - `is*()` functions to test if a vector is of that type. ```r is.integer(x) is.double(x) ``` ``` ## [1] FALSE ## [1] TRUE ``` - Avoid `is.vector()`, `is.atomic()`, `is.numeric()`. --- Since **atomic vector** needs **elements** of the same **type**, when we combine different types they are coerced in a fixed order: .center[character -> double -> integer -> logical] ```r str(c("a", 1)) ``` ``` ## chr [1:2] "a" "1" ``` -- Use `as.*()` to deliberately coerce. Failing to coerce creates `NA` ```r as.numeric(c(FALSE, FALSE, TRUE)) ``` ``` ## [1] 0 0 1 ``` .pull-left[ ```r as.integer(c("1", "1.5", "a")) ``` ``` ## Warning: NAs introduced by coercion ``` ``` ## [1] 1 1 NA ``` ] .pull-right[ ```r readr::parse_double(c("1", "1.5", "a")) ``` ``` ## Warning: 1 parsing failure. ## row col expected actual ## 3 -- a double a ``` ``` ## [1] 1.0 1.5 NA ## attr(,"problems") ## # A tibble: 1 x 4 ## row col expected actual ## <int> <int> <chr> <chr> ## 1 3 NA a double a ``` ] --- ## Attributes Matrices, arrays, factors or date-times are types of vectors that have attributes built on top of atomic vectors. Name-value pairs of metadata to an object. ```r x <- 'a' attr(x, 'what') <- 'apple' attr(x, "what") ``` ``` ## [1] "apple" ``` --- <br><br> .pull-left[ Get and set multiple attributes with `attributes()` and `structure()` ```r x <- structure('a', what = 'apple', type = 'fruit') attributes(x) ``` ``` ## $what ## [1] "apple" ## ## $type ## [1] "fruit" ``` With the exception of `names()` and `dim()`, most attributes are lost with calculations ] .pull-right[ <br><br><br> .center[<img src="https://d33wubrfki0l68.cloudfront.net/b4d4a33fddf808901c156bb7596b07823fda3da2/9825b/diagrams/vectors/attr.png" width="194"> ]] --- ### Attributes: `names` Names, a character vector giving each element a name .pull-left[ ```r x <- c(apple = 'a', banana = 'b') # 1 x y <- c('a', 'b') names(y) <- c('apple', 'banana') # 2 y setNames(y, c('apple', 'banana')) # 3 ``` ``` ## apple banana ## "a" "b" ## apple banana ## "a" "b" ## apple banana ## "a" "b" ``` ] .pull-right[ <img src="https://d33wubrfki0l68.cloudfront.net/4bf745126ec2e29d138bce87337060b69f9c3ac1/34a00/diagrams/vectors/attr-names-1.png" width="246"> ] --- ### Attributes: `dim` `Dim` attribute to a vector allows it to behave like a 2-dimensional matrix or a multi-dimensional array. .pull-left[ ```r a <- matrix(1:6, nrow = 2, ncol = 3) a ``` ``` ## [,1] [,2] [,3] ## [1,] 1 3 5 ## [2,] 2 4 6 ``` ```r b <- array(1:6, dim = c(1, 3, 2)) b ``` ``` ## , , 1 ## ## [,1] [,2] [,3] ## [1,] 1 2 3 ## ## , , 2 ## ## [,1] [,2] [,3] ## [1,] 4 5 6 ``` ] .pull-right[ + 1-d vector without a `dim` attribute has `NULL` dimension + Matrices and arrays can be a single column or row vector ] --- ## S3 atomic vectors .pull-left[ An object with a **class** attribute **S3 object** It behaves different from a regular vecture when passed through **generic** functions Usually store additional information Now we will see: - `factor` (categorical) - `Date` (Date) - `POSIXct` (date-time) - `duration` (difftime). ] .pull-right[ <img src="https://d33wubrfki0l68.cloudfront.net/baa19d0ebf9b97949a7ad259b29a1c4ae031c8e2/8e9b8/diagrams/vectors/summary-tree-s3-1.png" width="298" style="display: block; margin: auto;"> ] --- ### S3 atomic vectors: Factors - Vector that can only contain pre-defined value, used to store categorical data. <img src="https://d33wubrfki0l68.cloudfront.net/1c19eabc59d445cab78fc605053c7393ec630e15/5843b/diagrams/vectors/factor.png" width="246" style="display: block; margin: auto;"> - Built on top of integers, not characters, has two attributes: `class` and `levels` ```r fruits <- factor(c('banana', 'apple', 'orange', 'apple')) ``` .pull-left[ ```r fruits typeof(fruits) ``` ``` ## [1] banana apple orange apple ## Levels: apple banana orange ## [1] "integer" ``` ] .pull-right[ ```r attributes(fruits) ``` ``` ## $levels ## [1] "apple" "banana" "orange" ## ## $class ## [1] "factor" ``` ] --- ### S3 atomic vectors: Factors .pull-left[ Factors give counts of all categories, even unobserved ones ```r sex_char <- c("m", "m", "m") sex_factor <- factor( sex_char, levels = c("m", "f")) table(sex_char) table(sex_factor) ``` ``` ## sex_char ## m ## 3 ## sex_factor ## m f ## 3 0 ``` ] -- .pull-right[ **Ordered** factors: the order of the levels is meaningful. ```r x <- ordered( c('two', 'three', 'one'), levels = c('one', 'two', 'three')) x ``` ``` ## [1] two three one ## Levels: one < two < three ``` ] --- ### S3 atomic vectors: Factors - In base R, `read.csv` and `data.frame` automatically converted character vectors to factors. - This is suboptimal: use `stringsAsFactors = FALSE`. - Since they are built in integers, be carefull to treat them as strings. - `gsub()` and `grepl` coerce factors to strings. - [Interesting story about `stringsAsFactors`](https://simplystatistics.org/2015/07/24/stringsasfactors-an-unauthorized-biography/) --- ### S3 atomic vectors: Date All built on top of doubles Dates have `class = "Date"` ```r today <- Sys.Date() typeof(today) attributes(today) ``` ``` ## [1] "double" ## $class ## [1] "Date" ``` Represents: days since Jan. 1, 1970 ```r date <- as.Date("1970-02-01") unclass(date) ``` ``` ## [1] 31 ``` --- ### S3 atomic vectors: POSIXct, duration POSI: Portable Operating System Interface ct: calendar time / it: local time POSIXct: Seconds since Jan. 1, 1970 ```r now_ct <- as.POSIXct("2018-08-01 22:00", tz = "UTC") now_ct typeof(now_ct) attributes(now_ct) ``` ``` ## [1] "2018-08-01 22:00:00 UTC" ## [1] "double" ## $class ## [1] "POSIXct" "POSIXt" ## ## $tzone ## [1] "UTC" ``` `tzone` only changes format, not the instant time represented by a vector. --- ### S3 atomic vectors: duration Represent the amount of time between paris of dates or date-times Are built on top of doubles, have a `units` attribute that determines how the integer should be interpreted. ```r week <- as.difftime(8, units = "weeks") week ``` ``` ## Time difference of 8 weeks ``` ```r typeof(week) ``` ``` ## [1] "double" ``` ```r attributes(week) ``` ``` ## $class ## [1] "difftime" ## ## $units ## [1] "weeks" ``` --- ## Lists .pull-left[ Elements can be of any type. But each element of a list has the same type, because each element is a _reference_ to another object. That means that creating a list does not copy the components into the list (smaller size) <img src="https://d33wubrfki0l68.cloudfront.net/9628eed602df6fd55d9bced4fba0a5a85d93db8a/36c16/diagrams/vectors/list.png" width="350"> ] -- .pull-right[ `list()` ```r l1 <- list( 1:3, "a", c(TRUE, FALSE, TRUE), c(2.3, 5.9) ) typeof(l1) ``` ``` ## [1] "list" ``` ```r str(l1) ``` ``` ## List of 4 ## $ : int [1:3] 1 2 3 ## $ : chr "a" ## $ : logi [1:3] TRUE FALSE TRUE ## $ : num [1:2] 2.3 5.9 ``` ] --- .pull-left[ Lists are sometimes called recursive vectors because a list can contain other lists. ```r l3 <- list(list(list(1))) str(l3) ``` ``` ## List of 1 ## $ :List of 1 ## ..$ :List of 1 ## .. ..$ : num 1 ``` ] -- .pull-right[ c() combines several lists into one. ```r l4 <- list(list(1, 2), c(3, 4)) str(l4) l5 <- c(list(1, 2), c(3, 4)) str(l5) ``` ``` ## List of 2 ## $ :List of 2 ## ..$ : num 1 ## ..$ : num 2 ## $ : num [1:2] 3 4 ## List of 4 ## $ : num 1 ## $ : num 2 ## $ : num 3 ## $ : num 4 ``` <img src="https://d33wubrfki0l68.cloudfront.net/eb81c70723664f0920d0fd414e3f326b9ad1fa6e/c06ae/diagrams/vectors/list-c.png" width="241"> ] --- ### Lists: Testing and coercion Test with `is.list()` and coerce with `as.list`() ```r list(1:3) ``` ``` ## [[1]] ## [1] 1 2 3 ``` ```r as.list(1:3) ``` ``` ## [[1]] ## [1] 1 ## ## [[2]] ## [1] 2 ## ## [[3]] ## [1] 3 ``` `unlist()` turns a list into an atomic vector --- ### Lists: Matrices and arrays With atomic vectors, dimension is used to create matrices. With lists, the dimension attribute is used to create list-matrices or list-arrays. Useful for spatio-temporal grids. ```r l <- list(1:3, "a", TRUE, 1.0) dim(l) <- c(2, 2) l ``` ``` ## [,1] [,2] ## [1,] Integer,3 TRUE ## [2,] "a" 1 ``` ```r l[[1, 1]] ``` ``` ## [1] 1 2 3 ``` --- ## Data frames and tibbles A data frame is a named list of vectors with attributes for (column) `names`, `row.names` and its class is `data.frame` .pull-left[ S3 vectors built on top of lists <img src="https://d33wubrfki0l68.cloudfront.net/9ec5e1f8982238a413847eb5c9bbc5dcf44c9893/bc590/diagrams/vectors/summary-tree-s3-2.png" width="160"> ] .pull-right[ The length of each of its vectors must be the same (rectangular) Has `rownames()` and `colnames()`, the `names()` are the column names Has `nrow()` and `ncol()`, `length()` gives number of columns ] --- Some features of data frames create frustrations, which lead to the creation of **tibbles**, which _do less and complain more_. ```r df <- data.frame(col1 = 1:2, col2 = c('a', 'b')) df ``` ``` ## col1 col2 ## 1 1 a ## 2 2 b ``` ```r class(df$col2) ``` ``` ## [1] "factor" ``` ```r tbl <- tibble::tibble(col1 = 1:2, col2 = c('a', 'b')) tbl ``` ``` ## # A tibble: 2 x 2 ## col1 col2 ## <int> <chr> ## 1 1 a ## 2 2 b ``` ```r class(tbl$col2) ``` ``` ## [1] "character" ``` --- ### Data frame vs tibble behavior + Tibble don't coerce strings to factors by default -- + Tibbles discourage rownames, which are generally "bad" Rownames are "bad" because: (1) storing metadata in a different way than the rest of the data is generally not a good idea; (2) only work if a row can be identified by a single string; (3) must be unique. -- + Tibbles have a "prettier" print method -- + Tibbles have stricter subsetting rules -- + Tibbles always return a tibble and don't allow partial matching with `$` --- ### Data frames and tibbles, testing and coercing ```r is.data.frame(df) ``` ``` ## [1] TRUE ``` ```r is.data.frame(tbl) ``` ``` ## [1] TRUE ``` ```r tibble::is_tibble(df) ``` ``` ## [1] FALSE ``` ```r tibble::is_tibble(tbl) ``` ``` ## [1] TRUE ``` You can coerce with `as.data.frame()` or with `as_tibble()` --- ### List columns We can put any object in a data frame We need to either add the list-column after creation or wrapping the list in `I()` .pull-left[ ```r df <- data.frame(x = 1:3) df$y <- list(1:2, 1:3, 1:4) data.frame( x = 1:3, y = I(list(1:2, 1:3, 1:4))) ``` ``` ## x y ## 1 1 1, 2 ## 2 2 1, 2, 3 ## 3 3 1, 2, 3, 4 ``` <img src="https://d33wubrfki0l68.cloudfront.net/468ff533e993123c164eb090aa365e33962403bf/28ba7/diagrams/vectors/data-frame-list.png" width="189"> ] .pull-right[ ```r tibble::tibble( x = 1:3, y = list(1:2, 1:3, 1:4) ) ``` ``` ## # A tibble: 3 x 2 ## x y ## <int> <list> ## 1 1 <int [2]> ## 2 2 <int [3]> ## 3 3 <int [4]> ``` ] We can also have a matrix or array as a column in a data frame --- ## `NULL` NULL is special because it has a unique type, is always length zero, and can’t have any attributes .pull-left[ ```r typeof(NULL) ``` ``` ## [1] "NULL" ``` ```r length(NULL) ``` ``` ## [1] 0 ``` ```r x <- NULL attr(x, "y") <- 1 ``` ``` ## Error in attr(x, "y") <- 1: attempt to set an attribute on NULL ``` ] .pull-right[ - Test for NULLs with is.null() - Use it to represent an empty vector of arbitrary type - To represent an absent vector. `NULL` is often as a default function argument. ] --- name: title class: center, middle ## Exercises #### And Solutions from https://advanced-r-solutions.rbind.io/ --- ### Atomic vectors Q1. How do you create scalars of type raw and complex? (See ?raw and ?complex) ```r raw(1) as.raw(2) charToRaw("A") ``` ``` ## [1] 00 ## [1] 02 ## [1] 41 ``` ```r complex(1) complex(length.out = 1, real = 1, imaginary = 1) ``` ``` ## [1] 0+0i ## [1] 1+1i ``` --- Q2. Test your knowledge of vector coercion rules by predicting the output of the following uses of c(): ```r c(1, FALSE) c("a", 1) c(TRUE, 1L) ``` Q3. Why is 1 == "1" true? Why is -1 < FALSE true? Why is "one" < 2 false? --- Q4. Why is the default missing value, NA, a logical vector? What’s special about logical vectors? Q5. Precisely what do is.atomic(), is.numeric(), and is.vector() test for? `is.atomic()` tests if is an atomic vector or is NULL (!). `is.numeric()` tests if an object has type integer or double and is not of "factor", "Date", "POSIXt" or "difftime" class. `is.vector()` tests if an object is vector and has no attributes, apart from names. --- ## Attributes Q1. How is setNames() implemented? How is unname() implemented? Read the source code. .pull-left[ ```r setNames <- function (object = nm, nm){ names(object) <- nm object } ``` ] .pull-right[ ```r unname <- function (obj, force = FALSE) { if (!is.null(names(obj))) names(obj) <- NULL if (!is.null(dimnames(obj)) && (force || !is.data.frame(obj))) dimnames(obj) <- NULL obj } ``` ] --- Q2. What does dim() return when applied to a 1d vector? When might you use NROW() or NCOL()? ```r x <- 1:5 dim(x) nrow(x) ncol(x) NROW(x) NCOL(x) ``` ``` ## NULL ## NULL ## NULL ## [1] 5 ## [1] 1 ``` --- Q3. How would you describe the following three objects? What makes them different to 1:5? Row - column - third dimention ```r x1 <- array(1:5, c(1, 1, 5)) x2 <- array(1:5, c(1, 5, 1)) x3 <- array(1:5, c(5, 1, 1)) ``` --- Q4.An early draft used this code to illustrate structure(): ```r structure(1:5, comment = "my attribute") ``` ``` ## [1] 1 2 3 4 5 ``` But when you print that object you don’t see the comment attribute. Why? Is the attribute missing, or is there something else special about it? (Hint: try using help.) ```r foo <- structure(1:5, comment = "my attribute") attributes(foo) attr(foo, which = "comment") ``` ``` ## $comment ## [1] "my attribute" ## ## [1] "my attribute" ``` --- ## S3 atomic vectors Q1. What sort of object does table() return? What is its type? What attributes does it have? How does the dimensionality change as you tabulate more variables? ```r x <- table(mtcars[c("vs", "cyl", "am")]) typeof(x) attributes(x) ``` ``` ## [1] "integer" ## $dim ## [1] 2 3 2 ## ## $dimnames ## $dimnames$vs ## [1] "0" "1" ## ## $dimnames$cyl ## [1] "4" "6" "8" ## ## $dimnames$am ## [1] "0" "1" ## ## ## $class ## [1] "table" ``` --- Q2. What happens to a factor when you modify its levels? Q3: How do f2 and f3 differ from f1? .pull-left[ ```r f1 <- factor(letters[1:5]) f1 levels(f1) <- rev(levels(f1)) f1 attributes(f1) as.integer(f1) ``` ``` ## [1] a b c d e ## Levels: a b c d e ## [1] e d c b a ## Levels: e d c b a ## $levels ## [1] "e" "d" "c" "b" "a" ## ## $class ## [1] "factor" ## ## [1] 1 2 3 4 5 ``` ] .pull-right[ ```r f2 <- rev(factor(letters[1:5])) f2 attributes(f2) f3 <- factor(letters[1:5], levels = rev(letters[1:5])) f3 attributes(f3) ``` ``` ## [1] e d c b a ## Levels: a b c d e ## $levels ## [1] "a" "b" "c" "d" "e" ## ## $class ## [1] "factor" ## ## [1] a b c d e ## Levels: e d c b a ## $levels ## [1] "e" "d" "c" "b" "a" ## ## $class ## [1] "factor" ``` ] --- ## Lists Q1. List all the ways that a list differs from an atomic vector. <img decoding="async" amp-img-id="coverimage" src="https://www.houseofbots.com/images/news/3623/cover.png" class="i-amphtml-fill-content i-amphtml-replaced-content"> .footnote[https://www.houseofbots.com/news-detail/3623-4-50-data-structure-algorithms-and-programming-languages-interview-questions-for-programmers] --- Q2. Why do you need to use unlist() to convert a list to an atomic vector? Why doesn’t as.vector() work? ```r is.vector(as.vector(mtcars)) dim(mtcars) a<- unlist(mtcars) dim(a) str(a) ``` ``` ## [1] FALSE ## [1] 32 11 ## NULL ## Named num [1:352] 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ... ## - attr(*, "names")= chr [1:352] "mpg1" "mpg2" "mpg3" "mpg4" ... ``` --- Q3. Compare and contrast `c()` and `unlist()` when combining a date and date-time into a single vector ```r date <- as.Date("1970-01-02") dttm_ct <- as.POSIXct("1970-01-01 01:00", tz = "UTC") c(date, dttm_ct) ``` ``` ## [1] "1970-01-02" "1979-11-10" ``` ```r c(dttm_ct, date) ``` ``` ## [1] "1970-01-01 02:00:00 CET" "1970-01-01 01:00:01 CET" ``` ```r unlist(list(date, dttm_ct)) ``` ``` ## [1] 1 3600 ``` --- ## Data frames and tibbles Q1. Can you have a data frame with zero rows? What about zero columns? ```r iris[0, ] ``` ``` ## [1] Sepal.Length Sepal.Width Petal.Length Petal.Width Species ## <0 rows> (or 0-length row.names) ``` ```r iris[ ,0] ``` ``` ## data frame with 0 columns and 150 rows ``` ```r iris[0, 0] ``` ``` ## data frame with 0 columns and 0 rows ``` ```r data.frame() ``` ``` ## data frame with 0 columns and 0 rows ``` --- Q2: What happens if you attempt to set rownames that are not unique? ```r df <- data.frame(x = 1:3) row.names(df) <- c("x", "y", "y") ``` ``` ## Warning: non-unique value when setting 'row.names': 'y' ``` ``` ## Error in `.rowNamesDF<-`(x, value = value): duplicate 'row.names' are not allowed ``` ```r row.names(df) <- c("x", "y", "z") df[c(1, 1, 1), , drop = FALSE] ``` ``` ## x ## x 1 ## x.1 1 ## x.2 1 ``` --- Q3. If `df` is a data frame, what can you say about `t(df)`, and `t(t(df))`? Perform some experiments, making sure to try different column types. .pull-left[ ```r df <- data.frame(x = 1:5, y = 5:1) df ``` ``` ## x y ## 1 1 5 ## 2 2 4 ## 3 3 3 ## 4 4 2 ## 5 5 1 ``` ] .pull-right[ ```r t(df) ``` ``` ## [,1] [,2] [,3] [,4] [,5] ## x 1 2 3 4 5 ## y 5 4 3 2 1 ``` ```r is.matrix(df) ``` ``` ## [1] FALSE ``` ```r t(t(df)) ``` ``` ## x y ## [1,] 1 5 ## [2,] 2 4 ## [3,] 3 3 ## [4,] 4 2 ## [5,] 5 1 ``` ] --- Q4. What does `as.matrix()` do when applied to a data frame with columns of different types? How does it differ from `data.matrix()`? ```r str(iris) ``` ``` ## 'data.frame': 150 obs. of 5 variables: ## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ... ## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ... ## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ... ## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ... ## $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ... ``` ```r str(as.matrix(iris)) ``` ``` ## chr [1:150, 1:5] "5.1" "4.9" "4.7" "4.6" "5.0" "5.4" "4.6" "5.0" "4.4" ... ## - attr(*, "dimnames")=List of 2 ## ..$ : NULL ## ..$ : chr [1:5] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" ... ``` ```r str(data.matrix(iris)) ``` ``` ## num [1:150, 1:5] 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ... ## - attr(*, "dimnames")=List of 2 ## ..$ : NULL ## ..$ : chr [1:5] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" ... ```