R:使用 for 循环将因子的级别部分匹配到字符串? [复制]

Posted

技术标签:

【中文标题】R:使用 for 循环将因子的级别部分匹配到字符串? [复制]【英文标题】:R: Using a for loop to partially match levels of a factor to a character string? [duplicate] 【发布时间】:2015-10-14 18:20:07 【问题描述】:

我有一个地块和子地块的数据集,我在其中测量了树种的存在。我正在尝试遍历数据并确定每个地块-子地块组合中存在哪些物种。

我已经成功创建了一个数据框,可以识别每个地块-子地块组合中存在哪些物种,但现在我正在尝试为每个物种附加列,其中包含显示它们存在的指示变量(值 1)。

初始代码/data.frame 如下所示:

f = aggregate(Species ~ Subplot + Plot, data = live.trees, 
              FUN=function(x) paste(unique(x), collapse=', '))

a=rep(0, 35)
b=cbind(a,a,a,a,a,a,a,a,a,a,a,a)
colnames(b) = levels(live.trees$Species)
freq = as.data.frame(cbind(f, b))

Species = as.factor(live.trees$Species)

#Only showing 2 of 7 plots here...

freq[1:10,]
   Subplot Plot                    Species AA AM AO BC BG BP EA RA RM SH XG XM
1        1    1                         RA  0  0  0  0  0  0  0  0  0  0  0  0
2        2    1 EA, BP, XM, BC, AA, XG, RA  0  0  0  0  0  0  0  0  0  0  0  0
3        3    1         EA, XG, AA, AM, RA  0  0  0  0  0  0  0  0  0  0  0  0
4        4    1             AA, XM, RA, EA  0  0  0  0  0  0  0  0  0  0  0  0
5        5    1             EA, BC, RA, AA  0  0  0  0  0  0  0  0  0  0  0  0
6        1    2             XM, BC, RA, AM  0  0  0  0  0  0  0  0  0  0  0  0
7        2    2                     RM, RA  0  0  0  0  0  0  0  0  0  0  0  0
8        3    2                 XM, BC, RA  0  0  0  0  0  0  0  0  0  0  0  0
9        4    2                     RA, XM  0  0  0  0  0  0  0  0  0  0  0  0
10       5    2     XM, XG, AA, BC, BG, RA  0  0  0  0  0  0  0  0  0  0  0  0

我现在正在尝试编写一个贯穿表格的 for 循环,并在每个物种列(AA、AM、AO 等)中粘贴一个“1”,如果物种的两个字符串在下匹配freq$Species 列。到目前为止,我编写的 for 循环代码是:

#Manually going through and assigning a 1 value for each species 
#using a partial string match with grepl()

    for(k in 1:nrow(freq))
  if(grepl("AA", freq$Species[[k]]) == "TRUE")
    (freq$AA[k] = 1) else
    if(grepl("AM", freq$Species[[k]]) == "TRUE")
      (freq$AM[k] = 1) else
        if(grepl("AO", freq$Species[[k]]) == "TRUE")
          (freq$AO[k] = 1) else
            if(grepl("BC", freq$Species[[k]]) == "TRUE")
              (freq$BC[k] = 1)
                  #.... etc. (cutting off here to save space)

代码在一定程度上可以工作,但会覆盖之前的每个 Species 列,而且也很笨重。

Subplot Plot                    Species AA AM AO BC BG BP EA RA RM SH XG XM
1        1    1                         RA  0  0  0  0  0  0  0  0  0  0  0  0
2        2    1 EA, BP, XM, BC, AA, XG, RA  1  0  0  0  0  0  0  0  0  0  0  0
3        3    1         EA, XG, AA, AM, RA  1  0  0  0  0  0  0  0  0  0  0  0
4        4    1             AA, XM, RA, EA  1  0  0  0  0  0  0  0  0  0  0  0
5        5    1             EA, BC, RA, AA  1  0  0  0  0  0  0  0  0  0  0  0
6        1    2             XM, BC, RA, AM  0  1  0  0  0  0  0  0  0  0  0  0
7        2    2                     RM, RA  0  0  0  0  0  0  0  0  0  0  0  0
8        3    2                 XM, BC, RA  0  0  0  1  0  0  0  0  0  0  0  0
9        4    2                     RA, XM  0  0  0  0  0  0  0  0  0  0  0  0
10       5    2     XM, XG, AA, BC, BG, RA  1  0  0  0  0  0  0  0  0  0  0  0

我该怎么做:

1) 获取 for 循环以停止覆盖先前列中的物种存在指示符?

2) 以更优雅的方式编写 for 循环?我想我可以创建一个名为“Species”的因子变量并循环遍历其中的元素(在第一个 for 循环中)......但是我的新手级经验开始显示。

任何帮助或建议将不胜感激!

我知道这不是一个可重复的示例,但我正在寻找一般性建议或技巧,以帮助我指明正确的方向。我将尝试在 R 中找到一个默认数据集,我可以强制它同时复制我的麻烦。

提前谢谢你!

注意: Species 列是作为字符串创建的,因此属于类字符。

【问题讨论】:

较早的/帖子不知何故从我身边溜走了。感谢您指出! 下一步 - 将每个地块中每个物种的值相加 - 也难倒我。我可以使用 aggregate() aggregate(AA ~ Plot, data=freq, sum) 逐个物种地进行操作,但是,我不确定是否有一种更优雅的方式可以同时对所有物种进行操作。我想还有一种方法可以使用 sapply 来做到这一点,但是 R 在我的尝试中抛出了错误......@akrun 【参考方案1】:

试试

library(qdapTools)
res <- cbind(freq[1:3], mtabulate(strsplit(freq$Species, ', ')))
rowsum(res[,4:ncol(res)], group= res$Plot)
#  AA AM BC BG BP EA RA RM XG XM
#1  4  1  2  0  1  4  5  0  2  2
#2  1  1  3  1  0  0  5  1  1  4

或者

aggregate(.~Plot, res[c(2,4:ncol(res))], FUN=sum)
#   Plot AA AM BC BG BP EA RA RM XG XM
#1    1  4  1  2  0  1  4  5  0  2  2
#2    2  1  1  3  1  0  0  5  1  1  4

或者

library(dplyr)
res %>%
   group_by(Plot) %>%
   summarise_each(funs(sum), 4:ncol(res))

或者

library(data.table)
setDT(res)[, lapply(.SD, sum), by =Plot, .SDcols=4:ncol(res)]

数据

freq <- structure(list(Subplot = c(1L, 2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L, 
5L), Plot = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L), Species = c("RA", 
"EA, BP, XM, BC, AA, XG, RA", "EA, XG, AA, AM, RA", "AA, XM, RA, EA", 
"EA, BC, RA, AA", "XM, BC, RA, AM", "RM, RA", "XM, BC, RA", "RA, XM", 
"XM, XG, AA, BC, BG, RA"), AA = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 
0L, 0L, 0L), AM = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), 
    AO = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), BC = c(0L, 
    0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), BG = c(0L, 0L, 0L, 0L, 
    0L, 0L, 0L, 0L, 0L, 0L), BP = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 
    0L, 0L, 0L), EA = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L
    ), RA = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), RM = c(0L, 
    0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L), SH = c(0L, 0L, 0L, 0L, 
    0L, 0L, 0L, 0L, 0L, 0L), XG = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 
    0L, 0L, 0L), XM = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L
    )), .Names = c("Subplot", "Plot", "Species", "AA", "AM", 
"AO", "BC", "BG", "BP", "EA", "RA", "RM", "SH", "XG", "XM"), 
 class = "data.frame", row.names = c("1", 
"2", "3", "4", "5", "6", "7", "8", "9", "10"))

【讨论】:

OP 仅提供部分数据集。在完整的数据集中,这应该匹配结果 也很有帮助。谢谢。 @jbukoski 我更新了帖子。你能检查一下这是否是你想要的吗? 完美。但是,出于我的目的,不需要对 Plot 列求和(即 c(4:ncol(res)) 而不是 c(2,4:ncol(res)) )。小问题,感谢您的帮助! @jbukoski 也更新了 data.table 和 dplyr 方法。

以上是关于R:使用 for 循环将因子的级别部分匹配到字符串? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

有没有一种方法可以基于for循环中匹配的文件名在r中创建列表?

Pandas 使用 for 循环在部分字符串匹配上设置列:使用包含 NaN 的向量进行错误索引

R语言 因子

将数组 [in] 从 for 循环存储到返回未定义的新数组

将因子级别转换为R中的数字

如何使用 dplyr 将跨因子级别的分组计数保存到新变量中?