1

我是使用 R 的新手。所以我不确定如何使用 apply。我想使用 apply 来加速我的功能:

for(i in 1: ncol(exp)){
 for (j in 1: length(fe)){
  tmp =TRUE
  id = strsplit(colnames(exp)[i],"\\.")
  if(id == fe[j]){
   tmp = FALSE
  }
  if(tmp ==TRUE){
   only = cbind(only,c(names(exp)[i],exp[,i]) )
  }
 }
}

我怎样才能使用apply函数来做到这一点?

编辑 :

非常感谢您的非常好的解释,并对我的错误描述感到抱歉。您猜对了,但是当想删除 fe 中的匹配项时。

Exp <- data.frame(A.x=1:10,B.y=10:1,C.z=11:20,A.z=20:11)

fe<-LETTERS[1:2]

那么结果应该只是带有“C”的列名。其他所有内容都应删除。

1   C.z 
2    11 
3    12   
4    13   
5    14 
6    15  
7    16  
8    17  
9    18   
10   19  
11   20   
4

2 回答 2

4

编辑:如果您只想删除名称出现在 fe 中的列,您可以简单地执行以下操作:

Exp <- data.frame(A.x=1:10,B.y=10:1,C.z=11:20,A.z=20:11)
fe<-LETTERS[1:2]

id <- sapply(strsplit(names(Exp),"\\."),
    function(i)!i[1] %in% fe)
Exp[id]

这段代码和你的(更新的)for循环一样,只是效率更高。您不必循环遍历 fe,该%in%函数是矢量化的。

如果名称可以出现在点之间的任何位置,则

id <- sapply(strsplit(names(Exp),"\\."),
    function(i)sum(i %in% fe)==0)

你的代码做了一些非常有趣的事情,我不知道你到底想做什么。一方面,strsplit给出一个列表,所以id == fe[j]总是返回 false,除非fe[j]是一个列表本身。而且我怀疑它是...所以我将您的代码更正为

id = strsplit(colnames(Exp)[i],"\\.")[[1]][1]

如果您想与点之前的所有内容进行比较,或者

id = unlist(strsplit(colnames(Exp)[i],"\\.")) 

如果您想与字符串中的所有内容进行比较。在这种情况下,您也应该使用%in%而不是==

其次,你得到的是一个字符矩阵,它本质上乘以行。如果 fe[j] 中的所有元素都是唯一的,您也可以这样做:

only <- rbind(names(exp),exp)
only <- do.call(cbind,lapply(mat,function(x) 
       matrix(rep(x,ncol(exp)-1),nrow=nrow(exp)+1)
))

假设您的代码中的逻辑确实有意义(因为您没有应用一些不可能知道的示例数据),优化运行:

mat <- rbind(names(Exp),Exp)

do.call(cbind,
    lapply(mat, function(x){
        n <- sum(!fe %in% strsplit(x[1],"\\.")[[1]][1])
        matrix(rep(x,n),nrow=nrow(mat))
}))

请注意 - 如果您对 fe[j] 出现在名称中的任何位置感兴趣 - 您可以将代码更改为:

do.call(cbind,
    lapply(mat, function(x){
        n <- sum(!fe %in% unlist(strsplit(x[1],"\\.")))
        matrix(rep(x,n),nrow=nrow(mat))
}))

如果这没有返回您想要的,那么您的代码也不会这样做。我检查了以下示例数据,并且都给出了相同的结果:

Exp <- data.frame(A.x=1:10,B.y=10:1,C.z=11:20,A.z=20:11)
fe <- LETTERS[1:4]
于 2011-03-28T14:11:38.583 回答
2

函数族apply()是便利函数。它们不一定比编写良好的 for 循环或矢量化函数更快。例如:

set.seed(21)
x <- matrix(rnorm(1e6),5e5,2)

system.time({
  yLoop <- x[,1]*0  # preallocate result
  for(i in 1:NROW(yLoop)) yLoop[i] <- mean(x[i,])
})
#    user  system elapsed 
#   13.39    0.00   13.39 
system.time(yApply <- apply(x, 1, mean))
#    user  system elapsed 
#   16.19    0.28   16.51
system.time(yRowMean <- rowMeans(x))
#    user  system elapsed 
#    0.02    0.00    0.02
identical(yLoop,yApply,yRowMean)
# TRUE

您的代码如此缓慢的原因是 - 正如 Gavin 指出的那样 - 您正在为每次循环迭代增加数组。在循环之前预分配整个数组,您将看到显着的加速。

于 2011-03-28T14:22:11.343 回答