如何将apply等效于任何for循环

Shr*_*yes 5 r apply

大多数专业用户建议我永远不要在R中使用循环.请改用apply函数.问题是,如果您不熟悉函数式编程,那么为每个for/while循环编写一个应用等效项并不是那么直观.以下面的例子为例.

F <- data.frame(name = c("a", "b", "c", "d"), var1 = c(1,0,0,1), var2 = c(0,0,1,1),  
var3 = c(1,1,1,1), clus = c("one", "two", "three", "four"))
F$ObjTrim <- ""
for (i in 1:nrow(F))
{
 for (j in 2:(ncol(F)-1))
{
 if(F[i, j] == 1) 
 {F$ObjTrim[i]  <- paste(F$ObjTrim[i], colnames(F)[j], sep = " ") }

 }
  print(i)
}
Run Code Online (Sandbox Code Playgroud)

这里的目标是创建一个变量"ObjTrim",它接受所有具有值== 1的列名的值.有人可以建议一个等同于此的良好应用吗?

例如,上面的代码将给出:

 name var1 var2 var3  clus         ObjTrim
1    a    1    0    1   one       var1 var3
2    b    0    0    1   two            var3
3    c    0    1    1 three       var2 var3
4    d    1    1    1  four  var1 var2 var3
Run Code Online (Sandbox Code Playgroud)

谢谢!

ags*_*udy 5

在这里你可以避免for循环使用vectorization:colSums这里矢量化基本上用于将矢量c(TRUE,FALSE)转换为0或1.

 colnames(F)[colSums(F==1) != 0] ## create 
Run Code Online (Sandbox Code Playgroud)

这里使用我可重复的示例进行测试:

set.seed(1234)
## create matrix 2*10
F <- matrix(sample(c(1:5),20,rep=TRUE),nrow=2,
            dimnames = list(c('row1','row2'),paste0('col',1:10)))

#        col1 col2 col3 col4 col5 col6 col7 col8 col9 col10
# row1    1    4    5    1    4    4    2    2    2     1
# row2    4    4    4    2    3    3    5    5    2     2
colnames(F)[colSums(F==1) != 0]
"col1"  "col4"  "col10"
Run Code Online (Sandbox Code Playgroud)

PS:通常很容易用for"R风格的解决方案" 替换循环,但是在某些情况下,当有递归时特别难以/不可能这样做

编辑

在OP澄清之后,这里有一个apply解决方案:

F$ObjTrim <- apply(F,1,function(x) paste(colnames(F)[x==1],collapse=' '))

 name var1 var2 var3  clus        ObjTrim
1    a    1    0    1   one      var1 var3
2    b    0    0    1   two           var3
3    c    0    1    1 three      var2 var3
4    d    1    1    1  four var1 var2 var3
Run Code Online (Sandbox Code Playgroud)


cbe*_*ica 5

正如您对@ agstudy的回答所说,您确实希望每行都有这个,这可能对您有所帮助:

df <- F [, 2:4]
df
#   var1 var2 var3
# 1    1    0    1
# 2    0    0    1
# 3    0    1    1
# 4    1    1    1

ones <- which (df == 1, arr.ind=TRUE)
ones
#      row col
# [1,]   1   1
# [2,]   4   1
# [3,]   3   2
# [4,]   4   2
# [5,]   1   3
# [6,]   2   3
# [7,]   3   3
# [8,]   4   3
Run Code Online (Sandbox Code Playgroud)

你可以aggregate按行:

aggregate (col ~ row, ones, paste)
#   row     col
# 1   1    1, 3
# 2   2       3
# 3   3    2, 3
# 4   4 1, 2, 3
Run Code Online (Sandbox Code Playgroud)

如果您坚持使用colnames而不是索引,请首先替换cols ones:

ones <- as.data.frame (ones) 
ones$col <- colnames (df)[ones$col]
aggregate (col ~ row, ones, paste)
#   row              col
# 1   1       var1, var3
# 2   2             var3
# 3   3       var2, var3
# 4   4 var1, var2, var3
Run Code Online (Sandbox Code Playgroud)

当然,你也可以apply沿着行使用:

apply (df, 1, function (x) paste (colnames (df) [x == 1], collapse = " "))
# [1] "var1 var3"       "var3"             "var2 var3"       "var1 var2 var3"
Run Code Online (Sandbox Code Playgroud)

对于您的问题,存在矢量化函数,因此既不需要for循环也不apply需要.

但是,有些情况下for循环更清晰(读取速度更快),有时也更快计算替代方案.特别是在循环几次时允许使用矢量化函数并apply在很大范围内保存一些其他函数的情况.