2013-02-18 6 views
10

Ich habe eine Reihe von data.tables in einer Liste. Ich möchte unique() auf jede data.table in meiner Liste anwenden, aber dadurch werden alle meine data.table-Schlüssel zerstört.Warum speichert lapply() meine data.table-Schlüssel nicht?

Hier ist ein Beispiel:

A <- data.table(a = rep(c("a","b"), each = 3), b = runif(6), key = "a") 
B <- data.table(x = runif(6), b = runif(6), key = "x") 

blah <- unique(A) 

Hier hat blah noch einen Schlüssel, und alles ist richtig auf der Welt:

key(blah) 

# [1] "a" 

Aber wenn ich die data.tables zu einer Liste hinzuzufügen und verwenden lapply(), erhalten die Schlüssel zerstört:

dt.list <- list(A, B) 

unique.list <- lapply(dt.list, unique) # Keys destroyed here 

lapply(unique.list, key) 

# [[1]] 
# NULL 

# [[2]] 
# NULL 

Dies hat wahrscheinlich zu Ich verstehe nicht wirklich, was es bedeutet, dass Schlüssel "durch Verweis" zugewiesen werden, da ich andere Probleme mit dem Verschwinden von Schlüsseln hatte.

So:

  • Warum meine Schlüssel nicht lapply nicht behalten?
  • Was bedeutet es zu sagen, Schlüssel werden "per Referenz" zugewiesen?
  • Sollte ich sogar data.tables in einer Liste speichern?
  • Wie kann ich data.tables sicher speichern/manipulieren, ohne befürchten zu müssen, meine Schlüssel zu verlieren?

EDIT:

Für das, was es wert ist, die gefürchtete for Schleife funktioniert gut, auch:

unique.list <- list() 

for (i in 1:length(dt.list)) { 
    unique.list[[i]] <- unique(dt.list[[i]]) 
} 

lapply(unique.list, key) 

# [[1]] 
# [1] "a" 

# [[2]] 
# [1] "x" 

Aber das ist R und for Schleifen sind böse.

+1

Interessanterweise 'unique.list [[1]]! = Unique (A)'. Meine Vermutung, obwohl nur eine Vermutung, ist, dass vielleicht, was in der Lapply-Anweisung aufgerufen wird, das '{base}' unique und nicht das '{data.table}' 'unique' ist. –

+0

Ich denke, du hast Recht. Ich habe gerade bemerkt, dass - zusammen mit Schlüsseln zerstört - "unique" nicht einmal seine Arbeit macht, wenn es durch "lapply" passiert. –

+1

@PaulMurray +1 Gute Frage, aber _destroy_ scheint ein wenig stark. Es behält sie in diesem Fall nicht. –

Antwort

9

Interessanterweise beachten Sie den Unterschied zwischen diesen beiden unterschiedlichen Ergebnissen

lapply(dt.list, unique) 
lapply(dt.list, function(x) unique(x)) 

Wenn Sie letztere verwenden, sind die Ergebnisse wie erwartet.


Das scheinbar unerwartete Verhalten ist aufgrund der Tatsache, dass die erste lapply Aussage Aufruf unique.data.frame (dh von {base}) ist, während der zweite unique.data.table

+0

Wow, danke. Und * komisch *. Das funktioniert als Lösung, aber ich möchte immer noch wissen, was vor sich geht. Bin ich der einzige, der data.tables in Listen speichern will? Ich werde dies als [Bug-Bericht] einreichen (https://r-forge.r-project.org/tracker/?atid=975&group_id=240&func=browse) - denke, das ist fair? –

+1

@Plmrry Ich denke, wenn Sie Ihre 'data.tables' als Liste speichern, verlieren Sie einen großen Vorteil dessen, was data.table bietet, nämlich die Speichereffizienz durch Vermeidung unnötiger Duplizierung. Persönlich speichere ich eine Liste der ** Namen ** meiner data.tables und hole sie dann mit 'get (' * name * ')'. Ein bisschen hässlicher Code, aber schneller. –

+0

@Plmrry wie für den Fehlerbericht, es könnte nicht ein Fehler sein, aber nur die Art, wie 'match.fun()' funktioniert. Ich könnte aber nicht sagen –

5

Gute Frage aufruft. Es stellt sich heraus, dass es in ?lapply (siehe Hinweis Abschnitt) dokumentiert ist:

Aus historischen Gründen sind die von lapply erstellt Anrufe sind unbewertet, und Code geschrieben wurde (z bquote), die auf diese angewiesen ist. Dieser bedeutet, dass der aufgezeichnete Anruf immer die Form FUN (X [[0L]], ...), hat, wobei 0L durch den aktuellen Ganzzahlindex ersetzt wird. Dies ist normalerweise kein Problem, aber es kann sein, wenn FUN sys.call oder match.call verwendet oder wenn es eine primitive Funktion ist, die den Aufruf verwendet.Dies bedeutet, dass es oft sicherer ist, primitive Funktionen mit einem Wrapper aufzurufen, so dass z.B. lapply (ll, Funktion (x) is.numeric (x)) wird in R 2.7.1 benötigt, um sicherzustellen, dass der Methodenversand für is.numeric korrekt erfolgt.

+0

Danke! Natürlich war es die ganze Zeit im Handbuch ... –