Pavel Polishchuk, 2014
R - бесплатное свободно распространяемое программное обеспечение с открытым исходным кодом.
http://cran.r-project.org/
Находит широкое применение в различных областях знаний для моделирования, статистического анализа и обработки данных.
На февраль 2014 года в официальном репозитории R (CRAN) собрано 5246 пакета, которые представляют самые различные области знаний. Все эти пакеты свободно доступны на официальном сайте и существующих зеркалах.
http://cran.r-project.org/
Установка новых пакетов возможна через консоль R командой install.packages
либо через графический интерфейс.
Среди существующих графических оболочек для работы с R следует отметить RStudio, которая отличается удобством и постоянно расширяющимся функционалом.
http://www.rstudio.com/
Важно! R является регистрозависимым языком, поэтому надо быть внимательным при написании имен команд и переменных. Переменные big_table
и Big_table
рассматриваются как разные.
Удобный способ уставновки дополнительный пакетов через графический интерфейс RStudio. Важно отметить галочкой автоматическую уставновку зависимостей.
Установка пакета data.table
:
Загрузка пакета в рабочую область осуществляется через функции
library(имя_установленного_пакета)
или
require(имя_установленного_пакета)
Использовать функции из установленных пакетов, без их загрузки в рабочую область можно используя следующий вызов:
имя_установленного_пакета::имя_функции
Если необходимо использовать много различных функций, содержащихся в пакете, или происходит частое обращение к ним в ходе работы, то удобнее использовать первый вариант - загрузка всего пакета в рабочую область.
В случае же, если функция вызывается редко или существует конфликт имен (разные функции в разных пакетах имеют одинаковое название), то предпочтительным становится второй вариант вызова функций, при котором явно указывается какая функция и из какого пакета должна использоваться.
Функции производят операции над объектом и возвращают результат, при этом передаваемый объект не изменяется.
\[ result = f(data) \]
Если необходимо изменить состояние объекта, то результат функции присваивается переменной обозначающей этот объект.
\[ data = f(data) \]
Любая операция в R это функция
2 + 3
[1] 5
`+`(2, 3)
[1] 5
Типы данных в порядке увеличения приоритета:
Вектор может содержать данные только одного типа.
Логические:
c(TRUE, TRUE, FALSE)
[1] TRUE TRUE FALSE
class(c(TRUE, TRUE, FALSE))
[1] "logical"
Целочисленные:
c(1, 2, TRUE)
[1] 1 2 1
class(c(1, 2, TRUE))
[1] "numeric"
Текстовые:
c(2, "boo")
[1] "2" "boo"
class(c(2, "boo"))
[1] "character"
Какой класс будет иметь вектор?
c(1, 2, "tom", 2+8i, TRUE)
c(1,3,7)
[1] 1 3 7
1:15
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
15:1
[1] 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
-10:-1
[1] -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
-3.8:10
[1] -3.8 -2.8 -1.8 -0.8 0.2 1.2 2.2 3.2 4.2 5.2 6.2 7.2 8.2 9.2
seq(from=2, to=20, by=2)
[1] 2 4 6 8 10 12 14 16 18 20
seq(2, 20, 2)
[1] 2 4 6 8 10 12 14 16 18 20
c(1:5, 8, 11:15)
[1] 1 2 3 4 5 8 11 12 13 14 15
c(1:5, seq(10, 20, 2))
[1] 1 2 3 4 5 10 12 14 16 18 20
Матрица - двумерный набор элементов одного типа (таблица).
matrix(data=1:12, nrow=3, ncol=4)
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
matrix(data=1:12, nrow=3, ncol=4, byrow=TRUE)
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
Массив - многомерный набор элементов одного типа.
array(data=1:12, dim=c(2,2,3))
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
, , 3
[,1] [,2]
[1,] 9 11
[2,] 10 12
Factor - представляет номинальную или ранговую шкалу. Используется для представления Y в классификационных моделях.
factor(c(1,1,0,0,1,1,0))
[1] 1 1 0 0 1 1 0
Levels: 0 1
a <- factor(c("active", "inactive", "active", "active", "inactive", "active"))
a
[1] active inactive active active inactive active
Levels: active inactive
levels(a)
[1] "active" "inactive"
Data.frame - двумерный набор данных (таблица). В отличие от матриц, колонки в data.frame могут содержать данные различного типа. Однако тип данных внутри каждой колонки может быть только один. Это объясняется тем, что data.frame это список векторов (колонок). Поэтому к data.frame могут быть применены различные функции применимые к спискам.
data.frame(name=c("Tom", "Cruz", "Angela"), eye=c("brown", "black", "green"),
height=c(180, 192, 178))
name eye height
1 Tom brown 180
2 Cruz black 192
3 Angela green 178
Формулы - специальная форма выражения отношений между переменными в уравнении. Формулы используются при построении моделей для определения функциональной зависимости между параметрами.
Линейная комбинация (+):
# y = a*x1 + b*x2 + c
formula("y ~ x1 + x2")
y ~ x1 + x2
Линейная комбинация с отсутствующим свободным членом (+0)
# y = a*x1 + b*x2
formula("y ~ x1 + x2 + 0")
y ~ x1 + x2 + 0
Функция идентичности I(), при этом выражение в скобках рассматривается как обычное математическое.
# y = a*(x1 + x2) + c
formula("y ~ I(x1 + x2)")
y ~ I(x1 + x2)
# y = a*x + b*x^2 + c
formula("y ~ x + I(x^2)")
y ~ x + I(x^2)
Формулы могут содержать математические функции
# log(y) = a*log(x1) + b*x2 + c
formula("log(y) ~ log(x1) + x2")
log(y) ~ log(x1) + x2
Символ точки (.) подставляет все имеющиеся переменные. Функция зависимости y от всех остальных переменных, которые будут передаваться в функцию выглядит так
formula(y ~ .)
y ~ .
Синтаксис | Модель | Пояснение |
---|---|---|
Y ~ A | \( Y = \beta_{0} + \beta_{1}A \) | Уравнение регрессии с неявно заданным свободным членом |
Y ~ A + 0 | \( Y = \beta_{1}A \) | Уравнение регрессии без свободного члена |
Y ~ A + B | \( Y = \beta_{0} + \beta_{1}A + \beta_{2}B \) | Уравнеие модели первого порядка |
Y ~ A + I(A^2) | \( Y = \beta_{0} + \beta_{1}A + \beta_{2}A^2 \) | Уравнеие модели второго порядка с одной переменной |
Y ~ A:B | \( Y = \beta_{0} + \beta_{1}AB \) | Уравнение модели первого порядка, в которое входят только произведения переменных |
Y ~ A*B | \( Y = \beta_{0} + \beta_{1}A + \beta_{2}B + \beta_{3}AB \) | Полное уравнение модели первого порядка, аналогично Y ~ A + B + A:B |
Y ~ (A + B + C)^2 | \( Y = \beta_{0} + \beta_{1}A + \beta_{2}B + \beta_{3}C + \beta_{4}AB + \beta_{5}AC + \beta_{6}BC \) | Модель первого порядка включающая все произведения до порядка n, аналогично Y ~ A*B*C - A:B:C |
Списки содержат упорядоченный набор элементов, каждый из которых может являться вектором, матрицей, массивом, списком и т.д.
list(element_one=1:10, element_two=c(1, 3:7))
$element_one
[1] 1 2 3 4 5 6 7 8 9 10
$element_two
[1] 1 3 4 5 6 7
list(1:10, c(1, 3:7))
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 1 3 4 5 6 7
list(element_one=1:10, element_two=matrix(1:8, 2, 4))
$element_one
[1] 1 2 3 4 5 6 7 8 9 10
$element_two
[,1] [,2] [,3] [,4]
[1,] 1 3 5 7
[2,] 2 4 6 8
Как правило в виде списков удобно хранить либо какие-то однотипные данные соответствующие разным итерациям, например, множество моделей. Или хранить разнородные данные, которые имеют смысловую связь, например, различные статистические характеристики отдельной модели.
В R действия выполняются поэлементно сразу над всем набором данных (будь то вектор, матрица, data.frame и т.д.). Векторные вычисления очень эффективны, поэтому всегда когда нужно совершить действия над элементами вектора (матрицы и т.д.) предпочтительнее использовать векторизацию, а не циклы.
a <- 1:10
a
[1] 1 2 3 4 5 6 7 8 9 10
a + 2
[1] 3 4 5 6 7 8 9 10 11 12
Кстати оператор присваивания тоже является функцией, и присвоение можно выполнить в таком виде
'<-'(aa, 1:10)
aa
[1] 1 2 3 4 5 6 7 8 9 10
Сложение двух векторов одинаковой длины происходит поэлементно
a <- 1:10
a
[1] 1 2 3 4 5 6 7 8 9 10
b <- 11:20
b
[1] 11 12 13 14 15 16 17 18 19 20
a + b
[1] 12 14 16 18 20 22 24 26 28 30
Как упоминалось, векторные вычисления могут производиться над любой структурой данных (вектор, матрица, data.frame и т.д.). Пусть у нас есть матрица
m <- matrix(1:12, nrow=4)
m
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
Умножим все ее элементы на 2, или возведем во вторую степень
m * 2
[,1] [,2] [,3]
[1,] 2 10 18
[2,] 4 12 20
[3,] 6 14 22
[4,] 8 16 24
m ^ 2
[,1] [,2] [,3]
[1,] 1 25 81
[2,] 4 36 100
[3,] 9 49 121
[4,] 16 64 144
Если два вектора имеют различное количество элементов, то вектор меньшей длины будет повторяться столько раз чтобы соответствовать длине большего вектора.
Если длина большего вектора кратна длине меньшего вектора, такая операция будет произведена неявно, без уведомления пользоателя.
a <- 1:10
a
[1] 1 2 3 4 5 6 7 8 9 10
b <- 1:5
b
[1] 1 2 3 4 5
a + b
[1] 2 4 6 8 10 7 9 11 13 15
В случае если длины комбинируемых векторов различны, то будет произведено циклическое совмещение элементов меньшего вектора относительно элементов большего вектора и будет сгенерировано предупреждение.
a <- 1:10
b <- 1:3
a + b
Warning: длина большего объекта не является произведением длины меньшего
объекта
[1] 2 4 6 5 7 9 8 10 12 11
Все объекты поддерживают присвоение имен содержащимся в них элементам.
Обычный и именованный вектор
a <- 1:5
a
[1] 1 2 3 4 5
names(a) <- c("one", "two", "three", "four", "five")
a
one two three four five
1 2 3 4 5
Другой способ создания именованного вектора
a <- c("one"=1, "two"=2, "three"=3, "four"=4, "five"=5)
a
one two three four five
1 2 3 4 5
Аналогично векторам матрицы и data.frames имеют такие свойства как rownames
и colnames
, которые позволяют изменять имена колонок и строк.
df <- data.frame(1:2, 3:4, 5:6, 7:8)
df
X1.2 X3.4 X5.6 X7.8
1 1 3 5 7
2 2 4 6 8
rownames(df) <- c("case_1", "case_2")
colnames(df) <- c("var_1", "var_2", "var_3", "var_4")
df
var_1 var_2 var_3 var_4
case_1 1 3 5 7
case_2 2 4 6 8
Удаление имен осуществляется присвоением специального типа NULL
colnames(df) <- NULL
df
NA NA NA NA
case_1 1 3 5 7
case_2 2 4 6 8
Или для векторов
a <- 1:5
names(a) <- c("one", "two", "three", "four", "five")
a
one two three four five
1 2 3 4 5
names(a) <- NULL
a
[1] 1 2 3 4 5
При этом к элементам уже нельзя будет обращаться по имени, а только по индексу.
Преобразование типов данных осуществляется через группу функций, начинающихся на as.
Пример конвертации целочисленного вектора в текстовый
a <- 1:10
a
[1] 1 2 3 4 5 6 7 8 9 10
as.character(a)
[1] "1" "2" "3" "4" "5" "6" "7" "8" "9" "10"
Особенности приведения чисел выраженных как factors к числовому виду.
Преобразуем вектор целых чисел в номинальную шкалу (factor).
a <- c(1,1,0,0,1,1,0)
a
[1] 1 1 0 0 1 1 0
a <- as.factor(a)
a
[1] 1 1 0 0 1 1 0
Levels: 0 1
Для обратной конвертации использование функции as.integer
недостаточно.
as.integer(a)
[1] 2 2 1 1 2 2 1
Это связано с внутренним представлением типа данных factor. Эта структура представляет собой набор целочисленных значений, каждому из которых присвоено имя. В данном примере именами являются значения 1 и 0.
Поэтому для корретного преобразования factor в целочисленный тип данных необходимо предварительно провести конвертацию в текстовый вид.
as.integer(as.character(a))
[1] 1 1 0 0 1 1 0
Данная операция часто вызывает затрудние и служит причиной ошибок.
Подобно преобразованию типов данных возможно приведение различных структур данных к другому типу с помощью того же семейства функций, начинающихся на as.
.
a <- 1:3
as.data.frame(a)
a
1 1
2 2
3 3
Преобразоваание матрицы в data.frame
m <- matrix(1:8, 2, 4)
m
[,1] [,2] [,3] [,4]
[1,] 1 3 5 7
[2,] 2 4 6 8
as.data.frame(m)
V1 V2 V3 V4
1 1 3 5 7
2 2 4 6 8
Полное описание функций и возвращаемых ими значений с примерами можно найти в справке.
Дополнительно можно вызывать справку клавишей F1, когда курсор стоит на имени функции в тексте скрипта или в консоли.
Если необходимо найти какую-либо функцию по ее имени или части имени, то удобно пользоваться функциями из пакета sos
.
Установите пакет sos
и выполните следующие команды:
require(sos)
findFn("svm")
???svm
Индексация - исключительно эффективный и мощный инструмент для работы с данными.
Индексы могут быть:
Для индексирования используется три типа выражений:
[
- выбирает элементы вектора/списка/массива и т.д.$
- выбирает один элемент из data.frame/списка по его имени.[[
- выбирает элементы из вектора/списка/массива и т.д, но отбрасывает имена, если они есть.Выбор элементов вектора по их индексу
a <- 11:20
a
[1] 11 12 13 14 15 16 17 18 19 20
a[1:5]
[1] 11 12 13 14 15
a[c(2,4:7,9)]
[1] 12 14 15 16 17 19
Из этого примера видно, что для индексирования и выбора элементов на самом деле используется вектор индексов.
a <- 11:20
a
[1] 11 12 13 14 15 16 17 18 19 20
b <- 1:5
b
[1] 1 2 3 4 5
a[b]
[1] 11 12 13 14 15
Чтобы выбрать каждый второй элемент по индексу надо сгенерировать вектор, состоящий из четных чисел и использовать его для индексации исходного вектора.
a <- 11:20
a
[1] 11 12 13 14 15 16 17 18 19 20
b <- seq(1, 10, 2)
b
[1] 1 3 5 7 9
a[b]
[1] 11 13 15 17 19
Для удаления элементов по значению индекса перед ними добавляют знак минус
a <- 11:20
a
[1] 11 12 13 14 15 16 17 18 19 20
a[-1]
[1] 12 13 14 15 16 17 18 19 20
a[-c(2:4,7)]
[1] 11 15 16 18 19 20
Особенности индексирования позволяют менять положение элементов и дублировать их. Это очень эффективный прием, о котором часто забывают.
a <- 11:20
a[5:1]
[1] 15 14 13 12 11
a[c(5,1,1,1,2,3)]
[1] 15 11 11 11 12 13
С точки зрения индексирования матрицы и data.frames почти ничем не отличаются.
Создадим тестовый набор данных:
df <- data.frame(var1=c(11,21,31), var2=c(12,22,32), var3=c(13,23,33), var4=c(14,24,34), row.names=c("case1", "case2", "case3"))
df
var1 var2 var3 var4
case1 11 12 13 14
case2 21 22 23 24
case3 31 32 33 34
Выберем элемент строки 1 и колонки 2
df[1,2]
[1] 12
Выберем все значения строки 1. Результатом будет новый data.frame
df[1,]
var1 var2 var3 var4
case1 11 12 13 14
Выберем все значения колонки 1. Результатом будет вектор! Мы говорили выше, что data.frame это список колонок-векторов, и при выборе одной колонки присходит автоматическое преобразование результата к ветору.
df[,1]
[1] 11 21 31
Чтобы избежать этого необходимо добавить опцию drop
. Теперь результатом будет data.frame
df[,1, drop=FALSE]
var1
case1 11
case2 21
case3 31
Для выбора блоков данных в качестве индексов строк и стобцов можно использовать
# select rows 1 and 2 and columns 1 and 2
df[1:2, 1:2]
var1 var2
case1 11 12
case2 21 22
# select rows 1, 2 and 4 and columns 1 and 3
df[c(1,3), c(1:2,4)]
var1 var2 var4
case1 11 12 14
case3 31 32 34
Отрицательные индексы используются для удаления соответствующих колонок и строк (обратите внимание, что удаляется не один элемент а колонки и строки):
df[-2, -3]
var1 var2 var4
case1 11 12 14
case3 31 32 34
что аналогично предыдущему примеру, приводящему к тому же результату
df[c(1,3), c(1:2,4)]
var1 var2 var4
case1 11 12 14
case3 31 32 34
Текстовые индексы работают аналогично числовым
# выбрать один элемент
df["case2", "var3"]
[1] 23
# выбрать строку - возвращает data.frame
df["case2",]
var1 var2 var3 var4
case2 21 22 23 24
Выберем колонку
df[,"var1"] # возвращает вектор
[1] 11 21 31
df[,"var1", drop=FALSE] # возвращает data.frame
var1
case1 11
case2 21
case3 31
Выбор блока данных
df[c("case1", "case2"), c("var1", "var2")]
var1 var2
case1 11 12
case2 21 22
Для текстовых индексов отсутствует возможность использования отрицательных значений индексов, т.е. чтобы удалить строку/колонку необходимо сформировать вектов с именами строк/колонок, которые необходимо оставить.
Логические операции:
Генерация логического индекса (вектора) для вектора a
a <- 11:18
a
[1] 11 12 13 14 15 16 17 18
a > 15
[1] FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE
который можно использовать для выбора соответствующих элементов
a[a > 15] # возвращает значения вектора, которые больше 15
[1] 16 17 18
a[a != 12] # возвращает значения вектора, которые не равны 12
[1] 11 13 14 15 16 17 18
Возможна комбинация логических индексов с использованием операторов AND (&) и OR (|)
a[a < 12 | a >= 15] # a < 12 OR a >= 15
[1] 11 15 16 17 18
a[a > 12 & a <= 15] # a > 12 AND a <= 15
[1] 13 14 15
Логическое отрицание, оператор NOT (!), инвертирует значения логических индексов
a[a < 12 | a > 15] # a < 12 OR a > 15
[1] 11 16 17 18
a[!(a < 12 | a > 15)] # NOT(a < 12 OR a > 15), что аналогично a >= 12 AND a <= 15
[1] 12 13 14 15
Логический индекс (вектор) можно преобразовать в числовой. Функция which
возвращает порядковые номера элементов, значение которых TRUE
a <- 11:18
a > 15
[1] FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE
which(a > 15)
[1] 6 7 8
Для извлечения определенных элементов списка можно использовать числовые, текстовые и логические индексы. Однако при индексации списков есть некоторые особенности.
Создадим произвольный именованый список из двух элементов.
lst <- list(element_one=1:10, element_two=20:25)
Выберем первый элемент списка запросом показанным ниже.
lst[1]
$element_one
[1] 1 2 3 4 5 6 7 8 9 10
Обратите внимание, что в результате мы получим новый список содержащий только один элемент. Проверим это
class(lst[1])
[1] "list"
Выберем первый элемент списка используя другую функцию
lst[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
В этом случае запрос вернул содержимое первого элемента списка - целочисленный вектор.
Это важная особенность, которую упускают начинающие.
Альтернативный вариант доступа к содержимому одного элемента списка по его имени возможен с использоваем специальной конструкции ($)
lst$element_one
[1] 1 2 3 4 5 6 7 8 9 10
Это аналогично следующему вызову с использованием текстового индекса
lst[["element_one"]]
[1] 1 2 3 4 5 6 7 8 9 10
Выборка данных из data.frames была описана выше и ничем не отличается от других структур данных (вектров, матриц и т.д.). Единственная особенность вытекает из того, что data.frame это список векторов (колонок), то для выбора одной колонки по имени можно использовать конструкцию аналогичную для списков
df$var2
[1] 12 22 32
Такое выражение всегда возвращает вектор.
Если идет обращение к несуществующему индексу, то вернется специальное значение NA
v <- 1:5
v[6]
[1] NA
NA
специальное значение указывающее, что значение не определено (Not Available).
Если присваивать значение элементу с несуществующим индексом, то этот элемент будет создан.
v <- 1:5
v
[1] 1 2 3 4 5
v[6] <- 10
v
[1] 1 2 3 4 5 10
Другой пример в результате которого создаются NA
v <- 1:5
v
[1] 1 2 3 4 5
v[10] <- 11
v
[1] 1 2 3 4 5 NA NA NA NA 11
Для проверки является ли значение NA
используется специальная функция
is.na(v)
[1] FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE FALSE
Все то же самое справедливо и для текстовых индексов
v <- 1:5
names(v) <- c("one","two","three","four","five")
v["ten"]
<NA>
NA
v["ten"] <- 10
v
one two three four five ten
1 2 3 4 5 10
Аналогично для того, чтобы добавить новый элемент в список (колонку/строку в data.frame) используется новое имя или числовой индекс.
Пример с data.frame. Создадим data.frame и добавим новую переменную, которая будет равняться значению первой колонки во второй степени.
df <- data.frame(var1=c(11,21,31), var2=c(12,22,32), var3=c(13,23,33), var4=c(14,24,34), row.names=c("case1", "case2", "case3"))
df
var1 var2 var3 var4
case1 11 12 13 14
case2 21 22 23 24
case3 31 32 33 34
df$var5 <- df$var1 ^ 2
df
var1 var2 var3 var4 var5
case1 11 12 13 14 121
case2 21 22 23 24 441
case3 31 32 33 34 961
Пример со списком. Создадим именованый список из двух элементов и добавим к нему третий элемент.
lst <- list(element_one=1:10, element_two=20:25)
lst[["element_three"]] <- c(1:5,NA,7:8)
lst
$element_one
[1] 1 2 3 4 5 6 7 8 9 10
$element_two
[1] 20 21 22 23 24 25
$element_three
[1] 1 2 3 4 5 NA 7 8
Другие материалы с примерами по использованию индексов:
http://adv-r.had.co.nz/Subsetting.html от Hadley Wickham
c
library
require
class
seq
matrix
array
data.frame
factor
levels
formula
list
names
rownames
colnames
as.character
as.factor
as.integer
as.data.frame
finfFn
???
[
$
[[
which
is.na
&
|
>
<
>=
<=
==
!=
!
Есть data.frame
df <- data.frame(var1=c(11,21,31), var2=c(12,22,32), var3=c(13,23,33), var4=c(14,24,34), row.names=c("case1", "case2", "case3"))
df
var1 var2 var3 var4
case1 11 12 13 14
case2 21 22 23 24
case3 31 32 33 34
Y
и значениями -1, 0, 1.case2
.