在 R 中:如何在两个日期之间按组对变量求和
Posted
技术标签:
【中文标题】在 R 中:如何在两个日期之间按组对变量求和【英文标题】:In R: how to sum a variable by group between two dates 【发布时间】:2017-11-04 20:27:08 【问题描述】:我有两个数据框(DF1 和 DF2):
(1) DF1 包含关于个人级别的信息,即 11 年(2000-2011 年)中嵌套在 30 个单元中的 10.000 个人的信息。它包含四个变量:
-
“individual”(每个人的数字 id;范围为 1-10.000)
“unit”(每个单元的数字 id;范围为 1-30)
"date1"(日期格式的日期,即2000-01-01等;范围从2000-01-01到2010-12-31)
“日期 2”(“日期 1”+ 1 年)
(2) DF2 包含关于unit-level 的信息,即在同一时间段(2000-2011 年)与 DF1 中相同的 30 个单位,并进一步包含一个数字变量(“x” ):
-
“unit”(每个单元的数字 id;范围为 1-30)
“日期”(日期格式的日期,即2000-01-01等;范围从2000-01-01到2011-12-31)
“x”(数值型变量,范围从0到200)
我想创建一个新变量(“newvar”),它为每个“单位”的每个“个人”提供从“date1”(DF1)到“date2”(DF2)的“x”(DF2)总和)。这意味着我想将这个新变量添加到 DF1。
例如,如果 "unit"=1 中的 "individual"=1 有 "date1"=2000-01-01 和 "date2"=2001-01-01,并且在 DF2 中 "unit"=1 有三个观察值在时间段“date1”到“date2”(即2000-01-01到2001-01-01),“x”=1,“x”=2和“x”=3,那么我想添加一个在 "unit"=1 "newvar"=6 中给出 "individual"=1 的新变量。
我假设我需要在 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 年期间的每个单元都有许多观察结果。
【问题讨论】:
请展示一个可重现的小例子和预期的输出 我没有检查代码,但是您收到的错误消息是因为您将向量 (DF2$x
) 视为二维,而它只有一维。您需要删除最后一个括号之前的逗号:,])
谢谢@Bea!删除逗号时错误消息消失,这很好。不幸的是,该代码没有产生正确的总和,即它为 DF1 中“newvar”中的所有观察值提供了值 0。
谢谢你,@akrun!我添加了一个带有预期输出的小例子 - 我希望这就是你的想法?我是新手,所以我尽力提供所需的信息......
【参考方案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
【讨论】:
非常感谢@akrun!第二个选项解决了这个问题! 我意识到代码并没有完全按照我的想法做。对于 DF1 中的每个“个人”,它将 DF2 中的“x”值从“date1”中的第一个日期到个人特定的“date2”(从 2000 年 1 月 1 日到“date2”的累积值)求和,而不是从个人特定的“date1”到个人特定的“date2”。 Exp: 如果一个人有 "date1"=2005-01-01 & "date2"=2006-01-01,输出给出从 "date1"=2000-01-01 到 "date2"= "x" 的总和2006-01-01,而不是正确地在 2005-01-01 开始求和。任何有关如何修改代码的帮助将不胜感激! 是的,我都试过了,不幸的是他们给了我同样的结果...... @Gret-D 我正在使用您的示例。也许你可以提供一个新的例子 tat 给出不同的输出 我发现了错误 - 您的版本和 Bea 的版本(在具有 2 个单位的数据子集上)现在都可以使用!问题是其中一个日期意外地是“mondate”格式。对于给您带来的困惑,我深表歉意,再次感谢您!【参考方案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
和 DF1$date2
。
此外,length(DF1)
会为您提供列数。要获得行数,您可以使用nrow(DF1)
或dim(DF1)[1]
。
【讨论】:
非常感谢您的回答@Bea!不幸的是,for 循环需要很长时间才能运行,而且我没有耐心等待那么久(因为 akrun 的代码有效)。但是仅在没有 for 循环的情况下运行代码就可以正常工作(当然不能正确地对单位求和),所以我认为如果我的数据帧更小,这将是一个很好的解决方案...... 你是对的,for循环可能比data.table花费更长的时间。用 akrun 的代码解决了很好 :)以上是关于在 R 中:如何在两个日期之间按组对变量求和的主要内容,如果未能解决你的问题,请参考以下文章