В data.table
, :=
и все функции set*
обновляют объекты по ссылке. Это было введено примерно в 2012 году IIRC. И в это время база R не была мелкой копии, но deep скопирована. Короткая копия была введена с 3.1.0.
Это многословный ответ, но я думаю, что это отвечает на ваши первые два вопроса:
Как этот базовый метод R отличается от эквивалента data.table?
blockquote>В базе R v3.1.0 +, когда мы делаем:
DF1 = data.frame(x=1:5, y=6:10, z=11:15) DF2 = DF1[, c("x", "y")] DF3 = transform(DF2, y = ifelse(y>=8L, 1L, y)) DF4 = transform(DF2, y = 2L)
- Из
DF1
] доDF2
, обе колонки только мелкие скопированы.- С
DF2
доDF3
только один столбецy
должен был быть скопирован / перераспределен, ноx
получает неглубокий .- От
DF2
доDF4
, то же, что и (2).То есть, столбцы неглубоко копируются до тех пор, пока столбец остается неизменным - в некотором роде копия задерживается, если это абсолютно необходимо.
В
data.table
, мы модифицируем на месте . Значение даже во времяDF3
иDF4
столбцаy
не копируется.DT2[y >= 8L, y := 1L] ## (a) DT2[, y := 2L]
Здесь, поскольку
y
уже является целым столбцом, и мы модифицируем его целым числом, по ссылке отсутствует новое распределение памяти, сделанное здесь вообще.Это также особенно полезно, если вы хотите назначить ссылкой (помечены как (a) выше ). Это удобная функция, которая нам очень нравится в
data.table
.Другое преимущество, которое приходит бесплатно (что я узнал из наших взаимодействий), - это когда мы должны, скажем, преобразовать все столбцы data.table к типу
numeric
, скажем,character
type:DT[, (cols) := lapply(.SD, as.numeric), .SDcols = cols]
Здесь, поскольку мы обновляем по ссылке, каждый столбец символов заменяет по ссылке с его числовой копией. И после этой замены более ранний столбец символов больше не требуется и предназначен для захватов для сбора мусора. Но если вы должны сделать это, используя базу R:
DF[] = lapply(DF, as.numeric)
Все столбцы должны быть преобразованы в числовые, и это должно быть сохранено в временной переменной , а затем, наконец, будет возвращен к
DF
. Это означает, что если у вас есть 10 столбцов со 100 миллионами строк, каждый из типов символов, то вашDF
занимает пробел:10 * 100e6 * 4 / 1024^3 = ~ 3.7GB
А поскольку тип
numeric
в два раза больше в размере, нам понадобится в общей сложности7.4GB + 3.7GB
пространства для нас, чтобы сделать преобразование с использованием базы R.Но обратите внимание, что
data.table
копирует во времяDF1
-DF2
. То есть:DT2 = DT1[, c("x", "y"), with=FALSE]
приводит к копированию, потому что мы не можем назначить ссылкой на копию мелкой . Он будет обновлять все клоны.
Было бы здорово, если бы мы могли легко интегрировать функцию мелкой копии, но отслеживать, имеет ли столбец определенного объекта несколько ссылок и по мере возможности обновляется по ссылке. Усовершенствованная функция подсчета ссылок R может быть очень полезна в этом отношении. В любом случае, мы работаем над этим.
Для вашего последнего вопроса:
«Когда разница наиболее значительна?»
< / blockquote>
- Есть еще люди, которым приходится использовать более старые версии R, где невозможно избежать глубоких копий.
- Это зависит от того, сколько столбцов копируется, потому что операции вы выполняете на нем. В худшем случае сценарий будет заключаться в том, что вы скопировали все столбцы, конечно.
- Есть случаи, когда это , где мелкое копирование не принесет пользы.
- Если вы хотите обновить столбцы data.frame для каждая группа , и слишком много групп.
- Если вы хотите обновить столбец, скажем, data.table
DT1
, основанный на соединении с другой data.tableDT2
- это можно сделать как:, гдеDT1[DT2, col := i.val]
i.
ссылается на значение из столбцаval
вDT2
(аргументi
) для сопоставления строк. Этот синтаксис позволяет выполнить эту операцию очень эффективно, вместо того, чтобы сначала соединить весь результат, а затем обновить требуемый столбец.В целом, есть сильные аргументы, когда обновление по ссылке сэкономит много времени и будет быстрым. Но люди иногда любят не обновлять объекты на месте и готовы жертвовать скоростью / памятью для него. Мы пытаемся выяснить, как лучше всего обеспечить эту функциональность, а также уже существующее обновление по ссылке.
Надеюсь, это поможет. Это уже довольно длинный ответ. Я оставлю любые вопросы, которые вы могли бы оставить другим, или для вас выяснить (кроме любых очевидных заблуждений в этом ответе).