lapply z funkcją"$"
Powiedzmy, że mam listę danych.ramki
dflist <- list(data.frame(a=1:3), data.frame(b=10:12, a=4:6))
Jeśli chcę wyodrębnić pierwszą kolumnę z każdej pozycji na liście, mogę zrobić
lapply(dflist, `[[`, 1)
# [[1]]
# [1] 1 2 3
#
# [[2]]
# [1] 10 11 12
Dlaczego nie mogę używać funkcji "$" w ten sam sposób
lapply(dflist, `$`, "a")
# [[1]]
# NULL
#
# [[2]]
# NULL
Ale oba działają:
lapply(dflist, function(x) x$a)
`$`(dflist[[1]], "a")
Zdaję sobie sprawę, że w tym przypadku można użyć
lapply(dflist, `[[`, "a")
Ale pracowałem z obiektem S4, który nie pozwalał na indeksowanie przez [[
. Na przykład
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
2 answers
Dla pierwszego przykładu, można po prostu zrobić:
lapply(dflist, `$.data.frame`, "a")
Dla drugiej, użyj slot()
funkcji accessor
lapply(mylist, "slot", "tab")
Nie jestem pewien Dlaczego metoda dispatch nie działa w pierwszym przypadku, ale Note
sekcja ?lapply
rozwiązuje ten sam problem swojej metody borked dispatch dla prymitywnych funkcji, takich jak $
:
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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-08 20:22:28
Wydaje się więc, że ten problem ma więcej wspólnego z $
i tym, jak zwykle oczekuje nienotowanych nazw jako drugiego parametru, a nie łańcuchów. Spójrz na ten przykład
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"
)
Widzimy wyniki
[1] "z: a"
[1] "z: a"
[[1]]
[1] 31 32 33
[[2]]
[1] 31 32 33
Więc z
wartość jest ustawiana na "a", ale $
nie ocenia drugiego parametru. Więc zwraca kolumnę " z "zamiast kolumny" a". Prowadzi to do tego interesującego zestawu wyników
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
Kiedy wywołujemy $.data.frame
bezpośrednio omijamy standardowe odejście, które występuje w prymitywnym przed wysyłaniem (co dzieje się w pobliżu tutaj w źródle).
Dodany haczyk z {[10] } polega na tym, że przekazuje on argumenty do funkcji za pośrednictwem mechanizmu ...
. Na przykład
lapply(dflist, function(x, z) sys.call())
# [[1]]
# FUN(X[[2L]], ...)
# [[2]]
# FUN(X[[2L]], ...)
Oznacza to, że gdy wywoływane jest $
, odchodzi ...
do łańcucha "..."
. To wyjaśnia to zachowanie
dflist<- list(data.frame(a=1:3, "..."=11:13, check.names=F))
lapply(dflist, `$`, "a")
# [[1]]
# [1] 11 12 13
To samo dzieje się, gdy próbujesz użyć ...
siebie
f<-function(x,...) `$`(x, ...);
f(dflist[[1]], "a");
# [1] 11 12 13
`$`(dflist[[1]], "a")
# [1] 1 2 3
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-08 21:25:30