对每组满足不同条件的每组观察进行计数

时间:2020-01-07 16:52:55

标签: r

我有一个看起来像这样的数据框

state start end  date treat
1     1999  2000 2001 1
1     1998  2000 2001 1
1     2000  2003 NA   0
2     2001  2002 NA   0
2     2002  2004 2003 1
2     2003  2004 2005 1
3     2002  2004 2006 1
3     2003  2004 NA   0
3     2005  2007 NA   0

我想按状态标识符对它进行分组,并且对于每个状态,我想计算日期在开始和结束之间的已处理观察(处理)数。

换句话说,我想获得以下内容

state start end  date treat result
1     1999  2000 2001 1     0
1     1998  2000 2001 1     0
1     2000  2003 NA   0     2
2     2001  2002 NA   0     0
2     2002  2004 2003 1     1
2     2003  2004 2005 1     0
3     2002  2004 2006 1     0
3     2003  2004 NA   0     0
3     2005  2008 NA   0     1

例如,第一行的结果等于0,因为在状态= 1中,没有1999和2000之间的日期。另一方面,最后一行的结果等于1,因为在状态3中,我有一个日期在2005年至2008年之间的经过处理的单位(特别是日期=第7行中的2006年)。

非常感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

您可以通过 state split并将两个outer&结合起来测试 date 是否在 start < / em>和 end ,然后sum 治疗匹配日期。

x$result  <- unlist(lapply(split(x, x$state), function(y) {
  tt  <- outer(y$start, y$date, "<") & outer(y$end, y$date, ">")
  tt[is.na(tt)]  <- TRUE
  apply(tt, 1, function(z) sum(y$treat[z]))
}))
x
#  state start  end date treat result
#1     1  1999 2000 2001     1      0
#2     1  1998 2000 2001     1      0
#3     1  2000 2003   NA     0      2
#4     2  2001 2002   NA     0      0
#5     2  2002 2004 2003     1      1
#6     2  2003 2004 2005     1      0
#7     3  2002 2004 2006     1      0
#8     3  2003 2004   NA     0      0
#9     3  2005 2007   NA     0      1

或者您可以根据每个国家/地区和国家/地区的描述来描述治疗 date ,并merge来描述状态开始结束,然后将匹配的处理相加。

tt <- aggregate(treat ~ state + date, x[,c("state", "date", "treat")], sum)
tt <- merge(x[,c("state", "start", "end")], tt)
tt$treat[tt$start >= tt$date | tt$end <= tt$date]  <- 0
aggregate(treat ~ start + end + state, tt, sum)
#  start  end state treat
#1  1998 2000     1     0
#2  1999 2000     1     0
#3  2000 2003     1     2
#4  2001 2002     2     0
#5  2002 2004     2     1
#6  2003 2004     2     0
#7  2002 2004     3     0
#8  2003 2004     3     0
#9  2005 2007     3     1

答案 1 :(得分:0)

尽管在每一行上都会重复它们,但这会给出您的数字:

library(tidyverse)

df %>% group_by(state) %>% 
  mutate(result=sum(treat==1 & date>=min(start, na.rm=TRUE) & date<=max(end, na.rm=TRUE), na.rm=TRUE))
#> # A tibble: 9 x 6
#> # Groups:   state [3]
#>   state start   end  date treat result
#>   <dbl> <dbl> <dbl> <dbl> <dbl>  <int>
#> 1     1  1999  2000  2001     1      2
#> 2     1  1998  2000  2001     1      2
#> 3     1  2000  2003    NA     0      2
#> 4     2  2001  2002    NA     0      1
#> 5     2  2002  2004  2003     1      1
#> 6     2  2003  2004  2005     1      1
#> 7     3  2002  2004  2006     1      1
#> 8     3  2003  2004    NA     0      1
#> 9     3  2005  2007    NA     0      1

如果每个组只需要一个号码,那么summarize可能是一个更好的选择:

df %>% group_by(state) %>% 
  summarize(result=sum(treat==1 & date>=min(start, na.rm=TRUE) & date<=max(end, na.rm=TRUE), na.rm=TRUE))
#> # A tibble: 3 x 2
#>   state result
#>   <dbl>  <int>
#> 1     1      2
#> 2     2      1
#> 3     3      1