大多数专业用户建议我永远不要在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)
谢谢!
在这里你可以避免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)
正如您对@ 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在很大范围内保存一些其他函数的情况.