2015-05-08 5 views
35

Скажем, у меня есть список data.frames

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

Если я хочу, чтобы извлечь первый столбец из каждого элемента в списке, я могу сделать

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

Почему я не могу использовать функцию «$» таким же образом

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

Но обе эти работы:

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

Я понимаю, что в этом случае можно было бы использовать

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

, но я работал с объектом S4, не похоже, чтобы позволить индексацию через [[. Например

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

Это один работает 'lapply (dflist, функция (х) "$"(х, "а")) '. – Tim

+1

Хороший вопрос. Fyi, ответ - это вид findable с 'методами (" $ ", dflist [[1]]) – Frank

+2

Ну @Frank, это не значит, что я не знал, что' $ .data.frame' существует, я просто удивлен проблема была вызвана методом диспетчеризации. Я не могу думать о многих других случаях, когда вам нужно явно называть одну форму общей функции. – MrFlick

ответ

27

Для первого примера, вы можете просто сделать:

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

Для второго, используйте функцию slot() аксессора

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

Я не уверен, Почему Метод отправки не работает в первом случае, но Note раздел ?lapply ли решение этой проблемы и ее BORKED метод отправки для примитивных функций, таких как $:

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

Большое спасибо за понимание. Функция 'slot()' - это то, что я действительно сделал в конце, поэтому я ценю, что вы привлекли это к моему вниманию. Я добавил еще один ответ, который, я думаю, ближе к «почему» в этом случае. Это действительно больше об общей реализации '$', а не 'lapply()' от того, что я понимаю на данный момент. – MrFlick

11

Таким образом, кажется, что эта проблема имеет больше общего с $ и как это обычно ожидает некотируемые имена в качестве второго параметра а не строк. Посмотрите на этот пример

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" 
) 

Мы видим результаты

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

[[2]] 
[1] 31 32 33 

поэтому значение z в настоящее время устанавливается на «а», но $ не оценки второго параметра. Поэтому он возвращает столбец «z», а не столбец «a». Это приводит к этому интересному набору результатов

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 

Когда мы называем $.data.frame непосредственно мы в обход стандартного deparsing, что происходит в примитив до диспетчерской (что происходит вблизи here в источнике).

Добавленный улов с lapply состоит в том, что он передает аргументы функции через механизм .... Например

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

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

Это означает, что, когда $ вызывается, он deparses в ... на строку "...".Это объясняет такое поведение

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

То же самое происходит, когда вы пытаетесь использовать ... себя

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

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

Я чувствую, что могу быть плотным, но я не совсем понимаю, как это объясняет, почему '' lapply (dflist, '$', "a") '' возвращает 'NULL'. В конце концов, '' $ "(dflist [[1]]," z ")' возвращает '31: 33', но, по-видимому, эквивалентный вызов' 'lapply (dflist [1],' $ '," z ") '', возвращает 'NULL' ... Что мне не хватает? –

+0

А, ок. ну, есть дополнительный уровень с 'lapply'. Он передает параметры с помощью '...'. Итак, что происходит, если вы перехватите вызов, вы увидите, что второй параметр, переданный функции, - «...». Значит, ты прав. Это также связано с тем, как lapply аргументирует аргументы через '...'. Я тоже добавлю это. – MrFlick

+1

О, мужик, я вижу, к чему ты клонишь. Это увлекательно! Проверьте это: '' df <- data.frame ("..." = 1: 3, z = 31: 33); dflist <- list (df, df); lapply (dflist, '$', "z") '' –

Смежные вопросы