【问题标题】:R sum by group if date within date range如果日期在日期范围内,则按组求和
【发布时间】:2018-04-05 00:08:08
【问题描述】:

假设我有两个数据框。

第一个包括“名称”为“ID”发出“Rec”的“Date”和“Rec”失效的“Stop.Date”。

df(仅一部分)

structure(list(Date = structure(c(13236, 13363, 14074, 13199, 
14554), class = "Date"), ID = c("AU0000XINAA9", "AU0000XINAA9", 
"AU0000XINAC5", "AU0000XINAI2", "AU0000XINAJ0"), Name = c("N+1 BREWIN", 
"N+1 BREWIN", "ARBUTHNOT SECURITIES LTD.", "INVESTEC BANK (UK) PLC", 
"AWRAQ INVESTMENTS"), Rec = c(1, 2, 2, 2, 1), Stop.Date = structure(c(13363, 
13509, 14937, 13230, 16702), class = "Date")), .Names = c("Date", 
"ID", "Name", "Rec", "Stop.Date"), class = c("data.table", "data.frame"
), row.names = c(NA, -5L))

第二个数据帧只包含一个时间序列:假设在这种情况下从 2006 年 3 月 29 日到 2006 年底。

df2

      Date1
  1: 2006-02-20
  2: 2006-02-21
  3: 2006-02-22
  4: 2006-02-23
  5: 2006-02-24
 ---           
311: 2006-12-27
312: 2006-12-28
313: 2006-12-29
314: 2006-12-30
315: 2006-12-31

现在,如果 df2 中的“Date1”变量在时间范围内(直到 Stop.Date 的日期),我希望我的代码将所有按 ID 和名称组合的“Rec”相加

我发现这篇文章R - If date falls within range, then sum 似乎非常接近我的问题,但解决方案不考虑任何组。

我想提出一个 data.frame,其中显示 df2 中每个日期的每个“ID”的“REC”总和。

预期输出,例如

        Date1         ID          SumRec 

    1 2006-02-20 AU0000XINAI2        2
    2 2006-02-21 AU0000XINAI2        2
...
    4 2006-03-29 AU0000XINAA9        1
    5 2006-03-30 AU0000XINAA9        1
    6 2006-08-03 AU0000XINAA9        2  # since Date1 2006-08-03 is at the end 
                                          of range in df (row#1)-> it falls 
                                          within range in df (row#2) 
...

请记住,这只是数据的一小部分。通常,来自不同“名称”的每个“ID”存在更多的 Recs。 (那么 sum 函数就有意义了)

非常感谢您提前提供的帮助。

更新版本

新数据框:

df

structure(list(Date = structure(c(9905, 10381, 10381, 10954, 
10584, 10632, 10778, 10520, 10631, 10905), class = "Date"), ID = c("BMG4593F1389", 
"BMG4593F1389", "BMG4593F1389", "BMG4593F1389", "BMG4593F1389", 
"BMG4593F1389", "BMG4593F1389", "BMG526551004", "BMG526551004", 
"BMG526551004"), Name = c("ING FM", "Permission Denied 128064", 
"Permission Denied 2880", "Permission Denied 2880", "Permission Denied 32", 
"Permission Denied 888", "Permission Denied 888", "Permission Denied 2880", 
"Permission Denied 2880", "Permission Denied 2880"), Rec = c(2, 
3, 2, 2, 3, 3, 3, 1, 3, 3), Stop.Date = structure(c(12095, 11232, 
10954, 11180, 11345, 10764, 11667, 10631, 10905, 11087), class = "Date")), .Names = c("Date", 
"ID", "Name", "Rec", "Stop.Date"), class = c("data.table", "data.frame"
), row.names = c(NA, -10L))

df2

structure(list(Date1 = structure(c(10954, 10955, 10956, 10957, 
10958, 10959), class = "Date")), .Names = "Date1", row.names = c(NA, 
-6L), class = c("data.table", "data.frame"))

如果我现在执行以下代码:

> df=df[,interval := interval(df$Date, df$Stop.Date)]
> 
> df1 <- do.call(rbind, lapply(df2$Date1, function(x){   index <- x
> %within% df$interval;   list(ID = ifelse(any(index), df$ID[index],
> NA), Rec = ifelse(any(index), df$Rec[index], NA), 
>        Name = ifelse(any(index), df$Name[index], NA),interval = ifelse(any(index),df$interval[index],NA))})) 
> 
> df3 <- cbind(df2, df1)

我得出以下结果:

     Date1        ID        Rec  Name interval
1: 1999-12-29 BMG4593F1389   2 ING FM 189216000
2: 1999-12-30 BMG4593F1389   2 ING FM 189216000
3: 1999-12-31 BMG4593F1389   2 ING FM 189216000
4: 2000-01-01 BMG4593F1389   2 ING FM 189216000
5: 2000-01-02 BMG4593F1389   2 ING FM 189216000
6: 2000-01-03 BMG4593F1389   2 ING FM 189216000

但是因为例如 df$ID "BMG4593F1389" 的 df2$Date1 ("1999-12-29") 属于 df 中另外 6 个条目的日期范围(对于不同的 df$Names)对于这个特定的 df$ date1 应该是:

日期 1999-12-29 的预期结果(为简单起见,此处忽略 df3$interval 变量)

         Date1        ID        Rec         Name 
    1: 1999-12-29 BMG4593F1389   2   ING FM 
    2: 1999-12-29 BMG4593F1389   3   Permission Denied 128064 
    3: 1999-12-29 BMG4593F1389   2   Permission Denied 2880
    4: 1999-12-29 BMG4593F1389   3   Permission Denied 32
    5: 1999-12-29 BMG4593F1389   3   Permission Denied 888

    6: 1999-12-29 BMG5265510042  3   Permission Denied 2880

    7: 1999-12-30 BMG4593F1389   2   ING FM
... etc

所以最后我需要复制 df$Date1 中的日期,如果多个名称为特定 df$ID 发出 Rec,该特定 df$ID 落在相应的日期范围内。

有人可以帮我吗?

【问题讨论】:

  • 您的预期输出是什么?请至少显示几行,最好附上解释
  • 您想获得Rec 的总和还是简单地获得df2$Date1 中每个日期的Rec
  • 您的输出没有意义。您的示例数据开始于2006-03-29
  • 是的,这是真的。很抱歉造成混淆,请假设样本数据 df2 开始于 df 的最早日期(2006-02-20)
  • 我有一个后续问题,因此更新了我上面的问题。要是能看看就好了

标签: r dplyr data.table sumifs non-equi-join


【解决方案1】:

如果我正确理解问题的更新版本,则可以使用非等连接和后续聚合来解决:

library(data.table)
# non-equi join
df[df2, on = .(Date <= Date1, Stop.Date > Date1), allow = TRUE][
  # aggregation
  , .(sumRec = sum(Rec)), by = .(Date, ID, Name)]
          Date           ID                     Name sumRec
 1: 1999-12-29 BMG4593F1389                   ING FM      2
 2: 1999-12-29 BMG4593F1389 Permission Denied 128064      3
 3: 1999-12-29 BMG4593F1389   Permission Denied 2880      2
 4: 1999-12-29 BMG4593F1389     Permission Denied 32      3
 5: 1999-12-29 BMG4593F1389    Permission Denied 888      3
 6: 1999-12-29 BMG526551004   Permission Denied 2880      3
 7: 1999-12-30 BMG4593F1389                   ING FM      2
 8: 1999-12-30 BMG4593F1389 Permission Denied 128064      3
 9: 1999-12-30 BMG4593F1389   Permission Denied 2880      2
10: 1999-12-30 BMG4593F1389     Permission Denied 32      3
11: 1999-12-30 BMG4593F1389    Permission Denied 888      3
12: 1999-12-30 BMG526551004   Permission Denied 2880      3
13: 1999-12-31 BMG4593F1389                   ING FM      2
14: 1999-12-31 BMG4593F1389 Permission Denied 128064      3
15: 1999-12-31 BMG4593F1389   Permission Denied 2880      2
16: 1999-12-31 BMG4593F1389     Permission Denied 32      3
17: 1999-12-31 BMG4593F1389    Permission Denied 888      3
18: 1999-12-31 BMG526551004   Permission Denied 2880      3
19: 2000-01-01 BMG4593F1389                   ING FM      2
20: 2000-01-01 BMG4593F1389 Permission Denied 128064      3
21: 2000-01-01 BMG4593F1389   Permission Denied 2880      2
22: 2000-01-01 BMG4593F1389     Permission Denied 32      3
23: 2000-01-01 BMG4593F1389    Permission Denied 888      3
24: 2000-01-01 BMG526551004   Permission Denied 2880      3
25: 2000-01-02 BMG4593F1389                   ING FM      2
26: 2000-01-02 BMG4593F1389 Permission Denied 128064      3
27: 2000-01-02 BMG4593F1389   Permission Denied 2880      2
28: 2000-01-02 BMG4593F1389     Permission Denied 32      3
29: 2000-01-02 BMG4593F1389    Permission Denied 888      3
30: 2000-01-02 BMG526551004   Permission Denied 2880      3
31: 2000-01-03 BMG4593F1389                   ING FM      2
32: 2000-01-03 BMG4593F1389 Permission Denied 128064      3
33: 2000-01-03 BMG4593F1389   Permission Denied 2880      2
34: 2000-01-03 BMG4593F1389     Permission Denied 32      3
35: 2000-01-03 BMG4593F1389    Permission Denied 888      3
36: 2000-01-03 BMG526551004   Permission Denied 2880      3
          Date           ID                     Name sumRec

请注意,当直接使用structure(...) 中提供的df 时,我遇到了一条奇怪的错误消息。调用后错误信息消失了

df <- as.data.table(df)

说明

我是 asked 来解释 non-equi join 的工作原理。 非 equi 连接data.table 连接的扩展。 data.table 是一个增强基础 R 的 data.frame 的包。

在这里,我们将df2df 右连接,即,我们希望在结果中看到df2df 匹配的所有行,但只有Date1 匹配的行(来自df2)准确地说,位于DateStop.Date(来自df)、Date &lt;= Date1 &lt; Stop.Date 之间。由于有很多可能的匹配项,我们需要使用allow.cartesian = TRUE

用户有video of Arun's talk! 2016 年国际 R 用户大会介绍使用 data.table 实现高效内存非等连接

【讨论】:

  • 请问allow = TRUE 是做什么的?这是我第一次看到我认为的那个选项。谢谢!
  • 似乎完美运行!我只是将 sum 函数编辑为简单的“rec”,因为我只想要这个数据框中的 Rec 值。非常感谢您提供的简单解决方案。由于我对 R 很陌生,您介意解释一下在这种情况下非 equi 连接是如何工作的吗?
  • @Tung 默认情况下,allow.cartesianFALSE,以防止由于i 的连接列中的重复值导致的连接数超过nrow(x) + nrow(i) 行。在这里,我们需要所有可能的组合,它们将在第二步中聚合。
  • @JB_G 我已经添加了关于non-equi joins的附加说明。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-07
  • 2022-11-17
  • 2018-04-13
相关资源
最近更新 更多