Введение в data.table

2026-08-22

Данное руководство также доступно на следующих языках: en | es | fr | ru

Описание пакета data.table: его синтаксис, содержание и функции; выбор подмножества (subset) строк, выбор столбцов и проведение на них арифметических действий (select and compute), объединение в группы по определенному признаку. Опыт использования структуры данных data.frame из базового R будет полезен, но не необходим для понимания описания.


Анализ данных с использованием data.table

Действия манипуляции данных (subset, group, update, join и т.д.) связаны между собой. Объединение этих родственных действий позволяет:

Вкратце, этот пакет для вас, если вы заинтересованы в радикальном сокращении времени, затрачиваемого на написание кода и обсчет данных. Принципы data.table это позволяют, что мы и стремимся продемонстрировать в данном описании.

Данные

В этом документе мы используем данные NYC-flights14 из пакета flights (доступен только на GitHub). Он содержит данные о своевременности рейсов от Бюро транспортной статистики для всех рейсов, вылетевших из аэропортов Нью-Йорка в 2014 году (вдохновлено nycflights13). Данные доступны только за период с января по октябрь 2014 года.

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

input <- if (file.exists("../flights14.csv")) {
   "../flights14.csv"
} else {
  "https://raw.githubusercontent.com/Rdatatable/data.table/master/vignettes/flights14.csv"
}
flights <- fread(input)
flights
year month day dep_delay arr_delay carrier origin dest air_time distance hour
2014 1 1 14 13 AA JFK LAX 359 2475 9
2014 1 1 -3 13 AA JFK LAX 363 2475 11
2014 1 1 2 9 AA JFK LAX 351 2475 19
2014 1 1 -8 -26 AA LGA PBI 157 1035 7
2014 1 1 2 1 AA JFK LAX 350 2475 13
2014 10 31 1 -30 UA LGA IAH 201 1416 14
2014 10 31 -5 -14 UA EWR IAH 189 1400 8
2014 10 31 -8 16 MQ LGA RDU 83 431 11
2014 10 31 -4 15 MQ LGA DTW 75 502 11
2014 10 31 -5 1 MQ LGA SDF 110 659 8
dim(flights)
# [1] 253316     11

Примечание: fread напрямую поддерживает URL-адреса с http и https, а также команды операционной системы, такие как вывод sed и awk. Примеры можно найти в справке (?fread).

Введение

В этом описании мы

  1. Начнем с основ - что такое data.table, его общая структура, как выбирать строки, как выбирать и вычислять значения по столбцам;

  2. Затем мы рассмотрим выполнение агрегации данных по группам.

1. Основы

a) Что такое data.table?

data.table — это пакет R, который предоставляет расширенную версию data.frame, стандартной структуры данных для хранения данных в базовом (base) R. В разделе Данные выше мы увидели, как создать data.table с помощью функции fread(), но также можно создать его, используя функцию data.table(). Вот пример:

DT = data.table(
  ID = c("b","b","b","a","a","c"),
  a = 1:6,
  b = 7:12,
  c = 13:18
)
DT
ID a b c
b 1 7 13
b 2 8 14
b 3 9 15
a 4 10 16
a 5 11 17
c 6 12 18
class(DT$ID)
# [1] "character"

Вы также можете преобразовать существующие объекты в data.table с помощью setDT() (для структур data.frame и list) или as.data.table() (для других структур). Для получения более подробной информации о различиях (выходит за рамки этого руководства) обратитесь к ?setDT и ?as.data.table.

Примечания:

b) Общая структура - в чем заключается усовершенствование data.table?

По сравнению с data.frame, с использованием оператора [ ... ] в рамках data.table можно делать гораздо больше, чем просто выбирать строки и столбцы (примечание: мы также можем называть запись внутри DT[...] «запросом к DT», по аналогии с SQL). Для понимания этого сначала нужно рассмотреть общую форму синтаксиса data.table, как показано ниже:

DT[i, j, by]

##   R:                 i                 j        by
## SQL:  where | order by   select | update  group by

Для пользователей с опытом работы в SQL этот синтаксис может выглядеть знакомо.

Прочитать это (вслух) можно так:

Взять DT, выбрать/переставить строки, используя i, затем вычислить j, сгруппировав по by.

Начнем с рассмотрения i и j — выбора строк и операций со столбцами.

в) Выбор строк в i

– Вывести все рейсы, вылетевшие из аэропорта “JFK” в июне.

ans <- flights[origin == "JFK" & month == 6L]
head(ans)
year month day dep_delay arr_delay carrier origin dest air_time distance hour
2014 6 1 -9 -5 AA JFK LAX 324 2475 8
2014 6 1 -10 -13 AA JFK LAX 329 2475 12
2014 6 1 18 -1 AA JFK LAX 326 2475 7
2014 6 1 -6 -16 AA JFK LAX 320 2475 10
2014 6 1 -4 -45 AA JFK LAX 326 2475 18
2014 6 1 -6 -23 AA JFK LAX 329 2475 14

– Вывести первые две строки из flights.

ans <- flights[1:2]
ans
year month day dep_delay arr_delay carrier origin dest air_time distance hour
2014 1 1 14 13 AA JFK LAX 359 2475 9
2014 1 1 -3 13 AA JFK LAX 363 2475 11

– Отсортировать flights по столбцу origin в возрастающем порядке, а затем по столбцу dest в убывающем порядке:

Для этого мы можем использовать функцию R order().

ans <- flights[order(origin, -dest)]
head(ans)
year month day dep_delay arr_delay carrier origin dest air_time distance hour
2014 1 5 6 49 EV EWR XNA 195 1131 8
2014 1 6 7 13 EV EWR XNA 190 1131 8
2014 1 7 -6 -13 EV EWR XNA 179 1131 8
2014 1 8 -7 -12 EV EWR XNA 184 1131 8
2014 1 9 16 7 EV EWR XNA 181 1131 8
2014 1 13 66 66 EV EWR XNA 188 1131 9

order() оптимизировано внутри функции

Мы более подробно обсудим быструю сортировку data.table в руководстве data.table internals.

d) Выбрать столбец/столбцы в j

– Выбрать столбец arr_delay, но вывести его как вектор.

ans <- flights[, arr_delay]
head(ans)
# [1]  13  13   9 -26   1   0

– Выбрать столбец arr_delay и вернуть его в виде data.table.

ans <- flights[, list(arr_delay)]
head(ans)
arr_delay
13
13
9
-26
1
0

data.table (как и data.frame) также является списком (list) с условием, что у него есть атрибут class, а каждый его элемент имеет одинаковую длину. Возможность возвращать list с помощью j позволяет эффективно преобразовывать и возвращать data.table.

Подсказка:

Пока выражение j возвращает список (list), каждый элемент списка будет преобразован в столбец в результирующем data.table. Это делает j очень мощным инструментом, как мы скоро увидим. Также это очень важно понимать, когда вы захотите составлять более сложные запросы.

– Выбрать оба столбца: arr_delay и dep_delay.

ans <- flights[, .(arr_delay, dep_delay)]
head(ans)
arr_delay dep_delay
13 14
13 -3
9 2
-26 -8
1 2
0 4
## другой вариант
# ans <- flights[, list(arr_delay, dep_delay)]

– Выбрать оба столбца: arr_delay и dep_delay, и переименовать их в delay_arr и delay_dep.

Поскольку .() — это просто псевдоним для list(), мы можем присваивать имена столбцам так же, как при создании list.

ans <- flights[, .(delay_arr = arr_delay, delay_dep = dep_delay)]
head(ans)
delay_arr delay_dep
13 14
13 -3
9 2
-26 -8
1 2
0 4

е) Вычисление или выполнение в j

– Сколько рейсов имели общую задержку < 0?

ans <- flights[, sum( (arr_delay + dep_delay) < 0 )]
ans
# [1] 141814

Что здесь происходит?

ж) Выбор в i и выполнение в j

– Рассчитать среднее время задержки прибытия и отправления для всех рейсов, вылетевших из аэропорта “JFK” в июне.

ans <- flights[origin == "JFK" & month == 6L,
               .(m_arr = mean(arr_delay), m_dep = mean(dep_delay))]
ans
m_arr m_dep
5.839 9.808

Поскольку три основные компонента запроса (i, j и by) находятся вместе внутри [...], data.table видит все три и может оптимизировать запрос целиком до выполнения, а не оптимизировать каждый компонент отдельно. Таким образом, мы можем избежать выбора всего набора данных (то есть, выбора столбцов кроме arr_delay и dep_delay), что повышает как скорость, так и эффективность использования памяти.

– Сколько рейсов было вылетело в 2014 году из аэропорта “JFK” в июне?

ans <- flights[origin == "JFK" & month == 6L, length(dest)]
ans
# [1] 8422

Функция length() требует аргумента. Нам нужно вычислить количество строк в выбранном подмножестве. Мы могли бы использовать любой другой столбец в качестве аргумента для length(). Этот подход напоминает SELECT COUNT(dest) FROM flights WHERE origin = 'JFK' AND month = 6 в SQL.

Этот тип действий встречается довольно часто, особенно при группировке (как мы увидим в следующем разделе), и поэтому data.table предоставляет специальный символ .N для этого.

з) Обработка несуществующих элементов в i

– Что происходит при запросе несуществующих элементов?

При запросе data.table для элементов, которые не существуют, поведение зависит от используемого метода.

setkeyv(flights, "origin")

Понимание этих особенностей поможет избежать путаницы при работе с несуществующими элементами в ваших данных.

Специальный символ .N:

.N — это специальная встроенная переменная, которая содержит количество наблюдений в текущей группе. Она особенно полезна при использовании с by, как мы увидим в следующем разделе. В отсутствие операций группировки она просто возвращает количество строк в выбранном подмножестве.

Теперь, когда мы знаем это, мы можем выполнить ту же задачу, используя .N, следующим образом:

ans <- flights[origin == "JFK" & month == 6L, .N]
ans
# [1] 8422

Мы могли бы выполнить то же действие, используя nrow(flights[origin == "JFK" & month == 6L]). Однако сначала нужно было бы выбрать весь data.table, соответствующий индексам строк в i, а затем возвращать количество строк с помощью nrow(), что является ненужным и неэффективным. Мы подробно рассмотрим это и другие аспекты оптимизации в руководстве дизайн data.table.

и) Отлично! Но как я могу ссылаться на столбцы по именам в j (как в data.frame)?

Если вы явно указываете имена столбцов, разницы по сравнению с data.frame нет (начиная с версии 1.9.8).

– Выбрать оба столбца: arr_delay и dep_delay способом data.frame.

ans <- flights[, c("arr_delay", "dep_delay")]
head(ans)
arr_delay dep_delay
13 14
13 -3
9 2
-26 -8
1 2
0 4

Если вы сохранили нужные столбцы в векторе символов, есть два варианта: использовать префикс .. или использовать аргумент with.

– Выбрать столбцы по именам из переменной, используя префикс ..

select_cols = c("arr_delay", "dep_delay")
flights[ , ..select_cols]
arr_delay dep_delay
13 14
13 -3
9 2
-26 -8
1 2
-30 1
-14 -5
16 -8
15 -4
1 -5

Знакомым с терминалом Unix префикс .. напоминает команду “на уровень выше”, что аналогично происходящему здесь — .. указывает data.table искать переменную select_cols “на уровне выше”, то есть, в данном случае, в глобальном пространстве переменных.

– Выбрать столбцы по именам из переменной, используя with = FALSE

flights[ , select_cols, with = FALSE]
arr_delay dep_delay
13 14
13 -3
9 2
-26 -8
1 2
-30 1
-14 -5
16 -8
15 -4
1 -5

Аргумент называется with, как и функция R with(), из-за схожей функциональности. Допустим, у вас есть data.frame DF, и вы хотите выбрать все строки, где x > 1. В base R вы можете сделать следующее:

DF = data.frame(x = c(1,1,1,2,2,3,3,3), y = 1:8)

## (1) обычный способ
DF[DF$x > 1, ] # для data.frame эта запятая также понадобится
x y
2 4
2 5
3 6
3 7
3 8
## (2) с использованием with()
DF[with(DF, x > 1), ]
x y
2 4
2 5
3 6
3 7
3 8

with = TRUE в data.table является значением по умолчанию, поскольку это позволяет j обрабатывать выражения — особенно в сочетании с by, как мы вскоре увидим.

2. Объединения

Мы уже рассмотрели i и j в общем виде data.table в предыдущем разделе. В этом разделе мы увидим, как их можно объединить с by, чтобы выполнять действия по группам. Давайте рассмотрим несколько примеров.

а) Группировка с использованием by

– Как узнать количество рейсов, соответствующих каждому аэропорту отправления?

ans <- flights[, .(.N), by = .(origin)]
ans
origin N
JFK 81483
LGA 84433
EWR 87400
## либо со строковым вектором в 'by'
# ans <- flights[, .(.N), by = "origin"]

– Как рассчитать количество рейсов для каждого аэропорта отправления для кода перевозчика "AA"?

Уникальный код перевозчика "AA" соответствует American Airlines Inc.

ans <- flights[carrier == "AA", .N, by = origin]
ans
origin N
JFK 11923
LGA 11730
EWR 2649

– Как получить общее количество рейсов для каждой пары origin, dest для кода перевозчика "AA"?

ans <- flights[carrier == "AA", .N, by = .(origin, dest)]
head(ans)
origin dest N
JFK LAX 3387
LGA PBI 245
EWR LAX 62
JFK MIA 1876
JFK SEA 298
EWR MIA 848
## или, как вариант, с использованием вектора символов в `by`
# ans <- flights[carrier == "AA", .N, by = c("origin", "dest")]

– Как получить среднюю задержку прибытия и отправления для каждой пары origin, dest для каждого месяца для кода перевозчика "AA"?

ans <- flights[carrier == "AA",
        .(mean(arr_delay), mean(dep_delay)),
        by = .(origin, dest, month)]
ans
origin dest month V1 V2
JFK LAX 1 6.590 14.229
LGA PBI 1 -7.759 0.310
EWR LAX 1 1.367 7.500
JFK MIA 1 15.721 18.743
JFK SEA 1 14.357 30.750
LGA MIA 10 -6.252 -1.421
JFK MIA 10 -1.880 6.677
EWR PHX 10 -3.032 -4.290
JFK MCO 10 -10.048 -1.613
JFK DCA 10 16.484 15.516

Что если мы захотим отсортировать результат по столбцам группировки origin, dest и month?

b) Сортировка по by: keyby

data.table намеренно сохраняет исходный порядок групп. В некоторых случаях сохранение исходного порядка является важным. Однако иногда нам необходимо автоматически отсортировать данные по переменным, которые используются для группировки.

– Тогда как же мы можем отсортировать данные по всем переменным группировки напрямую?

ans <- flights[carrier == "AA",
        .(mean(arr_delay), mean(dep_delay)),
        keyby = .(origin, dest, month)]
ans
origin dest month V1 V2
EWR DFW 1 6.428 10.013
EWR DFW 2 10.537 11.346
EWR DFW 3 12.865 8.080
EWR DFW 4 17.793 12.921
EWR DFW 5 18.488 18.683
LGA PBI 1 -7.759 0.310
LGA PBI 2 -7.865 2.404
LGA PBI 3 -5.754 3.033
LGA PBI 4 -13.967 -4.733
LGA PBI 5 -10.357 -6.857

Ключи сортировки: На самом деле keyby делает немного больше, чем просто сортировка. Он также устанавливает ключ после сортировки, добавляя атрибут с названием sorted.

Мы подробнее рассмотрим keys в руководстве vignette("datatable-keys-fast-subset", package="data.table"). Пока что вам нужно знать, что вы можете использовать keyby, чтобы автоматически отсортировать результат по столбцам, указанным в by.

c) Цепочки вызовов

Давайте ещё раз рассмотрим задачу получения общего количества рейсов для каждой пары origin, dest для перевозчика “AA”.

ans <- flights[carrier == "AA", .N, by = .(origin, dest)]

– Как мы можем отсортировать ans по столбцу origin в порядке возрастания и по столбцу dest в порядке убывания?

Мы можем сохранить промежуточный результат в переменной, а затем использовать order(origin, -dest) для этой переменной. Это выглядит довольно просто.

ans <- ans[order(origin, -dest)]
head(ans)
origin dest N
EWR PHX 121
EWR MIA 848
EWR LAX 62
EWR DFW 1618
JFK STT 229
JFK SJU 690

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

ans <- flights[carrier == "AA", .N, by = .(origin, dest)][order(origin, -dest)]
head(ans, 10)
origin dest N
EWR PHX 121
EWR MIA 848
EWR LAX 62
EWR DFW 1618
JFK STT 229
JFK SJU 690
JFK SFO 1312
JFK SEA 298
JFK SAN 299
JFK ORD 432

d) Выражения в by

– Может ли by принимать выражения, или он принимает только столбцы?

Да, может. Например, если мы хотим узнать, сколько рейсов вылетели с опозданием, но прибыли раньше (или вовремя), вылетели и прибыли с опозданием и т.д.

ans <- flights[, .N, .(dep_delay>0, arr_delay>0)]
ans
dep_delay arr_delay N
TRUE TRUE 72836
FALSE TRUE 34583
FALSE FALSE 119304
TRUE FALSE 26593

e) Множественные столбцы в j - .SD

– Нужно ли вычислять mean() для каждого столбца по отдельности?

Конечно, неудобно набирать mean(myCol) для каждого столбца по отдельности. Что если у вас 100 столбцов, для которых нужно вычислить mean()?

Как сделать это эффективно и лаконично? Для этого вспомните этот совет - “Если выражение в j возвращает list, каждый элемент списка будет преобразован в столбец в результирующем data.table. Если мы можем ссылаться на подмножество данных для каждой группы как на переменную во время группировки, мы можем использовать уже знакомую базовую функцию lapply() для обработки всех столбцов этой переменной. Никаких новых названий, специфичных для data.table, учить не нужно.

Специальный символ .SD:

data.table предоставляет специальный символ .SD, который означает подмножество данных (Subset of Data). Это data.table, который содержит данные для текущей группы, определенной с помощью by.

Помните, что data.table внутренне является list, в котором все столбцы имеют одинаковую длину.

Давайте используем data.table DT из предыдущего примера, чтобы увидеть, как выглядит .SD.

DT
ID a b c
b 1 7 13
b 2 8 14
b 3 9 15
a 4 10 16
a 5 11 17
c 6 12 18
DT[, print(.SD), by = ID]
#        a     b     c
#    <int> <int> <int>
# 1:     1     7    13
# 2:     2     8    14
# 3:     3     9    15
#        a     b     c
#    <int> <int> <int>
# 1:     4    10    16
# 2:     5    11    17
#        a     b     c
#    <int> <int> <int>
# 1:     6    12    18
ID

Для выполнения вычислений на (многих) столбцах можно использовать базовую функцию R lapply().

DT[, lapply(.SD, mean), by = ID]
ID a b c
b 2.0 8.0 14.0
a 4.5 10.5 16.5
c 6.0 12.0 18.0

Мы почти закончили. Осталось прояснить только одну вещь. В нашем data.table flights мы хотели рассчитать mean() только для двух столбцов - arr_delay и dep_delay. Однако по умолчанию .SD будет содержать все столбцы, кроме группирующих переменных.

– Как указать только те столбцы, для которых мы хотим вычислить mean()?

.SDcols

С помощью аргумента .SDcols. Он принимает как имена столбцов, так и их индексы. Например, .SDcols = c("arr_delay", "dep_delay") гарантирует, что .SD будет содержать только эти два столбца для каждой группы.

Аналогично пункту и), вы также можете указать столбцы для удаления вместо столбцов для сохранения, используя - или !. Также можно выбирать последовательные столбцы как colA:colB и исключать их как !(colA:colB) или -(colA:colB).

Теперь давайте попробуем использовать .SD вместе с .SDcols, чтобы вычислить mean() для столбцов arr_delay и dep_delay, сгруппированных по origin, dest и month.

flights[carrier == "AA",                       ## Для перелётов авиакомпанией "AA":
        lapply(.SD, mean),                     ## посчитать среднее
        by = .(origin, dest, month),           ## для каждой комбинации 'origin,dest,month'
        .SDcols = c("arr_delay", "dep_delay")] ## для столбцов, указанных в .SDcols
origin dest month arr_delay dep_delay
JFK LAX 1 6.590 14.229
LGA PBI 1 -7.759 0.310
EWR LAX 1 1.367 7.500
JFK MIA 1 15.721 18.743
JFK SEA 1 14.357 30.750
LGA MIA 10 -6.252 -1.421
JFK MIA 10 -1.880 6.677
EWR PHX 10 -3.032 -4.290
JFK MCO 10 -10.048 -1.613
JFK DCA 10 16.484 15.516

f) Подмножество .SD для каждой группы:

– Как вернуть первые две строки для каждого месяца?

ans <- flights[, head(.SD, 2), by = month]
head(ans)
month year day dep_delay arr_delay carrier origin dest air_time distance hour
1 2014 1 14 13 AA JFK LAX 359 2475 9
1 2014 1 -3 13 AA JFK LAX 363 2475 11
2 2014 1 -1 1 AA JFK LAX 358 2475 8
2 2014 1 -5 3 AA JFK LAX 358 2475 11
3 2014 1 -11 36 AA JFK LAX 375 2475 8
3 2014 1 -3 14 AA JFK LAX 368 2475 11

g) Почему j настолько многофункционален?

Таким образом мы обеспечиваем консистентный синтаксис и продолжаем использовать уже существующие (и знакомые) базовые функции, вместо того чтобы изучать новые. Для иллюстрации используем data.table DT, который мы создали в самом начале в разделе Что такое data.table?.

– Как мы можем объединить столбцы a и b для каждой группы в ID?

DT[, .(val = c(a,b)), by = ID]
ID val
b 1
b 2
b 3
b 7
b 8
a 5
a 10
a 11
c 6
c 12

– Что если мы хотим, чтобы все значения столбцов a и b были объединены, но возвращены как столбец-список?

DT[, .(val = list(c(a,b))), by = ID]
ID val
b 1,2,3,7,8,9
a 4, 5,10,11
c 6,12

Когда вы начнёте привыкать к использованию синтаксиса в j, вы поймёте, насколько это мощный инструмент. Чтобы попрактиковаться с ним и попробовать разные вещи, вы можете поэкспериментировать с помощью функции print().

Например:

## обратите внимание на разницу между
DT[, print(c(a,b)), by = ID] # (1)
# [1] 1 2 3 7 8 9
# [1]  4  5 10 11
# [1]  6 12
ID
## и
DT[, print(list(c(a,b))), by = ID] # (2)
# [[1]]
# [1] 1 2 3 7 8 9
# 
# [[1]]
# [1]  4  5 10 11
# 
# [[1]]
# [1]  6 12
# 
ID

В случае (1) для каждой группы возвращается по вектору вектор, длины которых равны 6, 4, 2. Однако (2) возвращает список длиной 1 для каждой группы, где первый элемент содержит векторы длиной 6, 4, 2. Поэтому (1) даёт общую длину 6 + 4 + 2 = r 6+4+2, тогда как (2) возвращает `1 + 1 + 1 = `r 1+1+1.

При помощи аргумента j можно поместить внутрь data.table любой список. Например, при построении статистических моделей на группах строк список с этими моделями может стать столбцом data.table. Такой код лаконичен и легко читается.

## Удаётся ли дальним перелётам сократить отставание лучше, чем ближним?
## Различается ли сокращение отставания по месяцам?
flights[, `:=`(makeup = dep_delay - arr_delay)]

makeup.models <- flights[, .(fit = list(lm(makeup ~ distance))), by = .(month)]
makeup.models[, .(coefdist = coef(fit[[1]])[2], rsq = summary(fit[[1]])$r.squared), by = .(month)]
month coefdist rsq
1 0.004 0.027
2 -0.004 0.022
3 0.001 0.004
4 0.002 0.006
5 0.002 0.008
6 0.000 0.000
7 0.003 0.012
8 0.003 0.019
9 0.001 0.005
10 0.002 0.011

С использованием data.frame требуется более сложный код, чтобы добиться такого же результата.

setDF(flights)
flights.split <- split(flights, f = flights$month)
makeup.models.list <- lapply(flights.split, function(df) c(month = df$month[1], fit = list(lm(makeup ~ distance, data = df))))
makeup.models.df <- do.call(rbind, makeup.models.list)
data.frame(t(sapply(
  makeup.models.df[, "fit"],
  function(model) c(coefdist = coef(model)[2L], rsq =  summary(model)$r.squared)
)))
coefdist.distance rsq
0.004 0.027
-0.004 0.022
0.001 0.004
0.002 0.006
0.002 0.008
0.000 0.000
0.003 0.012
0.003 0.019
0.001 0.005
0.002 0.011
setDT(flights)

Подведение итогов

Общий синтаксис data.table выглядит следующим образом:

DT[i, j, by]

Как мы теперь видим,

Использование i:

Мы можем сделать гораздо больше в i, установив ключи для data.table, что позволит нам очень быстро извлекать подмножества и выполнять соединения. Мы рассмотрим это в разделах vignette("datatable-keys-fast-subset", package="data.table") и vignette("datatable-joins", package="data.table").

Использование j:

  1. Выберите столбцы способом data.table: DT[, .(colA, colB)].

  2. Выберите столбцы способом data.frame: DT[, c("colA", "colB")].

  3. Выполните вычисления по столбцам: DT[, .(sum(colA), mean(colB))].

  4. Укажите имена, если это необходимо: DT[, .(sA = sum(colA), mB = mean(colB))].

  5. Сочетание с i: DT[colA > value, sum(colB)].

Использование by:

Также не забывайте:

Если j возвращает list, каждый элемент этого списка станет столбцом в результирующей data.table.

В следующем руководстве (vignette("datatable-reference-semantics", package="data.table")) мы рассмотрим, как добавлять/обновлять/удалять столбцы по ссылке и как комбинировать эти операции с i и by.