R Language
Таблица данных
Поиск…
Вступление
Data.table - это пакет, который расширяет функциональные возможности фреймов данных из базы R, особенно улучшая их производительность и синтаксис. Подробную информацию см. В разделе «Документы» пакета в разделе « Начало работы с data.table» .
Синтаксис
-
DT[i, j, by]
# DT [где, выберите | update | do, by] -
DT[...][...]
# цепочка -
################# Shortcuts, special functions and special symbols inside DT[...]
- . ()
# в нескольких аргументах, заменяет список () - J ()
# in i, заменяет список () - знак равно
# in j, функция, используемая для добавления или изменения столбцов - .N
# в i, общее количество строк
# в j, количество строк в группе - .Я
# in j, вектор номеров строк в таблице (отфильтрованный i) - .sd
# в j, текущее подмножество данных
#, выбранный аргументом .SDcols - .grp
# в j, текущий индекс подмножества данных - .ОТ
# в j, список по значениям для текущего подмножества данных - V1, V2, ...
# имена по умолчанию для неназванных столбцов, созданных в j -
################# Joins inside DT[...]
- DT1 [DT2, on, j]
# присоединиться к двум таблицам - я.*
# специальный префикс на столбцах DT2 после объединения - от = .EACHI
# специальный вариант доступен только с присоединением - DT1 [! DT2, on, j]
# анти-объединение двух таблиц - DT1 [DT2, on, roll, j]
# присоединиться к двум таблицам, перекатывая последний столбец в on = -
################# Reshaping, stacking and splitting
- расплав (DT, id.vars, measure.vars)
# преобразовать в длинный формат
# для нескольких столбцов, используйте measure.vars = patterns (...) - dcast (DT, формула)
# преобразовать в широкий формат - rbind (DT1, DT2, ...)
# stack перечислены data.tables - rbindlist (DT_list, idcol)
# стек список data.tables - split (DT, by)
# разбить таблицу data.table в список -
################# Some other functions specialized for data.tables
- foverlaps
# перекрытие объединяется - сливаться
# другой способ соединения двух таблиц - задавать
# другой способ добавления или изменения столбцов - fintersect, fsetdiff, funion, fsetequal, уникальный, дублированный, anyDuplicated
# операции теории множеств со строками как элементами - uniqueN
# количество отдельных строк - rowidv (DT, cols)
# row ID (от 1 до .N) в каждой группе, определяемой cols - rleidv (DT, cols)
# идентификатор группы (от 1 до .GRP) в каждой группе, определяемый циклами cols - shift (DT, n, type = c ("lag", "lead"))
# применить оператор сдвига к каждому столбцу - setorder, setcolorder, setnames, setkey, setindex, setattr
# изменять атрибуты и порядок по ссылке
замечания
Установка и поддержка
Чтобы установить пакет data.table:
# install from CRAN
install.packages("data.table")
# or install development version
install.packages("data.table", type = "source", repos = "http://Rdatatable.github.io/data.table")
# and to revert from devel to CRAN, the current version must first be removed
remove.packages("data.table")
install.packages("data.table")
На официальном сайте пакета есть страницы вики, которые помогают начать работу, а также списки презентаций и статей со всего Интернета. Прежде чем задавать вопрос - здесь, в StackOverflow или где-либо еще - прочитайте страницу поддержки .
Загрузка пакета
Многие функции в приведенных выше примерах существуют в пространстве имен data.table. Чтобы использовать их, вам нужно сначала добавить строку, такую как library(data.table)
или использовать полный путь, например data.table::fread
а не просто fread
. Для помощи по отдельным функциям синтаксис - это help("fread")
или « ?fread
. Опять же, если пакет не загружен, используйте полное имя типа ?data.table::fread
.
Создание таблицы данных.
Data.table - это расширенная версия класса data.frame из базы R. Таким образом, атрибут class()
представляет собой вектор "data.table" "data.frame"
а функции, которые работают с data.frame, также будут работа с таблицей данных. Существует множество способов создания, загрузки или принуждения к таблице данных.
строить
Не забудьте установить и активировать пакет data.table
library(data.table)
Существует одноименный конструктор:
DT <- data.table(
x = letters[1:5],
y = 1:5,
z = (1:5) > 3
)
# x y z
# 1: a 1 FALSE
# 2: b 2 FALSE
# 3: c 3 FALSE
# 4: d 4 TRUE
# 5: e 5 TRUE
В отличие от data.frame
, data.table
не будет принуждать строки к факторам:
sapply(DT, class)
# x y z
# "character" "integer" "logical"
Читайте в
Мы можем читать из текстового файла:
dt <- fread("my_file.csv")
В отличие от read.csv
, fread
будет читать строки как строки, а не как факторы.
Измените файл data.frame
Для эффективности data.table предлагает способ изменения data.frame или списка, чтобы сделать data.table на месте (без копирования или изменения его памяти):
# example data.frame
DF <- data.frame(x = letters[1:5], y = 1:5, z = (1:5) > 3)
# modification
setDT(DF)
Обратите внимание, что мы не <-
присваиваем результат, так как объект DF
был изменен на месте. Атрибуты класса data.frame будут сохранены:
sapply(DF, class)
# x y z
# "factor" "integer" "logical"
Объект принуждения к data.table
Если у вас есть list
, data.frame
или data.table
, вы должны использовать функцию setDT
для преобразования в data.table
потому что она делает преобразование по ссылке вместо создания копии (что делает as.data.table
). Это важно, если вы работаете с большими наборами данных.
Если у вас есть другой объект R (такой как матрица), вы должны использовать as.data.table
чтобы принудить его к data.table
.
mat <- matrix(0, ncol = 10, nrow = 10)
DT <- as.data.table(mat)
# or
DT <- data.table(mat)
Добавление и изменение столбцов
DT[where, select|update|do, by]
используется для работы с столбцами таблицы данных.
- Часть «где» является аргументом
i
- Часть «select | update | do» является аргументом
j
Эти два аргумента обычно передаются положением вместо имени.
Ниже приведены приведенные ниже примеры
mtcars = data.table(mtcars, keep.rownames = TRUE)
Редактирование целых столбцов
Используйте оператор :=
внутри j
для назначения новых столбцов:
mtcars[, mpg_sq := mpg^2]
Удалите столбцы, установив NULL
:
mtcars[, mpg_sq := NULL]
Добавьте несколько столбцов, используя многомерный формат оператора :=
:
mtcars[, `:=`(mpg_sq = mpg^2, wt_sqrt = sqrt(wt))]
# or
mtcars[, c("mpg_sq", "wt_sqrt") := .(mpg^2, sqrt(wt))]
Если столбцы зависят и должны быть определены последовательно, один из способов:
mtcars[, c("mpg_sq", "mpg2_hp") := .(temp1 <- mpg^2, temp1/hp)]
Синтаксис .()
Используется, когда правая часть LHS := RHS
- это список столбцов.
Для динамически определяемых имен столбцов используйте круглые скобки:
vn = "mpg_sq"
mtcars[, (vn) := mpg^2]
Столбцы также могут быть изменены с помощью set
, хотя это редко необходимо:
set(mtcars, j = "hp_over_wt", v = mtcars$hp/mtcars$wt)
Редактирование подмножеств столбцов
Используйте аргумент i
для подмножества в строки «где» должны быть сделаны изменения:
mtcars[1:3, newvar := "Hello"]
# or
set(mtcars, j = "newvar", i = 1:3, v = "Hello")
Как и в data.frame, мы можем подмножество, используя номера строк или логические тесты. Также возможно использовать «соединение» в i
, но эта более сложная задача рассматривается в другом примере.
Редактирование атрибутов столбцов
Функции, редактирующие атрибуты, такие как levels<-
или names<-
, фактически заменяют объект на измененную копию. Даже если он используется только в одном столбце в таблице данных. Весь объект копируется и заменяется.
Чтобы изменить объект без копий, используйте setnames
для изменения имен столбцов data.table или data.frame и setattr
для изменения атрибута для любого объекта.
# Print a message to the console whenever the data.table is copied
tracemem(mtcars)
mtcars[, cyl2 := factor(cyl)]
# Neither of these statements copy the data.table
setnames(mtcars, old = "cyl2", new = "cyl_fac")
setattr(mtcars$cyl_fac, "levels", c("four", "six", "eight"))
# Each of these statements copies the data.table
names(mtcars)[names(mtcars) == "cyl_fac"] <- "cf"
levels(mtcars$cf) <- c("IV", "VI", "VIII")
Имейте в виду, что эти изменения сделаны по ссылке, поэтому они являются глобальными . Изменение их в одной среде влияет на объект во всех средах.
# This function also changes the levels in the global environment
edit_levels <- function(x) setattr(x, "levels", c("low", "med", "high"))
edit_levels(mtcars$cyl_factor)
Специальные символы в data.table
.sd
.SD
относится к подмножеству data.table
для каждой группы, за исключением всех столбцов , используемых в by
.
.SD
вместе с lapply
может использоваться для применения любой функции к нескольким столбцам по группам в data.table
Мы продолжим использовать тот же встроенный набор данных, mtcars
:
mtcars = data.table(mtcars) # Let's not include rownames to keep things simpler
Среднее значение всех столбцов в наборе данных по количеству цилиндров , cyl
:
mtcars[ , lapply(.SD, mean), by = cyl]
# cyl mpg disp hp drat wt qsec vs am gear carb
#1: 6 19.74286 183.3143 122.28571 3.585714 3.117143 17.97714 0.5714286 0.4285714 3.857143 3.428571
#2: 4 26.66364 105.1364 82.63636 4.070909 2.285727 19.13727 0.9090909 0.7272727 4.090909 1.545455
#3: 8 15.10000 353.1000 209.21429 3.229286 3.999214 16.77214 0.0000000 0.1428571 3.285714 3.500000
Помимо cyl
, в наборе данных есть другие категориальные столбцы, такие как vs
, am
, gear
и carb
. На самом деле нет смысла воспринимать mean
этих столбцов. Поэтому давайте исключаем эти столбцы. Это где .SDcols
входит в картину.
.SDcols
.SDcols
указывает столбцы data.table
, которые включены в .SD
.
Среднее значение всех столбцов (сплошные столбцы) в наборе данных по количеству передач gear
, и количество цилиндров, cyl
, устроенных gear
и cyl
:
# All the continuous variables in the dataset
cols_chosen <- c("mpg", "disp", "hp", "drat", "wt", "qsec")
mtcars[order(gear, cyl), lapply(.SD, mean), by = .(gear, cyl), .SDcols = cols_chosen]
# gear cyl mpg disp hp drat wt qsec
#1: 3 4 21.500 120.1000 97.0000 3.700000 2.465000 20.0100
#2: 3 6 19.750 241.5000 107.5000 2.920000 3.337500 19.8300
#3: 3 8 15.050 357.6167 194.1667 3.120833 4.104083 17.1425
#4: 4 4 26.925 102.6250 76.0000 4.110000 2.378125 19.6125
#5: 4 6 19.750 163.8000 116.5000 3.910000 3.093750 17.6700
#6: 5 4 28.200 107.7000 102.0000 4.100000 1.826500 16.8000
#7: 5 6 19.700 145.0000 175.0000 3.620000 2.770000 15.5000
#8: 5 8 15.400 326.0000 299.5000 3.880000 3.370000 14.5500
Может быть, мы не хотим вычислять mean
по группам. Чтобы вычислить среднее значение для всех автомобилей в наборе данных, мы не укажем переменную by
.
mtcars[ , lapply(.SD, mean), .SDcols = cols_chosen]
# mpg disp hp drat wt qsec
#1: 20.09062 230.7219 146.6875 3.596563 3.21725 17.84875
Замечания:
- Нет необходимости заранее определять
cols_chosen
..SDcols
могут напрямую принимать имена столбцов -
.SDcols
также могут непосредственно брать вектор столбчатых чисел. В приведенном выше примере это будутmtcars[ , lapply(.SD, mean), .SDcols = c(1,3:7)]
.N
.N
- сокращенное число строк в группе.
iris[, .(count=.N), by=Species]
# Species count
#1: setosa 50
#2: versicolor 50
#3: virginica 50
Написание кода, совместимого как с data.frame, так и с data.table
Различия в синтаксисе подмножества
data.table
является одним из нескольких двумерных структур данных , доступных в R, помимо data.frame
, matrix
и (2D) array
. Все эти классы используют очень похожий, но не идентичный синтаксис для подмножества, схему A[rows, cols]
.
Рассмотрим следующие данные, хранящиеся в matrix
: data.frame
и data.table
:
ma <- matrix(rnorm(12), nrow=4, dimnames=list(letters[1:4], c('X', 'Y', 'Z')))
df <- as.data.frame(ma)
dt <- as.data.table(ma)
ma[2:3] #---> returns the 2nd and 3rd items, as if 'ma' were a vector (because it is!)
df[2:3] #---> returns the 2nd and 3rd columns
dt[2:3] #---> returns the 2nd and 3rd rows!
Если вы хотите быть уверенными в том, что будет возвращено, лучше быть явным .
Чтобы получить определенные строки , просто добавьте запятую после диапазона:
ma[2:3, ] # \
df[2:3, ] # }---> returns the 2nd and 3rd rows
dt[2:3, ] # /
Но, если вы хотите подмножество столбцов , некоторые случаи интерпретируются по-разному. Все три могут быть подмножеством одинаковым образом с целыми или символьными индексами, не сохраненными в переменной.
ma[, 2:3] # \
df[, 2:3] # \
dt[, 2:3] # }---> returns the 2nd and 3rd columns
ma[, c("Y", "Z")] # /
df[, c("Y", "Z")] # /
dt[, c("Y", "Z")] # /
Однако они отличаются для имен без кавычек
mycols <- 2:3
ma[, mycols] # \
df[, mycols] # }---> returns the 2nd and 3rd columns
dt[, mycols, with = FALSE] # /
dt[, mycols] # ---> Raises an error
В последнем случае mycols
оцениваются как имя столбца. Поскольку dt
не может найти столбец с именем mycols
, возникает ошибка.
Примечание: Для версии data.table
пакета priorto 1.9.8, такое поведение было несколько иначе. Все, что было в индексе столбца, было бы оценено с использованием dt
в качестве среды. Таким образом, оба dt[, 2:3]
и dt[, mycols]
вернут вектор 2:3
. mycols
втором случае mycols
не mycols
, потому что переменная mycols
существует в родительской среде.
Стратегии обеспечения совместимости с data.frame и data.table
Есть много причин писать код, который гарантированно работает с data.frame
и data.table
. Возможно, вы вынуждены использовать data.frame
, или вам может понадобиться поделиться некоторым кодом, который вы не знаете, как будет использоваться. Итак, для удобства есть некоторые основные стратегии для достижения этого:
- Используйте синтаксис, который ведет себя одинаково для обоих классов.
- Используйте общую функцию, которая делает то же самое, что и самый короткий синтаксис.
- Принудите
data.table
вести себя какdata.frame
(например: вызов определенного методаprint.data.frame
). - Рассматривайте их как
list
, который они в конечном счете. - Преобразуйте таблицу в
data.frame
прежде чем что-либо делать (плохая идея, если это огромная таблица). - Преобразуйте таблицу в таблицу
data.table
, если зависимости не являются проблемой.
Строки подмножества. Просто, просто используйте селектор [, ]
с запятой:
A[1:10, ]
A[A$var > 17, ] # A[var > 17, ] just works for data.table
Подстрочные столбцы. Если вам нужен один столбец, используйте селектор $
или [[ ]]
:
A$var
colname <- 'var'
A[[colname]]
A[[1]]
Если вам нужен единый способ захватить более одного столбца, необходимо немного обжаловать:
B <- `[.data.frame`(A, 2:4)
# We can give it a better name
select <- `[.data.frame`
B <- select(A, 2:4)
C <- select(A, c('foo', 'bar'))
Подстрочные «индексированные» строки. Хотя data.frame
имеет row.names
, data.table
имеет свою уникальную key
функцию. Лучше всего избегать row.names
и использовать существующие оптимизации в случае data.table
когда это возможно.
B <- A[A$var != 0, ]
# or...
B <- with(A, A[var != 0, ]) # data.table will silently index A by var before subsetting
stuff <- c('a', 'c', 'f')
C <- A[match(stuff, A$name), ] # really worse than: setkey(A); A[stuff, ]
Получите таблицу с 1 столбцом, получите строку как вектор. Это легко понять, что мы видели до сих пор:
B <- select(A, 2) #---> a table with just the second column
C <- unlist(A[1, ]) #---> the first row as a vector (coerced if necessary)
Установка ключей в data.table
Да, вам нужно SETKEY до 1.9.6
В прошлом (pre 1.9.6) ваша data.table
установкой столбцов в качестве ключей к таблице, особенно для больших таблиц. [См. Интро-виньетку на стр. 5 от версии 2015 года, где скорость поиска была в 544 раза лучше.] Вы можете найти более старый код, используя эти установочные ключи с помощью «setkey» или установки столбца «key =» при настройке таблицы.
library(data.table)
DT <- data.table(
x = letters[1:5],
y = 5:1,
z = (1:5) > 3
)
#> DT
# x y z
#1: a 5 FALSE
#2: b 4 FALSE
#3: c 3 FALSE
#4: d 2 TRUE
#5: e 1 TRUE
Установите ключ с setkey
команды setkey
. У вас может быть ключ с несколькими столбцами.
setkey(DT, y)
Проверьте ключ таблицы в таблицах ()
tables()
> tables()
NAME NROW NCOL MB COLS KEY
[1,] DT 5 3 1 x,y,z y
Total: 1MB
Обратите внимание, что это приведет к повторной сортировке ваших данных.
#> DT
# x y z
#1: e 1 TRUE
#2: d 2 TRUE
#3: c 3 FALSE
#4: b 4 FALSE
#5: a 5 FALSE
Теперь это не нужно
До v1.9.6 вам нужно было установить ключ для определенных операций, особенно соединяя таблицы. Разработчики data.table ускорились и внедрили функцию "on="
которая может заменить зависимость от ключей. См. « Ответ» здесь для подробного обсуждения.
В январе 2017 года разработчики написали виньетку вокруг вторичных индексов, которая объясняет синтаксис «on» и позволяет идентифицировать другие столбцы для быстрой индексации.
Создание вторичных индексов?
Аналогично ключу можно setindex(DT, key.col)
или setindexv(DT, "key.col.string")
, где DT - ваша таблица данных. Удалите все индексы с помощью setindex(DT, NULL)
.
См. Ваши вторичные индексы с indices(DT)
.
Почему вторичные индексы?
Это не сортирует таблицу (в отличие от ключа), но позволяет быстро индексировать с помощью синтаксиса «on». Обратите внимание, что может быть только один ключ, но вы можете использовать несколько вторичных индексов, что экономит необходимость повторного подключения и использования таблицы. Это ускорит подмножество при изменении столбцов, на которые вы хотите настроить.
Напомним, в примере выше y был ключом для таблицы DT:
DT
# x y z
# 1: e 1 TRUE
# 2: d 2 TRUE
# 3: c 3 FALSE
# 4: b 4 FALSE
# 5: a 5 FALSE
# Let us set x as index
setindex(DT, x)
# Use indices to see what has been set
indices(DT)
# [1] "x"
# fast subset using index and not keyed column
DT["c", on ="x"]
#x y z
#1: c 3 FALSE
# old way would have been rekeying DT from y to x, doing subset and
# perhaps keying back to y (now we save two sorts)
# This is a toy example above but would have been more valuable with big data sets