2012-10-07 5 views
24

Załóżmy, że mam stworzyć listę w badania i dołączyć do niego w następujący sposób:Czy dodanie do listy w R powoduje kopiowanie?

x = list(10) 
x[[2]] = 20 

Jest to równoważne

x = list(10) 
x = list(10, 20) 

? Nie mam tak dużego doświadczenia z określonymi szczegółami, jak R radzi sobie z listami w pamięci, ale moim ograniczonym zrozumieniem jest to, że ma skłonność do kopiowania; Ideałem byłoby dla mnie, że pierwsza opcja nie polega na stworzeniu w pamięci innej listy, a jedynie na odłożeniu nowego miejsca w pamięci na dołączoną wartość. Zasadniczo, jeśli mam dużą listę, nie chcę, aby R tworzyła kolejną kopię, jeśli chcę tylko coś do niej dołączyć.

Jeśli zachowanie, którego chcę, nie jest tym, co tu podano, czy istnieje jakikolwiek inny sposób uzyskania pożądanego efektu?

+4

może "? Tracemem' byłby użyteczny? – Chase

+1

I '.Internal (sprawdź (x))' przed i po. –

Odpowiedz

15

Jestem przekonany, że odpowiedź brzmi "nie". Użyłem następujący kod dokładnie sprawdzić:

Rprof(tmp <- tempfile(), memory.profiling = TRUE) 

x <- list() 
for (i in 1:100) x[[i]] <- runif(10000) 

Rprof() 
summaryRprof(tmp, memory = "stats") 
unlink(tmp) 

dane wyjściowe:

# index: runif 
#  vsize.small max.vsize.small  vsize.large max.vsize.large 
#   76411   381781   424523   1504387 
#   nodes  max.nodes  duplications tot.duplications 
#   2725878   13583136    0    0 
#   samples 
#    5 

Odpowiednia część jest duplications = 0.

+3

Nie sądzę, aby twoje rozumowanie było konieczne: duplikacje mają specjalne znaczenie w R, i technicznie, podczas gdy wydłużenie długości wektora tworzy kopię, nie jest to duplikacja. Zobacz ten wątek na R-help: http://r.789695.n4.nabble.com/Understanding-tracemem-td4636321.html – hadley

4

Przyjęto odpowiedź flodel, ale wskazówka Chase'a była dobra, więc potwierdziłem, że mam pożądane zachowanie, używając jego sugestii użycia tracemem(). Oto pierwszy przykład, gdzie po prostu dołączyć do listy:

x = list(10) 
tracemem(x[[1]]) 
# [1] "<0x2d03fa8>" #(likely different on each machine) 
x[[2]] = 20 
tracemem(x[[1]]) 
# [1] "<0x2d03fa8>" 

A oto wynik z drugiego przykładu, gdzie stworzenia dwóch list:

x = list(10) 
tracemem(x[[1]]) 
# [1] "<0x2d03c78>" 
x = list(10, 20) 
tracemem(x[[1]]) 
# [1] "<0x2d07ff8>" 

Wygląda więc pierwsza metoda

do podać pożądane zachowanie.

10

Matthew Dowle za odpowiedź here i Uzasadnieniem znacznie wydajność pamięci jest zatrzymanie licznych za kopiowanie scen przez <-, [<-, [[<- i innych bazowych R operacji (names etc)

[[<- skopiuje cały x . Patrz przykład poniżej

x <- list(20) 
tracemem(x) 
#[1] "<0x2b0e2790>" 
x[[2]] <- 20 
# tracemem[0x2b0e2790 -> 0x2adb7798]: 

Twój drugi przypadek

x <- list(10,20) 

naprawdę nie jest dołączenie oryginalnego x ale zastępując x z obiektu, który okazuje się być oryginalny x z załączonym wartości.

+0

(+1), Drugi przypadek nie jest dołączany lub przykład czegoś, czym byłem proponuję, ale raczej przykład czegoś, czego nie chcę, żeby R działał za kulisami. – guy

+0

Ahh, źle odczytałem twoje pytanie, najpierw przeczytałem mi, gdy pytałeś, czy 'x <- list (10,20)', było odpowiednikiem (pod względem pamięci) do 'x <- list (10); x [[2]] <- 20'. Po ponownym przeczytaniu widzę, że był bardziej zniuansowany. – mnel

+0

Tak, ale w tej połączonej odpowiedzi 'x' było' data.frame'. W tym pytaniu 'x' jest' list'. Kopiowanie zachowania 'list' może być inne. Zauważ, że nie ma metody '[<- .list', ale istnieje' [<-. Data.frame'. Użyj '.Internal (inspect (x)), aby sprawdzić. –

8

Aby pomóc mi dowiedzieć się, czy modyfikowanie listy powoduje jej głęboką kopię lub płytką kopię, przygotowałem mały eksperyment.Jeśli modyfikując listę sprawia głęboką kopię, to powinno być wolniejsze kiedy modyfikując listę, która zawiera duży obiekt w porównaniu do listy, która zawiera niewielką obiektu:

z1 <- list(runif(1e7)) 
z2 <- list(1:10) 

system.time({ 
    for(i in 1:1e4) z1[1 + i] <- 1L 
}) 
# user system elapsed 
# 0.283 0.034 0.317 
system.time({ 
    for(i in 1:1e4) z2[1 + i] <- 1L 
}) 
# user system elapsed 
# 0.284 0.034 0.319 

Te czasy na moim komputerze były w zasadzie identyczne, co sugeruje, że kopiowanie listy powoduje płytką kopię, kopiowanie wskaźników do istniejących struktur danych.

+7

'.Internal (inspect (x))' jest bardziej konkretny sposób. Patrząc, czy zmienił się adres szesnastkowy długiego wektora. –

+0

@MatthewDowle Nice, thanks. – hadley