2017-02-17 5 views
2

Я думаю, что этот вопрос связан с концепцией Mutable Vs Immutable objects in R, и это может быть «вопрос начинающего». Я столкнулся с этой проблемой с funcion names() и функцией setnames() пакета data.table. Я уверен, что это ожидаемое поведение, но для меня это было довольно неожиданно, и я уверен, что это связано не только с names().Функции, возвращающие переменные Mutable или Immutable в R

Представьте меня data.table под названием dt с двумя столбцами а и Ь:

dt <- data.table(a = 1:5, b= 1:5) 
oldNames <- names(dt) 

Если вы печатаете oldNames, очевидно, показывает:

oldNames 
[1] "a" "b" 

Но если вы Ставить имена dt с setnames():

setnames(dt,oldNames,c("aNew","bNew")) 

Изменено содержимое переменной oldNames.

oldNames 
[1] "aNew" "bNew" 

Я знаю, что в Python это ожидаемое поведение некоторых типов данных (изменяемые из них), а не в других (в inmutable из них). В R, есть ли такая дикотомия?

Для меня «ожидаемым» поведением было бы то, что переменная oldNames хранит имена столбцов и не зависит от будущих изменений в таблице данных. Например, с помощью функции length() этого не происходит:

L <- length(dt) 
L 
[1] 2 
dt[,c:=1:5] 
L 
[1] 2 

Любая ссылка на какой-то хорошей информации о поведении или объяснения были бы оценены и что будет способ кодирования так oldNames не меняет его после модификации dt.

+0

Вы правы, она дублируется, я думал, что это была проблема R/поведение вообще не из Data.Table. спасибо. –

ответ

1

Я считаю, что это связано с реализацией пакета data.table. В R, множество символов может указывать на то же самое, но это обычно не вызывает проблемы, так как объекты будут скопированы на модификации, например:

a <- c(1,2) 
b <- a 
# To check the memory address, 
# `a` and `b` are pointed to the same object since `b` does not modify `a`. 
pryr::address(a) 
[1] "0x1a735620" 
pryr::address(b) 
[1] "0x1a735620" 
# Then we modify `a` 
a <- c(1,3) 
# We will notice that the address of `a` has changed 
# since there are modifications, but `b` not. 
pryr::address(a) 
[1] "0x1a72f168" 
pryr::address(b) 
[1] "0x1a735620" 

Из моего ограниченного знания, data.table пакет немного специальный, поскольку он будет модифицировать объект на месте с некоторыми операциями. См:

dt <- data.table(a = 1:5, b= 1:5) 
n1 <- names(dt) 

pryr::address(n1) 
[1] "0x18aeffe0" 

setnames(dt, c("a","b"), c("aa","bb")) 

n2 <- names(dt) 
pryr::address(n2) # identical to the address of `n1` 
[1] "0x18aeffe0" 

n1 
[1] "aa" "bb" 

Я думаю, что data.table пакет не признать, что есть переменная указывает на его имя атрибута, тем самым вызывая проблему. Я считаю это ошибкой, и вы можете пометить вопрос «data.table».

В настоящее время вы можете использовать n <- c(names(dt)) для хранения имен, таким образом, R рассмотрит c(), изменив атрибут имени и сохранит его в другом адресе памяти.

Кстати, R есть изменяемые объекты, см Reference class и R6 objects ;-)

С уважением;

Update:?

См data.table :: копировальной и data.table :: setnames

Цитирую data.table :: копия:

A 'copy()' может потребоваться при выполнении 'dt_names = names (DT)'. Из-за R's copy-on-modify, 'dt_names' по-прежнему указывает на то же место в памяти как 'names (DT)'. Поэтому, изменяя «DT» по ссылке, , добавив новый столбец, также будут обновлены «dt_names». Чтобы избежать этого, необходимо явно копия: 'dt_names < - копия (имена (DT))'.

Они, конечно, не распространены в R, data.table может сделать это, потому что использует интерфейс R's C.

Session Info:

> sessionInfo() 
R version 3.3.2 (2016-10-31) 
Platform: x86_64-suse-linux-gnu (64-bit) 
Running under: openSUSE Tumbleweed 

locale: 
[1] LC_CTYPE=en_US.UTF-8  LC_NUMERIC=C    LC_TIME=en_US.UTF-8  
[4] LC_COLLATE=en_US.UTF-8  LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 
[7] LC_PAPER=en_US.UTF-8  LC_NAME=C     LC_ADDRESS=C    
[10] LC_TELEPHONE=C    LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C  

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

other attached packages: 
[1] pryr_0.1.2   data.table_1.9.6 magrittr_1.5  personalutils_0.1.0 

loaded via a namespace (and not attached): 
[1] tools_3.3.2  Rcpp_0.12.9  stringi_1.1.2 codetools_0.2-15 
[5] stringr_1.1.0 chron_2.3-47 
+0

Большое спасибо за ваш ответ. Когда вы говорите: «Пакет data.table не распознал, что существует переменная, указывающая на ее атрибут имени, что вызывает проблему_», потому что я это обычное поведение в пакетах R? –

+0

Большое спасибо за ваш ответ. Когда вы говорите: «Пакет data.table не распознал, что существует переменная, указывающая на ее атрибут имени, что вызывает проблему», это обычное поведение в пакетах R ?. На самом деле я немного путаюсь с вашим пониманием вашего адреса. Я проверил адрес объекта 'L' (length()), и его адрес не изменяется (как это происходит с объектом' names'), но его значением, когда я добавляю новый столбец в 'dt' doesn ' t изменить либо! Таким образом, 'L' указывает на то же положение в памяти, но оно не изменяется от 2 до 3 значений. –

+0

Hey Gonzalo, извините, я сделал ошибку в своем примере, вы можете увидеть мой обновленный ответ. Использовать 'length()' и 'names()' немного отличается, использование 'length()' похоже на 'c (names())', оно будет выполнять некоторые вычисления и генерировать новую переменную. –

Смежные вопросы