2012-10-07 19 views
24

Angenommen, ich habe eine Liste in R erstellen und anhängen wie folgt:Führt das Anhängen an eine Liste in R zum Kopieren?

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

Ist dies entspricht

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

? Ich bin nicht so erfahren mit den besonderen Details, wie R Listen im Gedächtnis behandelt, aber mein begrenztes Verständnis ist, dass es kopierfreudig ist; Was für mich ideal wäre, wäre, dass die erste Option nicht im Wesentlichen das Erstellen einer anderen Liste im Speicher beinhaltet, sondern lediglich dazu führt, dass ein neuer Platz im Speicher für den angehängten Wert reserviert wird. Im Wesentlichen, wenn ich eine große Liste habe, möchte ich nicht, dass R eine weitere Kopie davon macht, wenn ich nur etwas daran anhängen möchte.

Wenn das Verhalten, das ich will, nicht das ist, was hier gegeben wird, gibt es sonst noch eine Möglichkeit, den gewünschten Effekt zu erzielen?

+4

vielleicht '' tracemem' würde von Nutzen sein? – Chase

+1

Und '.Internal (inspect (x))' vorher und nachher. –

Antwort

15

Ich bin ziemlich zuversichtlich, die Antwort ist "Nein". Ich habe den folgenden Code zu überprüfen:

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

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

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

Der Ausgang:

# 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 

Der relevante Teil duplications = 0 zu sein.

+3

Ich denke nicht, dass Ihre Argumentation unbedingt korrekt ist: Duplikate haben eine besondere Bedeutung in R, und technisch gesehen, während die Verlängerung eines Vektors eine Kopie erzeugt, ist es keine Duplizierung. Siehe diesen Thread auf R-Hilfe: http://r.789695.n4.nabble.com/Understanding-tracemem-td4636321.html – hadley

4

Akzeptiert Flodel's Antwort, aber Chases Tipp war gut, also bestätigte ich, dass ich das gewünschte Verhalten mit seinem Vorschlag, tracemem() zu verwenden, habe. Hier ist das erste Beispiel, wo wir gerade in die Liste anhängen:

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

Und hier ist das Ergebnis aus dem zweiten Beispiel, wo wir zwei Listen erstellen:

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

So ist die erste Methode scheint gib das gewünschte Verhalten.

10

Matthew Dowle Antwort here und die Logik hinter viel Speichereffizienz ist es, die zahlreichen hinter den Kulissen Kopieren von <-, [<-, [[<- und anderen Basis R Operationen (names etc)

[[<- kopiert die gesamte x zu stoppen . Siehe nachstehendes Beispiel

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

Ihr zweiter Fall

x <- list(10,20) 

ist nicht wirklich das Original x anhängen, sondern ersetzt x mit einem Objekt, das die ursprünglichen x mit einem nachgestellten Wert sein geschieht.

+0

(+1), Der zweite Fall ist nicht anhängend, oder ein Beispiel für etwas, was ich war vorschlagen, aber eher ein Beispiel für etwas, was ich nicht hinter den Kulissen tun soll. – guy

+0

Ahh, ich habe deine Frage falsch gelesen, sie las mir zuerst, als du fragst, ob 'x <- list (10,20)', das Äquivalent (in Bezug auf das Gedächtnis) zu 'x <- Liste (10) war; x [[2]] <- 20'. Beim erneuten Lesen sehe ich, dass es nuancierter war. – mnel

+0

Ja, aber in dieser verknüpften Antwort war 'x' ein' data.frame'. In dieser Frage ist "x" eine "Liste". Das Kopierverhalten von 'list' kann unterschiedlich sein. Beachten Sie, dass es keine "[<- .list" -Methode gibt, sondern ein '[<-. Data.frame'. Verwenden Sie '.Internal (inspect (x))', um zu überprüfen. –

8

Um herauszufinden, ob das Ändern einer Liste eine tiefe Kopie oder eine flache Kopie ist, habe ich ein kleines Experiment eingerichtet.Wenn Modifizieren eine Liste eine tiefe Kopie macht, dann sollte es langsamer sein, wenn Sie eine Liste sind ändern, die ein großes Objekt enthält im Vergleich zu einer Liste, die ein kleines Objekt enthält:

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 

Die Zeiten auf meinem Computer waren im Grunde identisch, was darauf hindeutet, dass beim Kopieren einer Liste eine flache Kopie erstellt wird, indem Zeiger auf vorhandene Datenstrukturen kopiert werden.

+7

'.Internal (inspect (x))' ist eine konkretere Art zu erzählen. Nachsehen, ob sich die Hexadezimaladresse des langen Vektors geändert hat. –

+0

@MatthewDowle Schön, danke. – hadley

Verwandte Themen