R — очень мощный язык, разработанный специально для анализа и визуализации данных и машинного обучения, что делает его обязательным к изучению для любого начинающего специалиста по данным.
R особенно удобен для линейной алгебры. Встроенные типы данных, такие как векторы и матрицы, хорошо сочетаются со встроенными функциями, такими как алгоритмы решения собственных значений и определителей, а также с возможностями динамического индексирования.
В этой вводной в статье про R рассмотрим следующие реализации линейной алгебры:
R оперирует структурами данных, самой простой из которых является числовой вектор — упорядоченный набор чисел. Чтобы создать вектор x
с четырьмя элементами 1
, 2
, 3
и 4
, можно использовать объединяющую функцию c()
.
Здесь используется оператор присваивания <-
, указывающий на назначаемый объект. В большинстве случаев <-
можно заменить на =
.
Также можно использовать функцию assign()
:
Оператор <- считается сокращённым вариантом этой функции.
Присваивание векторов работает и в обратном направлении:
c(1, 2, 3, 4) -> xВекторы используются различными способами.
Операция y <- c(x, 0, x)
присвоит вектор 1, 2, 3, 4, 0, 1, 2, 3, 4
переменной y
.
Векторы можно свободно перемножать и дополнять константами:
v <- 2*x + y + 1Заметьте, что эта операция верна, даже когда x
и y
имеют разную длину. В данном случае R просто будет повторять x (иногда дробно), пока не достигнет длины y. Поскольку y равен 9 числам в длину, а x — 4, x повторится 2.25 раз пока не совпадёт с длиной y.
Можно использовать все арифметические операторы: +
, -
, *
, /
и ^
, а также log
, exp
, sin
, cos
, tan
, sqrt
и многие другие. max(x)
и min(x)
отображают наибольший и наименьший элементы вектора x
, а length(x)
— количество элементов x
; sum(x)
выдаёт сумму всех элементов x
, а prod(x)
— их произведение.
mean(x)
вычисляет выборочное среднее, var(x)
возвращает выборочную дисперсию, sort(x)
возвращает вектор того же размера, что и x, элементы в котором расположены в порядке возрастания.
В R существует множество методов для генерации последовательностей чисел. 1:30
аналогичен c(1, 2, …, 29, 30)
. Двоеточие имеет более высокий приоритет в выражении, поэтому 2*1:15
вернёт c(2, 4, …, 28, 30)
, а не c(2, 3, …, 14, 15)
.
30:1 используется для генерации последовательности в обратном направлении.
Для генерации последовательностей можно использовать и функцию seq()
. seq(2,10)
возвращает такой же вектор, что и 2:10
. В seq()
, можно также указать длину шага: seq(1,2,by=0.5)
возвращает c(1, 1.5, 2)
.
Аналогичная функция rep()
копирует объект различными способами. Например, rep(x, times=5)
вернёт пять копий x
впритык.
Логические значения в R — TRUE, FALSE и NA. Логические векторы задаются условиями. val <- x > 13
задаёт val
в качестве вектора той же длины, что x
, со значением TRUE
, если условие выполняется, и FALSE
, если нет.
Логические операторы в R: <
, <=
, >
, >=
, ==
и !=
, означающие, соответственно, меньше чем, меньше чем или равно, больше чем, больше чем или равно, равно или не равно.
Функция is.na(x)
возвращает логический вектор того же размера, что и x
, со значение TRUE
, если соответствующий элемент для x
равен NA
.
x == NA
отличается от is.na(x)
, поскольку NA
является не значением, а маркером для недоступной величины.
Второй тип “пропущенного значения” создаётся численными вычислениями, например 0/0
. В этом случае значения NaN
(не числа) рассматриваются как значения NA
, то есть is.na(x)
вернёт TRUE
и для NA
, и для NaN
значений. is.nan(x)
используется только для определения значений NaN
.
Первый вид индексации — через логический вектор. y <- x[!is.na(x)]
устанавливает y
значениям x
, не равным NA
или NaN
.
(x+1)[(!is.na(x)) & x>0] -> z
устанавливает z
значениям x+1
, больше 0 и не являющимся Na
или NaN
.
Второй метод осуществляется с вектором положительных целых значений. В этом случае значения должны быть в наборе {1, 2, …, length(x)}
. Для формирования результата соответствующие элементы вектора выбираются и объединяются в этом порядке. Важно помнить, что, в отличие от других языков, в R первый индекс равен 1, а не 0.
x[1:10]
возвращает первые 10 элементов x
, предполагая, что length(x)
не менее 10. c(‘x’, ‘y’)[rep(c(1,2,2,1), times=4)]
создаёт символьный вектор длиной 16, где ‘x’, ‘y’, ‘y’, ‘x’
повторяются четыре раза.
Вектор отрицательных целых чисел определяет значения, которые должны быть исключены. y <- x[-(1:5)]
устанавливает y
всем значениям x
, кроме первых пяти.
Наконец, вектор символьных строк может использоваться, когда у объекта есть атрибут name для идентификации его компонентов. Для <- c(1, 2, 3, 4)
можно задать имя каждому индексу вектора names(fruit) <- c(‘mango’, ‘apple’, ‘banana’, ‘orange’)
. Затем элементы можно вызывать по имени lunch <- fruit[c(‘apple’, ‘orange’)]
.
Преимущество этого подхода в том, что иногда буквенно-цифровые имена запомнить легче, чем индексы.
Обратите внимание, что индексированное выражение может встречаться на принимающей стороне присвоения, где оно только для этих элементов вектора. Например, x[is.na(x)] <- 0
заменяет все значения NA
и NaN
в векторе x
на 0
.
Другой пример: y[y<0] <- -y[y<0]
аналогичен y <- abs(y)
— код просто заменяет все значения меньше 0 на отрицательные значения.
Массив — это проиндексированный набор записей данных, не обязательно численный.
Вектор размерности — это вектор неотрицательных чисел. Если длина равна k, тогда массив k-размерный. Размерности индексируются от единицы вверх до значения, указанного вектором размерности.
Вектор может использоваться R в качестве массива, как атрибут dim
. Если z
— вектор из 1500 элементов, присвоение dim(z) <- c(100, 5, 3)
означает, что z
теперь представлен как массив 100 на 5 на 3.
На индивидуальные элементы массива можно ссылаться, указав имя массива и в квадратных скобках индексы, разделённые запятыми.
Первое значение вектора a
— 3 на 4 на 6 — может быть вызвано как a[1, 1, 1]
, а последнее как a[3, 4, 6]
.
a[,,]
отображает массив полностью, следовательно, a[1,1,]
берёт первую строку первого 2-размерного сечения a
.
Следующий код генерирует массив 4 на 5: x <- array(1:20, dim = c(4,5))
.
Массивы определяются вектором значений и размерностью матрицы. Значения вычисляются сначала сверху вниз, затем слева направо.
array(1:4, dim = c(2,2))
вернёт
1 3
2 4
а не
1 2
3 4
В матрицах индексов запрещены отрицательные индексы, а значения NA
и ноль разрешены.
Важной операцией с векторами является внешнее произведение. Если a
и b
— это два численных массива, их внешним произведением является массив, вектор размерности которого получается объединением двух векторов размерности, а вектор данных достигается формированием всех возможных произведений элементов вектора данных a
и элементов вектора b
. Внешнее произведение вычисляется с помощью оператора %o%
:
ab <- a %o% b
Другой способ:
ab <- outer(a, b, ‘*’)
Фактически любую функцию можно применить к двум массивам, используя внешнюю () функцию. Предположим, мы определили функцию f <- function(x, y) cos(y)/(1+x²)
. Функцию можно применить к двум векторам x
и y
с помощью z <- outer(x, y, f)
.
Рассмотрим определители матриц 2 на 2 [a, b; c, d], где каждая запись представляет собой неотрицательное число от 0 до 9. Задача: найти определители всех возможных матриц этой формы и отобразить на графике высокой плотности частоту, с которой встречается значение.
Или, перефразируя, нужно найти распределение вероятности определителя, если каждая цифра выбирается независимо и равномерно случайным образом.
Один из умных способов сделать это — использовать внешнюю функцию дважды.
d <- outer(0:9,0:9)
fr <- table(outer(d, d, ‘-’))
plot(fr, xlab = ‘Determinant’, ylab = ‘Frequency’)
Первая строка присваивает d этой матрице:
Вторая строка снова использует внешнюю функцию для расчёта всех возможных определителей. Последняя строка строит график.
Функция aperm(a, perm)
используется для перестановки массива a. Аргументом perm должна быть перестановка чисел {1,…, k}, где k — количество индексов в a. Результатом функции будет массив того же размера, что и a, но прежняя размерность, заданная perm[j]
, становится новой размерностью j-th
.
Проще понять, если думать об этом как об обобщённом транспонировании матриц. Если A
— это матрица, тогда B
— просто результат перестановки матрицы A
:
В таких особых случаях перестановку осуществляет функция t()
.
Для умножения матриц используется оператор %*% . Если A
и B
являются квадратными матрицами одинакового размера, A*B
— это поэлементное произведение двух матриц. A %*% B
— это скалярное произведение (произведение матриц).
Если x — вектор, тогда x %*% A %*% x
— его квадратичная форма.
crossprod()
осуществляет перекрёстные произведения. Таким образом crossprod(X, y)
аналогична операции t(X) %*% y
, но более эффективна.
diag(v)
, где v
— вектор — задаёт диагональную матрицу с элементами вектора в качестве диагональных элементов. diag(M)
, где m
— матрица — задаёт вектор основных диагональных элементов M
(так же как и в Matlab). diag(k)
, где k
— единичное числовое значение — возвращает единичную матрицу k
на k
.
Решение линейных уравнений является инверсией умножения матриц. Если
b <- A %*% xс заданными только A
и b
, вектор x
— решение системы линейных уравнений, которое быстро решается в R:
Функция eigen(Sm)
вычисляет собственные значения и собственные векторы симметричной матрицы Sm. Результат — это список, где первый элемент отображает значения, а второй — векторы. ev <- eigen(Sm)
присваивает этот список ev
.
ev$val
— это вектор собственных значений Sm
, и ev$vec
— матрица соответствующих собственных векторов.
Для больших матриц лучше избегать вычисления собственных векторов, если они не нужны, используя выражение:
evals <- eigen(Sm, only.values = TRUE)$valuesФункция svd(m)
принимает произвольный матричный аргумент m
и вычисляет его сингулярное разложение. Оно состоит из 1) матрицы ортонормированных столбцов U
с тем же пространством столбцов, что и m
, 2) второй матрицы ортонормированных столбцов V
, пространство столбцов которой является пространством строк m
, 3) и диагональной матрицы положительных элементов D
:
det(m)
используется для вычисления определителя квадратной матрицы m
.
Функция lsfit()
возвращает список заданных результатов процедуры выравнивания методом наименьших квадратов. Присваивание наподобие этого:
выдаёт результаты выравнивания методом наименьших квадратов, где y — это вектор наблюдений, а X — проектная матрица.
ls.diag()
используется для диагностики регрессии.
Тесно связанной функцией является qr().
b <- qr.coef(Xplus,y)
fit <- qr.fitted(Xplus,y)
res <- qr.resid(Xplus,y)
Они вычисляют ортогональную проекцию y
на диапазон X
в fit
, проекцию на ортогональное дополнение в res
и вектор коэффициентов для проекции в b
.
Матрицы можно строить из других векторов и матриц с помощью функций cbind()
и rbind()
.
cbind()
формирует матрицы, связывая матрицы горизонтально (поколоночно), а rbind()
связывает матрицы вертикально (построчно).
В присвоении X <- cbind(arg_1, arg_2, arg_3, …)
аргументами cbind()
должны быть либо векторы любой длины, либо столбцы одинакового размера (одинаковым количеством строк).
rbind()
выполняет соответствующую операцию для строк.
Перевод статьи Andre Ye: Intro to R: Linear Algebra
Комментарии