2015-05-08 7 views
35

Sagen wir, ich

dflist <- list(data.frame(a=1:3), data.frame(b=10:12, a=4:6)) 

eine Liste von data.frames haben, wenn ich die erste Spalte von jedem Element in der Liste extrahieren will, kann ich

lapply(dflist, `[[`, 1) 
# [[1]] 
# [1] 1 2 3 
# 
# [[2]] 
# [1] 10 11 12 
tun

Warum kann ich nicht verwenden, um die „$“ funktionieren auf die gleiche Art und Weise

lapply(dflist, `$`, "a") 
# [[1]] 
# NULL 
# 
# [[2]] 
# NULL 

Aber diese beiden Arbeiten:

lapply(dflist, function(x) x$a) 
`$`(dflist[[1]], "a") 

Mir ist klar, dass in diesem Fall ein

lapply(dflist, `[[`, "a") 

aber ich arbeitete mit einem S4-Objekt verwenden können, die nicht die Indizierung über [[ zu ermöglichen schien. Zum Beispiel

library(adegenet) 
data(nancycats) 
catpop <- genind2genpop(nancycats) 
mylist <- list(catpop, catpop) 

#works 
catpop[[1]]$tab 

#doesn't work 
lapply(mylist, "$", "tab") 
# Error in slot(x, name) : 
# no slot of name "..." for this object of class "genpop" 

#doesn't work 
lapply(mylist, "[[", "tab") 
# Error in FUN(X[[1L]], ...) : this S4 class is not subsettable 
+0

Dieses funktioniert 'lapply (dflist, Funktion (x) "$"(x, "a")) zu verwenden, '. – Tim

+1

Schöne Frage. Fyi, die Antwort ist irgendwie auffindbar mit 'Methoden (" $ ", dflist [[1]])' – Frank

+2

Nun @ Frank, es ist nicht, dass ich nicht bewusst war, dass '$ .data.frame 'existierte, bin ich nur überrascht Das Problem wurde durch das Versenden von Methoden verursacht. Ich kann mir nicht viele andere Fälle vorstellen, in denen Sie explizit eine Form einer generischen Funktion aufrufen müssen. – MrFlick

Antwort

27

Für das erste Beispiel, können Sie einfach tun:

lapply(dflist, `$.data.frame`, "a") 

Für die zweite, verwenden Sie die slot() Accessorfunktion

lapply(mylist, "slot", "tab") 

Ich bin nicht sicher warum Methodenversand funktioniert nicht im ersten Fall, aber die Note Abschnitt ?lapply nicht adressiert genau diese Frage seiner borked Methode Dispatch für primitive Funktionen wie $:

Note: 

[...] 

For historical reasons, the calls created by ‘lapply’ are 
unevaluated, and code has been written (e.g., ‘bquote’) that 
relies on this. This means that the recorded call is always of 
the form ‘FUN(X[[i]], ...)’, with ‘i’ replaced by the current 
(integer or double) index. This is not normally a problem, but it 
can be if ‘FUN’ uses ‘sys.call’ or ‘match.call’ or if it is a 
primitive function that makes use of the call. This means that it 
is often safer to call primitive functions with a wrapper, so that 
e.g. ‘lapply(ll, function(x) is.numeric(x))’ is required to ensure 
that method dispatch for ‘is.numeric’ occurs correctly. 
+0

Vielen Dank für Ihre Einsichten. Die Funktion 'slot()' ist das, wonach ich am Ende wirklich gesucht habe, also schätze ich es, dass Sie mich darauf aufmerksam gemacht haben. Ich habe eine weitere Antwort hinzugefügt, die in diesem Fall näher an das "Warum" herankommt. Es geht mehr um die generische '$' Implementierung als um 'lapply()' von dem, was ich an dieser Stelle verstehe. – MrFlick

11

So scheint es, dass dieses Problem mehr mit $ zu tun hat und wie es erwartet typischerweise nicht notieren Namen als zweiten Parameter anstatt Strings. Schauen Sie sich dieses Beispiel

dflist <- list(
    data.frame(a=1:3, z=31:33), 
    data.frame(b=10:12, a=4:6, z=31:33) 
) 
lapply(dflist, 
    function(x, z) { 
     print(paste("z:",z)); 
     `$`(x,z) 
    }, 
    z="a" 
) 

Wir sehen die Ergebnisse

[1] "z: a" 
[1] "z: a" 
[[1]] 
[1] 31 32 33 

[[2]] 
[1] 31 32 33 

so der z Wert wird auf „ein“ gesetzt, aber $ nicht den zweiten Parameter zu bewerten. Daher gibt es die Spalte "z" anstatt die Spalte "a" zurück. Dies führt zu diesem interessanten Satz von Ergebnissen

a<-"z"; `$`(dflist[[1]], a) 
# [1] 1 2 3 
a<-"z"; `$`(dflist[[1]], "z") 
# [1] 31 32 33 

a<-"z"; `$.data.frame`(dflist[[1]], a) 
# [1] 31 32 33 
a<-"z"; `$.data.frame`(dflist[[1]], "z") 
# [1] 31 32 33 

Wenn wir rufen $.data.frame direkt sind wir den Standard deparsing Umgehung, die Disposition in der primitiven vor auftritt (das nahe here in der Quelle passiert).

Der hinzugefügte Catch mit lapply ist, dass es Argumente an die Funktion über den ... Mechanismus weiterleitet. Zum Beispiel

lapply(dflist, function(x, z) sys.call()) 
# [[1]] 
# FUN(X[[2L]], ...) 

# [[2]] 
# FUN(X[[2L]], ...) 

Das bedeutet, dass, wenn $ aufgerufen wird, die ... auf den String "..." deparses.Dies erklärt dieses Verhalten

dflist<- list(data.frame(a=1:3, "..."=11:13, check.names=F)) 
lapply(dflist, `$`, "a") 
# [[1]] 
# [1] 11 12 13 

gleiche passiert, wenn Sie versuchen, ... sich

f<-function(x,...) `$`(x, ...); 

f(dflist[[1]], "a"); 
# [1] 11 12 13 
`$`(dflist[[1]], "a") 
# [1] 1 2 3 
+0

Ich fühle mich, als ob ich dicht sein könnte, aber ich verstehe nicht, wie das erklärt, warum '' lapply (dflist, '$', "a") '' NULL' zurückgibt. Immerhin gibt "$" (dflist [[1]], "z") '' 31: 33' zurück, aber der scheinbar äquivalente Aufruf, '' lapply (dflist [1], '$', "z) '', gibt 'NULL' zurück ... Was fehlt mir? –

+0

Ah, ok. Nun, es gibt eine zusätzliche Ebene mit 'lapply'. Er übergibt Parameter mit '...'. Was passiert, wenn Sie den Aufruf abfangen, sehen Sie, dass der zweite an die Funktion übergebene Parameter "..." ist. Also hast du recht. Es hat auch damit zu tun, wie die Argumente über "..." geladen werden. Ich werde das auch hinzufügen. – MrFlick

+1

Oh, Mann, ich verstehe, worauf Sie hinauswollen. Das ist faszinierend! Sieh dir das an: '' df <- data.frame ("..." = 1: 3, z = 31: 33); dflist <- Liste (df, df); lapply (dflist, '$', "z") '' –

Verwandte Themen