Lab 03: Matrices, Lists

Higher Dimensions by Hand!

Vectors gave us the ability to form 1 dimensional data.

If we desired data in, say, 2 dimensions, we could still use a vector.

x <- 1:100
rows <- 10
cols <- 10

# Get the item at row i, column j
i <- 7
j <- 5
x[(i - 1) * cols + j] # Don't try this at home!
[1] 65

Who wants to do that?

Higher Dimensions, Passed to R

Thankfully, R has a set of functions that make this easy for us.

x <- matrix(1:100, nrow = 10, ncol = 10)
x
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]    1   11   21   31   41   51   61   71   81    91
 [2,]    2   12   22   32   42   52   62   72   82    92
 [3,]    3   13   23   33   43   53   63   73   83    93
 [4,]    4   14   24   34   44   54   64   74   84    94
 [5,]    5   15   25   35   45   55   65   75   85    95
 [6,]    6   16   26   36   46   56   66   76   86    96
 [7,]    7   17   27   37   47   57   67   77   87    97
 [8,]    8   18   28   38   48   58   68   78   88    98
 [9,]    9   19   29   39   49   59   69   79   89    99
[10,]   10   20   30   40   50   60   70   80   90   100
x[7, 9] # we can specify the row and column, sep. by a comma
[1] 87

Row-Major, Column-Major

The matrix function stores the given vector in column-major order by default. Our previous code assumed row-major order.

To see what this means, let’s turn m into two matrices, one for each.

m <- 1:9

Row-Major

     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8    9

Column-Major

     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

So row-major fills in the matrix by row, and column-major does so by column.

Specifying Row-Major, Column-Major

As said, the default is column-major.

If you’d prefer row-major, call matrix with byrow = TRUE.

Row-Major

matrix(
  m, 
  nrow = 3, 
  ncol = 3, 
  byrow = TRUE
)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8    9

Column-Major

matrix(
  m, 
  nrow = 3, 
  ncol = 3
)
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

Matrix Functions: rbind

rbind combines the rows of the inputs into a new matrix.

rbind(1:3, 3:1)
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    3    2    1
rbind(matrix(1:6, nrow = 3, ncol = 2), c(-100, 100))
     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6
[4,] -100  100
rbind(matrix(1:3, nrow = 1, ncol = 3), matrix(9:11, nrow = 1, ncol = 3))
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    9   10   11

Matrix Functions: cbind

cbind combines the columns of the inputs into a new matrix.

cbind(1:3, 3:1)
     [,1] [,2]
[1,]    1    3
[2,]    2    2
[3,]    3    1
cbind(matrix(1:6, nrow = 3, ncol = 2), c(0, 50, 100))
     [,1] [,2] [,3]
[1,]    1    4    0
[2,]    2    5   50
[3,]    3    6  100
cbind(matrix(1:6, nrow = 3, ncol = 2), matrix(6:1, nrow = 3, ncol = 2))
     [,1] [,2] [,3] [,4]
[1,]    1    4    6    3
[2,]    2    5    5    2
[3,]    3    6    4    1

Matrix Functions: nrow, ncol

With vectors, we use length to obtain the number of objects. Similarly, for matrices:

To obtain the number of rows, use nrow:

nrow(matrix(1:20, nrow = 5, ncol = 4))
[1] 5

To obtain the number of columns, use ncol:

ncol(matrix(1:20, nrow = 5, ncol = 4))
[1] 4

Accessing Elements

Use <matrix>[i, j] to get the value at the ith row and jth column.

x[2, 4]
[1] 32

If you want the ith row, use <matrix>[i,].

x[2,]
 [1]  2 12 22 32 42 52 62 72 82 92

Similarly, if you want the jth column, use <matrix>[,j].

x[,4]
 [1] 31 32 33 34 35 36 37 38 39 40

Note that a vector is returned in each case.

Lists

Lists allow us to store collection of objects, as with vectors, except every object need not be the same type.

list(1:7, "Go Bears!", TRUE)
[[1]]
[1] 1 2 3 4 5 6 7

[[2]]
[1] "Go Bears!"

[[3]]
[1] TRUE

Also, the objects of a list need not be atomic types. As you can see, the first object above is a vector. We can even have lists of lists.

list(list(1:7, "Go Bears!", TRUE), list(7:1, "!sraeB oG", FALSE))

Lists: Names

We can assign names to the objects.

my_list = list(nums = 1:7, str = "Go Bears!", bool = TRUE)
my_list
$nums
[1] 1 2 3 4 5 6 7

$str
[1] "Go Bears!"

$bool
[1] TRUE

Lists: Access by Name

Then access the objects by name with the $ operator.

my_list$nums
[1] 1 2 3 4 5 6 7
my_list$str
[1] "Go Bears!"
my_list$bool
[1] TRUE

Lists: Access with Square Brackets

As with vectors, we can access a list’s objects with indices, logical values, or names using square brackets.

Be careful! There are two types of access with lists.

person <- list(name = "Franz Liszt", profession = "Pianist", alive = FALSE)

What is the difference between these two?

person[1]
$name
[1] "Franz Liszt"
person[[1]]
[1] "Franz Liszt"

List: Square Brackets, Two Methods?

person[1]
$name
[1] "Franz Liszt"

The first (one set of square brackets) returns a list with only the first object.

person[[1]]
[1] "Franz Liszt"

The second (two sets of square brackets) returns the underlying object (a string).

Lists: Only One!

Note that when using double square brackets [[]], you can only access one object at a time.

person[[c(1, 2)]]
Error in person[[c(1, 2)]]: subscript out of bounds

This isn’t an issue with single square brackets.

person[c(1, 2)]
$name
[1] "Franz Liszt"

$profession
[1] "Pianist"

Can you guess why?