在多个组中计算连续的0和1字符串

时间:2014-11-20 19:38:17

标签: r count dataframe

有几个关于使用 rle cumsum 等函数计算连续的0和1(或其他值)字符串的讨论。我玩过这些功能,但我不能轻易弄清楚如何让它们适用于我的具体问题。

我正在处理按时间(“年”)和位置(“id”)组织的生态存在/缺失数据(“pres.abs”= 1或0)。对于每个位置id,我想分别计算连续1和0的长度。如果无法计算,我想返回“NA”。

以下是数据外观(前3列)和我希望实现的输出(最后2列)的示例。理想情况下,这将是一个非常快速的函数,避免for循环,因为实际数据帧包含~15,000行。

year = rep(1:10, times=3)
id = c(rep(1, times=10), rep(2, times=10), rep(3, times=10))
pres.abs.id.1 = c(0, 0, 0, 1, 1, 1, 0, 0, 1, 1) #Pres/abs data at site 1 across time
pres.abs.id.2 = c(1, 1, 0, 1, 0, 0, 1, 0, 0, 0) #Pres/abs data at site 2 across time
pres.abs.id.3 = c(0, 0, 0, 0, 0, 1, 1, 1, 1, 1) #Pres/abs data at site 3 across time
pres.abs = c(pres.abs.id.1, pres.abs.id.2, pres.abs.id.3)
dat = data.frame(id, year, pres.abs)

dat$cumul.zeroes = c(1,2,3,NA,NA,NA,1,2,NA,NA,NA,NA,1,NA,1,2,NA,1,2,3,1,2,3,4,5,NA,NA,NA,NA,NA)
dat$cumul.ones = c(NA,NA,NA,1,2,3,NA,NA,1,2,1,2,NA,1,NA,NA,1,NA,NA,NA,NA,NA,NA,NA,NA,1,2,3,4,5)

> dat
   id year pres.abs cumul.zeroes cumul.ones
1   1    1        0            1         NA
2   1    2        0            2         NA
3   1    3        0            3         NA
4   1    4        1           NA          1
5   1    5        1           NA          2
6   1    6        1           NA          3
7   1    7        0            1         NA
8   1    8        0            2         NA
9   1    9        1           NA          1
10  1   10        1           NA          2
11  2    1        1           NA          1
12  2    2        1           NA          2
13  2    3        0            1         NA
14  2    4        1           NA          1
15  2    5        0            1         NA
16  2    6        0            2         NA
17  2    7        1           NA          1
18  2    8        0            1         NA
19  2    9        0            2         NA
20  2   10        0            3         NA
21  3    1        0            1         NA
22  3    2        0            2         NA
23  3    3        0            3         NA
24  3    4        0            4         NA
25  3    5        0            5         NA
26  3    6        1           NA          1
27  3    7        1           NA          2
28  3    8        1           NA          3
29  3    9        1           NA          4
30  3   10        1           NA          5

非常感谢你的帮助。

2 个答案:

答案 0 :(得分:3)

这是使用rlesequence的基本R方式:

dat <- within(dat, {
    cumul.counts <- unlist(lapply(split(pres.abs, id), function(x) sequence(rle(x)$lengths)))
    cumul.zeroes <- replace(cumul.counts, pres.abs == 1, NA)
    cumul.ones <- replace(cumul.counts, pres.abs == 0, NA)
    rm(cumul.counts)
})

#    id year pres.abs cumul.ones cumul.zeroes
# 1   1    1        0         NA            1
# 2   1    2        0         NA            2
# 3   1    3        0         NA            3
# 4   1    4        1          1           NA
# 5   1    5        1          2           NA
# 6   1    6        1          3           NA
# 7   1    7        0         NA            1
# 8   1    8        0         NA            2
# 9   1    9        1          1           NA
# 10  1   10        1          2           NA
# 11  2    1        1          1           NA
# 12  2    2        1          2           NA
# 13  2    3        0         NA            1
# 14  2    4        1          1           NA
# 15  2    5        0         NA            1
# 16  2    6        0         NA            2
# 17  2    7        1          1           NA
# 18  2    8        0         NA            1
# 19  2    9        0         NA            2
# 20  2   10        0         NA            3
# 21  3    1        0         NA            1
# 22  3    2        0         NA            2
# 23  3    3        0         NA            3
# 24  3    4        0         NA            4
# 25  3    5        0         NA            5
# 26  3    6        1          1           NA
# 27  3    7        1          2           NA
# 28  3    8        1          3           NA
# 29  3    9        1          4           NA
# 30  3   10        1          5           NA

答案 1 :(得分:1)

这是dplyr的一个选项:

require(dplyr)
dat %>%
  group_by(id, x = cumsum(c(0,diff(pres.abs)) != 0)) %>%
  mutate(cumul.zeros = ifelse(pres.abs, NA_integer_, row_number()),
         cumul.ones = ifelse(!pres.abs, NA_integer_, row_number())) %>%
  ungroup() %>% select(-x) 

#Source: local data frame [30 x 5]
#
#   id year pres.abs cumul.zeros cumul.ones
#1   1    1        0           1         NA
#2   1    2        0           2         NA
#3   1    3        0           3         NA
#4   1    4        1          NA          1
#5   1    5        1          NA          2
#6   1    6        1          NA          3
#7   1    7        0           1         NA
#8   1    8        0           2         NA
#9   1    9        1          NA          1
#10  1   10        1          NA          2
#11  2    1        1          NA          1
#12  2    2        1          NA          2
#13  2    3        0           1         NA
#14  2    4        1          NA          1
#15  2    5        0           1         NA
#16  2    6        0           2         NA
#17  2    7        1          NA          1
#18  2    8        0           1         NA
#19  2    9        0           2         NA
#20  2   10        0           3         NA
#21  3    1        0           1         NA
#22  3    2        0           2         NA
#23  3    3        0           3         NA
#24  3    4        0           4         NA
#25  3    5        0           5         NA
#26  3    6        1          NA          1
#27  3    7        1          NA          2
#28  3    8        1          NA          3
#29  3    9        1          NA          4
#30  3   10        1          NA          5