setkey на подмножестве неглубокой копии кадра данных разбивает начало [дубликат]

Идиома Python для этого - newList = oldList[:]

8
задан Matthew 24 September 2014 в 17:36
поделиться

1 ответ

В data.table, := и все функции set* обновляют объекты по ссылке. Это было введено примерно в 2012 году IIRC. И в это время база R не была мелкой копии, но deep скопирована. Короткая копия была введена с 3.1.0.


Это многословный ответ, но я думаю, что это отвечает на ваши первые два вопроса:

Как этот базовый метод R отличается от эквивалента data.table?

В базе 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)
  1. Из DF1 ] до DF2, обе колонки только мелкие скопированы.
  2. С DF2 до DF3 только один столбец y должен был быть скопирован / перераспределен, но x получает неглубокий .
  3. От 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>
  1. Есть еще люди, которым приходится использовать более старые версии R, где невозможно избежать глубоких копий.
  2. Это зависит от того, сколько столбцов копируется, потому что операции вы выполняете на нем. В худшем случае сценарий будет заключаться в том, что вы скопировали все столбцы, конечно.
  3. Есть случаи, когда это , где мелкое копирование не принесет пользы.
  4. Если вы хотите обновить столбцы data.frame для каждая группа , и слишком много групп.
  5. Если вы хотите обновить столбец, скажем, data.table DT1, основанный на соединении с другой data.table DT2 - это можно сделать как:
    DT1[DT2, col := i.val]
    
    , где i. ссылается на значение из столбца val в DT2 (аргумент i) для сопоставления строк. Этот синтаксис позволяет выполнить эту операцию очень эффективно, вместо того, чтобы сначала соединить весь результат, а затем обновить требуемый столбец.

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

Надеюсь, это поможет. Это уже довольно длинный ответ. Я оставлю любые вопросы, которые вы могли бы оставить другим, или для вас выяснить (кроме любых очевидных заблуждений в этом ответе).

13
ответ дан Community 21 August 2018 в 03:11
поделиться