在R中:如何在两个日期之间按组对变量求和

时间:2017-06-03 15:36:42

标签: r date for-loop sum

我有两个数据帧(DF1和DF2):

(1)DF1包含个人级别的信息,即在11年(2000-2011)内以30个单位嵌套的10.000个人。它包含四个变量:

  1. “个人”(每个人的数字ID;范围从1-10.000)
  2. “unit”(每个单位的数字ID;范围从1-30)
  3. “date1”(日期格式的日期,即2000-01-01等;范围从2000-01-01至2010-12-31)
  4. “date2”(“Date1”+ 1年)
  5. (2)DF2包含单位级别的信息,即在同一时间段(2000-2011)与DF1相同的30个单位,并且还包含一个数字变量(“x”) ):

    1. “unit”(每个单位的数字ID;范围从1-30)
    2. “date”(日期格式的日期,即2000-01-01等;范围从2000-01-01至2011-12-31)
    3. “x”(数字变量,范围从0到200)
    4. 我想创建一个新变量(“newvar”),它为每个“单位”给出每个“个体”,“x”(DF2)从“date1”(DF1)到“date2”(DF2)的总和)。这意味着我想将这个新变量添加到DF1。

      例如,如果“unit”中的“individual”= 1 = 1,则“date1”= 2000-01-01,“date2”= 2001-01-01,而DF2中“unit”= 1则有3个观察值在时间段“date1”到“date2”(即2000-01-01至2001-01-01)中,“x”= 1,“x”= 2且“x”= 3,那么我想添加一个在“单位”中给出“个人”= 1的新变量= 1“newvar”= 6。

      我假设我需要在R中使用for循环并使用以下代码:

      for(i in length(DF1)){
      
      DF1$newvar[i] <-sum(DF2$x[which(DF1$date == DF1$date1[i] &
                           DF1$date == DF1P$date1[i] &
                           DF2$unit == DF1P$unit[i]),])
      

      }

      但收到错误消息:

      Error in DF2$x[which(DF2$date ==  : incorrect number of dimensions 
      

      如何创建此变量的任何想法都将非常受欢迎!

      这是一个小例子以及预期输出,为简单起见使用一个单位:

      假设DF1如下所示:

      individual  unit  date1        date2   
      1           1     2000-01-01   2001-01-01
      2           1     2000-02-02   2001-02-02
      3           1     2000-03-03   2000-03-03
      4           1     2000-04-04   2000-04-04
      5           1     2000-12-31   2001-12-31 
      (...)
      996         1     2010-01-01   2011-01-01
      997         1     2010-02-15   2011-02-15
      998         1     2010-03-05   2011-03-05
      999         1     2010-04-10   2011-04-10
      1000        1     2010-12-27  2011-12-27
      1001        2     2000-01-01   2001-01-01
      1002        2     2000-02-02   2001-02-02
      1003        2     2000-03-03   2000-03-03
      1004        2     2000-04-04   2000-04-04
      1005        2     2000-12-31   2001-12-31 
      (...)
      1996        2     2010-01-01   2011-01-01
      1997        2     2010-02-15   2011-02-15
      1998        2     2010-03-05   2011-03-05
      1999        2     2010-04-10   2011-04-10
      2000        2     2010-12-027  2011-12-27
      (...)
      3000        34    2000-02-02   2002-02-02
      3001        34    2000-05-05   2001-05-05
      3002        34    2000-06-06   2001-06-06
      3003        34    2000-07-07   2001-07-07
      3004        34    2000-11-11   2001-11-11
      (...)
      9996        34    2010-02-06   2011-02-06
      9997        34    2010-05-05   2011-05-05
      9998        34    2010-09-09   2011-09-09 
      9999        34    2010-09-25   2011-09-25
      10000       34    2010-10-15   2011-10-15
      

      假设DF2如下所示:

      unit      date         x
      1         2000-01-01   1
      1         2000-05-01   2
      1         2000-12-01   3
      1         2001-01-02   10
      1         2001-07-05   20
      1         2001-12-31   30
      (...) 
      2         2010-05-05   1 
      2         2010-07-01   1
      2         2010-08-09   1
      3         (...)
      

      这是我希望DF1在运行代码后的样子:

      individual  unit      date1        date2        newvar  
          1           1     2000-01-01   2001-01-01   6
          2           1     2000-02-02   2001-02-02   16
          3           1     2000-03-03   2001-03-03   15
          4           1     2000-04-04   2001-04-04   15
          5           1     2000-12-31   2001-12-31   60
          (...)
          996         1     2010-01-01   2011-01-01    3
          997         1     2010-02-15   2011-02-15    2
          998         1     2010-03-05   2011-03-05    2
          999         1     2010-04-10   2011-04-10    2
          1000        1     2010-12-27  2011-12-27     0
          (...)
      

      然而,我不能简单地汇总:想象一下,在DF1中,每个“单位”在2000年到2011年之间每年有数百个人。而DF2在2000 - 2011年期间对每个单位都有很多观察。

2 个答案:

答案 0 :(得分:2)

你几乎就在那里,我只是稍微修改了你的for循环,并确保日期变量被认为是这样的:

DF1$date1 = as.Date(DF1$date1,"%Y-%m-%d")
DF1$date2 = as.Date(DF1$date2,"%Y-%m-%d")
DF2$date = as.Date(DF2$date,"%Y-%m-%d")

for(i in 1:nrow(DF1)){
  DF1$newvar[i] <-sum(DF2$x[which(DF2$unit == DF1$unit[i] & 
                                  DF2$date>= DF1$date1[i] &
                                  DF2$date<= DF1$date2[i])]) 
}

问题是,您要求DF2$date同时== DF1$date1&amp; DF1$date2。 而且,length(DF1)为您提供了列数。要获得行数,您可以使用nrow(DF1)dim(DF1)[1]

答案 1 :(得分:1)

我们可以使用data.table

library(data.table)
setDT(DF1)
setDT(DF2)
DF1[DF2[, .(newvar = sum(x)), .(unit, individual = cumsum(date %in% DF1$date1))],
             newvar := newvar, on = .(individual, unit)]
DF1
#    individual unit      date1      date2 newvar
#1:          1    1 2000-01-01 2001-01-01      6
#2:          2    1 2001-01-02 2002-01-02     60

或者我们可以使用非等连接

DF1[DF2[DF1, sum(x), on = .(unit, date >= date1, date <= date2),
        by = .EACHI], newvar := V1, on = .(unit, date1=date)]

DF1
#   individual unit      date1      date2 newvar
#1:          1    1 2000-01-01 2001-01-01      6
#2:          2    1 2001-01-02 2002-01-02     60