从for循环到申请

时间:2011-03-28 13:33:17

标签: r loops statistics apply

我是R的新手 所以我不确定如何使用申请。 我想使用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   

2 个答案:

答案 0 :(得分: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]

答案 1 :(得分: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所指出的那样 - 你在每次循环迭代中都在增长你的数组。在循环之前预先分配整个数组,您将看到显着的加速。