Mатрицы

Создание матрицы

Матрицы в R можно создавать разными способами. Выбор способа зависит от того, какую матрицу мы хотим создать: пустую матрицу (чтобы потом заполнять ее нужными значениями) или матрицу, составленную из уже имеющихся значений, например, из векторов.

Для того чтобы создать пустую матрицу, нужно определить, матрицу какой размерности мы хотим. Размерность матрицы – число строк и число столбцов в ней. Создадим для начала матрицу \(2 \times 3\), состоящую из нулей:

M <- matrix(0, nrow = 2, ncol = 3)
M
##      [,1] [,2] [,3]
## [1,]    0    0    0
## [2,]    0    0    0

Можем посмотреть на ее размерность:

dim(M)
## [1] 2 3

Заполнять эту матрицу другими значениями мы пока не будем – это будет интереснее делать, когда мы узнаем про циклы. А сейчас посмотрим, как собрать матрицу из “готовых” векторов.
Пусть у нас есть три вектора

x <- c(1, 2, 3, 0)
y <- c(4, 5, 6, 0)
z <- c(7, 8, 9, 0)

и мы хотим объединить их в матрицу. Векторы будут столбцами матрицы:

M_cols <- cbind(x, y, z) # c - от columns
M_cols
##      x y z
## [1,] 1 4 7
## [2,] 2 5 8
## [3,] 3 6 9
## [4,] 0 0 0

А теперь векторы будут строками матрицы:

M_rows <- rbind(x, y, z) # r - от rows
M_rows
##   [,1] [,2] [,3] [,4]
## x    1    2    3    0
## y    4    5    6    0
## z    7    8    9    0

Другой способ создавать матрицы - разбивать на строки один длинный вектор. Возьмем вектор:

long_vec <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 5, 0)

Посиотрим, сколько в нем элементов:

length(long_vec)
## [1] 12

А теперь превратим вектор в матрицу из трех строк и четырех столбцов:

m1 <- matrix(long_vec, 3, 4) # получим матрицу с 3 строками и 4 столбцами
m1
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7    0
## [2,]    2    5    8    5
## [3,]    3    6    9    0

Конечно, если бы потребовали от R невозможное – матрицу, произведение числа строк и столбцов которой не равно длине вектора, из которого мы пытаемся эту матрицу создать – мы бы получили ошибку:

# m2 <- matrix(long_vec, 4, 5)

Столбцам и строкам матрицы можно дать названия. Посмотрим еще раз на матрицу m1:

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

А теперь дадим столбцам этом матрицы названия.

colnames(m1) <- c("A", "B", "C", "D")
m1
##      A B C D
## [1,] 1 4 7 0
## [2,] 2 5 8 5
## [3,] 3 6 9 0

А теперь назовем строки матрицы:

rownames(m1) <- c("r1", "r2", "r3")
m1
##    A B C D
## r1 1 4 7 0
## r2 2 5 8 5
## r3 3 6 9 0

Можно, конечно, присваивать названия сразу и строкам, и столбцам. Проделаем это с матрицей M_cols.

dimnames(M_cols) <- list(c("r1", "r2", "r3", "r4"), c("X", "Y", "Z")) # сначала названия строк, затем -- столбцов

О том, что такое list – поговорим чуть позже.

Элементы матрицы

Для того, чтобы обратиться к элементу матрицы, необходимо указать строку и столбец, на пересечении которых он находится:

m1[1, 3] 
## [1] 7

Если нам нужна отдельная строка (одна строка, все столбцы), то номер столбца нужно не указывать, просто оставить позицию пустой:

m1[1, ] # вся первая строка
## A B C D 
## 1 4 7 0

Аналогично для столбцов:

m1[, 2] # весь второй столбец
## r1 r2 r3 
##  4  5  6

Списки

Список предсталяет собой “вектор векторов” в терминах R. Для тех, кто знаком с программированием, может показаться, что списки похожи на массивы. Это так, но списки, в отличие от массивов, могут содержать элементы разных типов. Например, в списке может быть сохранен вектор имен студентов (текстовый, тип character) и вектор их оценок (целочисленный, тип integer).

Пример списка с числовыми значениями:

L <- list(c(1, 2, 3, 4), c(5, 6, 7, 8))
L
## [[1]]
## [1] 1 2 3 4
## 
## [[2]]
## [1] 5 6 7 8

А вот пример списка с элементами разных типов:

grades <- list(c("Ann", "Sam", "Tom"), c(8, 7, 5))
grades
## [[1]]
## [1] "Ann" "Sam" "Tom"
## 
## [[2]]
## [1] 8 7 5

Так как в списках может храниться большое число разных векторов, для удобства им можно давать названия. Список grades можно было записать и так:

grades <- list(names = c("Ann", "Sam", "Tom"), marks = c(8, 7, 5))

И тогда отдельные вектора из списка можно было бы вызывать удобным образом:

grades$names # имена
## [1] "Ann" "Sam" "Tom"
grades$marks # оценки
## [1] 8 7 5

И если мы бы запросили у R структуру этого списка, мы бы увидели названия векторов, которые в него входят.

str(grades)
## List of 2
##  $ names: chr [1:3] "Ann" "Sam" "Tom"
##  $ marks: num [1:3] 8 7 5

Можно подумать: зачем нужно знать про списки, если на практике мы обычно будем сталкиваться с другими объектами – базами данных? На самом деле, со списками мы тоже будем встречаться. Многие статистические функции выдают результат в виде списков. Когда результаты выводятся на экран, это не всегда заметно, но если мы захотим заглянуть внутрь, то увидим, что та же регрессионная выдача представляет собой объект, похожий на список, из которого можно выбрать вектор коэффициентов (coefficients), вектор остатков (residuals), предсказанных значений (fitted.values) и так далее.

А как обращаться к элементам списка, если вектора в нем никак не названы?

Для обращения к элементам списка необходимо использовать двойные квадратные скобки:

L
## [[1]]
## [1] 1 2 3 4
## 
## [[2]]
## [1] 5 6 7 8
L[[1]] # первый элемент списка, вектор (1,2,3,4)
## [1] 1 2 3 4

Если нужно обратиться к “элементу элемента” списка (например, к числу 8 в этом примере) нужно сначала указывать номер вектора, в котором находится элемент, а потом номер самого элемента в этом векторе.

L[[2]][4] # 8 - 4ый элемент 2ого вектора в списке
## [1] 8

Можно заметить, что список похож на матрицу: для того, чтобы обратиться к элементу, нужно указать “строку” (вектор) и “столбец” (положение в векторе).

Для того, чтобы добавить элемент в список, нужно четко понимать положение элемента в этом списке: будет ли это элементом самого списка или “элементом элемента”:

L
## [[1]]
## [1] 1 2 3 4
## 
## [[2]]
## [1] 5 6 7 8
L[[3]] <- c(8, 9) # добавили в список третий вектор
L
## [[1]]
## [1] 1 2 3 4
## 
## [[2]]
## [1] 5 6 7 8
## 
## [[3]]
## [1] 8 9
L[[3]][3] <- 0 # добавили третий элемент третьего вектора в списке  
L
## [[1]]
## [1] 1 2 3 4
## 
## [[2]]
## [1] 5 6 7 8
## 
## [[3]]
## [1] 8 9 0

Аналогичным образом можно изменять элементы списка:

L[[1]][1] = 99 # заменим 1 элемент 1 вектора в массиве на 99
L
## [[1]]
## [1] 99  2  3  4
## 
## [[2]]
## [1] 5 6 7 8
## 
## [[3]]
## [1] 8 9 0

Если в списке всего один элемент, при необходимости его можно быстро превратить в обычный вектор с помощью unlist():

small_L <- list(c("a", "b", "c"))
small_L
## [[1]]
## [1] "a" "b" "c"
small_vec <- unlist(small_L)
small_vec
## [1] "a" "b" "c"

То же можно делать и со списками из нескольких векторов, тогда все склеится в один длинный вектор:

L
## [[1]]
## [1] 99  2  3  4
## 
## [[2]]
## [1] 5 6 7 8
## 
## [[3]]
## [1] 8 9 0
unlist(L)
##  [1] 99  2  3  4  5  6  7  8  8  9  0