lapply失败,但函数适用于每个单独的输入参数

时间:2013-01-19 02:29:39

标签: r

非常感谢任何建议或提示。 我正在使用数据框。简化编码如下: `

f<-funtion(name){
    x<-tapply(name$a,list(name$b,name$c),sum)
1)  y<-dataset[[deparse(substitute(name))]]
    #where dataset is an already existed list object with names the same as the 
    #function argument. I would like to avoid inputting two arguments.
    z<-vector("list",n) #where n is also defined already
2)  for (i in 1:n){z[[i]]<-x[y[[i]],i]}
    ...
}
lapply(list_names,f) 

`

警告信息是:   在is.na(x)中:is.na()应用于'NULL'类型的非(列表或向量)

并且输出不正确。我试过调试,发现冲突可能在第1)和第2行。但是,当我尝试f(名称)时,它非常精细且输出正确。我想问题是在lapply,我搜索了一段时间,但无法达到目的。有任何想法吗?非常感谢!

数据的结构

谢谢Joran。再次检查我发现问题可能不在我所描述的内容中。我按如下方式生成完整代码,您可以复制粘贴以查看错误。

n<-4
name1<-data.frame(a=rep(0.1,20),b=rep(1:10,each=2),c=rep(1:n,each=5),
                  d=rep(c("a1","a2","a3","a4","a5","a6","a7","a8","a9","a91"),each=2))
name2<-data.frame(a=rep(0.2,20),b=rep(1:10,each=2),c=rep(1:n,each=5),
                  d=rep(c("a1","a2","a3","a4","a5","a6","a7","a8","a9","a91"),each=2))
name3<-data.frame(a=rep(0.3,20),b=rep(1:10,each=2),c=rep(1:n,each=5),
                  d=rep(c("a1","a2","a3","a4","a5","a6","a7","a8","a9","a91"),each=2))
#d is the name for the observations. d corresponds to b.
dataset<-vector("list",3)
names(dataset)<-c("name1","name2","name3")
dataset[[1]]<-list(c(1,2),c(1,2,3,4),c(1,2,3,4,5,10),c(4,5,8))
dataset[[2]]<-list(c(1,2,3,5),c(1,2),c(1,2,10),c(2,3,4,5,8,10))
dataset[[3]]<-list(c(3,5,8,10),c(1,2,5,7),c(1,2,3,4,5),c(2,3,4,6,9))
f<-function(name){
  x<-tapply(name$a,list(name$b,name$c),sum)
  rownames(x)<-sort(unique(name$d)) #the row names for 
  y<-dataset[[deparse(substitute(name))]]
  z<-vector("list",n)
  for (i in 1:n){
    z[[i]]<-x[y[[i]],i]}
  nn<-length(unique(unlist(sapply(z,names)))) # the number of names appeared
  names_<-sort(unique(unlist(sapply(z,names)))) # the names appeared add to the matrix 
                                                # below
  m<-matrix(,nrow=nn,ncol=n);rownames(m)<-names_
  index<-vector("list",n)
  for (i in 1:n){
    index[[i]]<-match(names(z[[i]]),names_)
    m[index[[i]],i]<-z[[i]]
  }
  return(m)
}
list_names<-vector("list",3)
list_names[[1]]<-name1;list_names[[2]]<-name2;list_names[[3]]<-name3
names(list_names)<-c("name1","name2","name3")
lapply(list_names,f)
f(name1)

lapply(list_names,f)会失败,但是f(name1)会产生我想要的矩阵。再次感谢。

1 个答案:

答案 0 :(得分:5)

为什么它不起作用

问题是调用堆栈在两种情况下看起来都不一样。在lapply中,它看起来像

[[1]]
lapply(list_names, f) # lapply(X = list_names, FUN = f)

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

在正在评估的表达式中,f被称为FUN,其参数name被称为X[[1L]]

直接拨打f时,堆栈只是

[[1]]
f(name1) # f(name = name1)

通常这没关系,但是substitute确实如此,因为substitute关心函数参数的名称,而不是它的值。当你到达

y<-dataset[[deparse(substitute(name))]]

lapply内,它正在寻找名为dataset的{​​{1}}中的元素,而没有一个元素,因此X[[1L]]绑定到y

让它发挥作用的一种方法

处理此问题的最简单方法可能是让NULL对字符串进行操作并将f传递给lapply。通过将names(list_names)的开头更改为

,可以非常轻松地完成此操作
f

并将f<-function(name){ passed.name <- name name <- list_names[[name]] x<-tapply(name$a,list(name$b,name$c),sum) rownames(x)<-sort(unique(name$d)) #the row names for y<-dataset[[passed.name]] # the rest of f... 更改为lapply(list_names, f)。这应该通过几乎最小的修改为您提供所需的内容,但您也可以考虑重命名一些变量,因此单词lapply(names(list_names),f)不会用于许多不同的东西 - 函数namenames的参数,以及包含f的所有各种变量。