Введение в R: линейная алгебра

Векторное индексирование, решатели собственных векторов, разложение по сингулярным числам и многое другое

R - очень мощный язык, разработанный специально для анализа данных, визуализации данных и машинного обучения, что делает его обязательным к изучению для любого начинающего специалиста по данным.

R особенно удобен с линейной алгеброй. Его встроенные типы данных, такие как векторы и матрицы, хорошо сочетаются со встроенными функциями, такими как решатели собственных значений и определителей, а также возможностями динамического индексирования.

В этой статье Intro to R будут рассмотрены следующие реализации темы линейной алгебры в R:

Векторы

  • Назначение вектора
  • Векторные операции
  • Создание последовательностей
  • Логические векторы
  • Недостающие значения
  • Индексирование векторов

Массивы и матрицы

  • Массивы
  • Индексирование массива
  • Индексирование матриц
  • Внешний продукт двух массивов
  • Демонстрация: все возможные детерминанты однозначных матриц 2x2
  • Обобщенное транспонирование массива
  • Умножение матриц
  • Собственные значения и собственные векторы
  • Разложение по сингулярным значениям и детерминанты
  • Аппроксимация методом наименьших квадратов и QR-разложение
  • Формирование разбитых матриц

Векторы

Присвоение вектора

R работает со структурами данных, простейшим из которых является числовой вектор. Вектор - это упорядоченный набор чисел. Чтобы создать вектор x с четырьмя элементами 1, 2, 3 и 4, можно использовать функцию конкатенации c().

x <- c(1, 2, 3, 4)

В этом сценарии используется оператор присваивания <-, который указывает на назначаемый объект. В большинстве случаев <- можно переключить с помощью =.

Функцию assign() также можно использовать:

assign('x', c(1, 2, 3, 4))

Оператор ‹- считается ярлыком для этого.

Назначения можно делать и в обратном направлении:

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 - ИСТИНА, ЛОЖЬ и НЕТ. Логические векторы задаются условиями. 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, которые не равны Na или NaN и больше 0.

Второй метод - с вектором положительных целых величин. В этом случае значения должны быть в наборе {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.

Наконец, вектор символьных строк может использоваться, когда объект имеет атрибут names для идентификации его компонентов. С фруктом <- 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 attribute. Если бы z был вектором из 1500 элементов, присвоение dim(z) <- c(100, 5, 3) означало бы, что z теперь обрабатывается как массив 100 на 5 на 3.

Индексирование массива

На отдельные элементы массива можно ссылаться, указав имя массива, за которым следуют нижние индексы в квадратных скобках, разделенные столбцами.

В векторе 3 на 4 на 6 a первое значение может быть вызвано через a[1, 1, 1], а последнее значение - через a[3, 4, 6].

a[,,] представляет весь массив; следовательно, a[1,1,] занимает первую строку первого двумерного поперечного сечения в 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, ‘*’)

Фактически, любую функцию можно применить к двум массивам с помощью функции external (). Предположим, мы определяем функцию f <- function(x, y) cos(y)/(1+x²). Функцию можно применить к двум векторам x и y через z <- outer(x, y, f).

Демонстрация: все возможные детерминанты однозначных матриц 2x2

Рассмотрим определители матриц 2 на 2 [a, b; c, d], где каждая запись представляет собой неотрицательное целое число от 0 до 9. Проблема состоит в том, чтобы найти определители всех возможных матриц в этой форме и представить частоту, с которой встречается значение, с помощью графика с высокой плотностью.

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

Один из умных способов сделать это - дважды использовать внешнюю функцию (0.

d <- outer(0:9,0:9)
fr <- table(outer(d, d, ‘-’))
plot(fr, xlab = ‘Determinant’, ylab = ‘Frequency’)

Первая строка присваивает этой матрице d:

Во второй строке снова используется функция outer () для вычисления всех возможных определителей, а в последней строке это строится.

Обобщенное транспонирование массива

Функцию aperm(a, perm) можно использовать для перестановки массива a. Аргумент perm должен быть перестановкой целых чисел {1,…, k}, где k - количество индексов в a. Результатом функции является массив того же размера, что и, но со старым измерением, заданным perm[j], становится новым j-th измерением.

Легко представить себе это как обобщение транспонирования для матриц. Если A - матрица, то B - это просто транспонирование A:

B <- aperm(A, c(2, 1))

В этих особых случаях функция 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 с помощью

solve(A, b)

Собственные значения и собственные векторы

Функция eigen(Sm) вычисляет собственные значения и собственные векторы симметричной матрицы Sm. Результатом является список, в котором первый элемент назван значениями, а второй - векторами. ev <- eigen(Sm) назначает этот список ev.

ev$val - это вектор собственных значений Sm и ev$vec матрица соответствующих собственных векторов.

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

evals <- eigen(Sm, only.values = TRUE)$values

Разложение по сингулярным значениям и детерминанты

Функция svd(m) принимает произвольный аргумент матрицы, m, и вычисляет разложение по сингулярным значениям m. Он состоит из матрицы ортонормированных столбцов U с тем же пространством столбцов, что и m, второй матрицы ортонормированных столбцов V, пространство столбцов которых является пространством строк m, и диагональной матрицы положительных элементов D, таких что

m = U %*% D %*% t(V)

det(m) можно использовать для вычисления определителя квадратной матрицы m.

Подгонка методом наименьших квадратов и QR-разложение

Функция lsfit() возвращает список, содержащий результаты процедуры аппроксимации методом наименьших квадратов. Задание вроде

ans <- lsfit(X, y)

дает результаты аппроксимации методом наименьших квадратов, где 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.

Создание разделов Matrices

Матрицы могут быть построены из других векторов и матриц с помощью функций cbind() и rbind().

cbind() формирует матрицы путем привязки матриц по горизонтали (по столбцам), а rbind() связывает матрицы по вертикали (по строкам).

В присваивании X <- cbind(arg_1, arg_2, arg_3, …) аргументы cbind() должны быть либо векторами любой длины, либо столбцами с одинаковым размером столбца (одинаковым количеством строк).

rbind() выполняет соответствующую операцию для строк.

Спасибо за прочтение!

Я надеюсь, что это Введение в R дало вам представление о мощных возможностях R в линейной алгебре.