【问题标题】:Cumulative Sum in R based on Date and other conditions using data.tableR中基于日期和其他条件使用data.table的累积和
【发布时间】:2021-09-26 22:39:34
【问题描述】:

我有一些足球数据(2020/2021 Serie A),我想计算每支球队在过去 n 天内的比赛次数(假设在过去 30 天内进行简化)。因此,条件是团队、比赛日期(严格小于)和同一天 - 30(大于或等于)。

我想知道使用 data.table(单独)的最佳方法是什么,更重要的是,代码背后的逻辑。我会在团队和日期上循环,但我认为这很麻烦,而且我确信有一种方法可以在一行中完成。

下面给出了一个示例,其结果是我所期望的(日期和日期可能会产生误导,因为有些比赛被推迟了,但这并不重要。数据是按日期分类的)。非常感谢。

Code Team Date Day Date - 30d Games played over the last 30 days
TORATA Atalanta 2020-09-26 2 2020-08-27 NA
LAZATA Atalanta 2020-09-30 1 2020-08-31 1
ATACAG Atalanta 2020-10-04 3 2020-09-04 2
NAPATA Atalanta 2020-10-17 4 2020-09-17 3
ATASAM Atalanta 2020-10-24 5 2020-09-24 4
CROATA Atalanta 2020-10-31 6 2020-10-01 3
ATAINT Atalanta 2020-11-08 7 2020-10-09 3

【问题讨论】:

  • 不清楚如何计算最后一列。
  • 这是在 Date-30d 和 Date 之间发生的游戏数的计数器。基本上,它计算行数。

标签: r date data.table conditional-statements cumulative-sum


【解决方案1】:

这是一个实现,只是 data.table 和基础 R:

dat[, z := sapply(Date, function(z) sum(between(z - Date, 0.1, 30)))]
dat
#      Code     Team       Date   Day Date...30d Games.played.over.the.last.30.days     z
#    <char>   <char>     <Date> <int>     <Date>                              <int> <int>
# 1: TORATA Atalanta 2020-09-26     2 2020-08-27                                 NA     0
# 2: LAZATA Atalanta 2020-09-30     1 2020-08-31                                  1     1
# 3: ATACAG Atalanta 2020-10-04     3 2020-09-04                                  2     2
# 4: NAPATA Atalanta 2020-10-17     4 2020-09-17                                  3     3
# 5: ATASAM Atalanta 2020-10-24     5 2020-09-24                                  4     4
# 6: CROATA Atalanta 2020-10-31     6 2020-10-01                                  3     3
# 7: ATAINT Atalanta 2020-11-08     7 2020-10-09                                  3     3

在这种情况下,对于每个 Date 值,我们计算有多少日期在它的 30 天内。

如果您需要 NA 代替 0,则可以添加 dat[z &lt; 1, z := NA] 或类似名称。


数据:

library(data.table)
dat <- structure(list(Code = c("TORATA", "LAZATA", "ATACAG", "NAPATA", "ATASAM", "CROATA", "ATAINT"), Team = c("Atalanta", "Atalanta", "Atalanta", "Atalanta", "Atalanta", "Atalanta", "Atalanta"), Date = structure(c(18531, 18535, 18539, 18552, 18559, 18566, 18574), class = "Date"), Day = c(2L, 1L, 3L, 4L, 5L, 6L, 7L), Date...30d = structure(c(18501, 18505, 18509, 18522, 18529, 18536, 18544), class = "Date"), Games.played.over.the.last.30.days = c(NA, 1L, 2L, 3L, 4L, 3L, 3L)), class = c("data.table", "data.frame"), row.names = c(NA, -7L))
setDT(dat)

【讨论】:

  • 感谢您的回答。使用“runner”库的那个也很好,但你的是干净的data.table和base,我更喜欢。
【解决方案2】:

您可以将runnerdata.table 结合使用来计算正在运行的Date 窗口计数:

library(data.table)
library(runner)

setDT(data)

data[,Date:=as.Date(Date,'%Y-%m-%d')]

data[,N:=runner::runner(
                        x = Date, 
                        k = 30, # 30-days window
                        lag = 1,
                        idx = Date,
                        f = length)
    ,by=Team][]

     Code     Team       Date Day    Date30d Games30days N
1: TORATA Atalanta 2020-09-26   2 2020-08-27          NA 0
2: LAZATA Atalanta 2020-09-30   1 2020-08-31           1 1
3: ATACAG Atalanta 2020-10-04   3 2020-09-04           2 2
4: NAPATA Atalanta 2020-10-17   4 2020-09-17           3 3
5: ATASAM Atalanta 2020-10-24   5 2020-09-24           4 4
6: CROATA Atalanta 2020-10-31   6 2020-10-01           3 3
7: ATAINT Atalanta 2020-11-08   7 2020-10-09           3 3

数据:

data <- read.table(text='
Code    Team    Date    Day     Date30d     Games30days
TORATA  Atalanta    2020-09-26  2   2020-08-27  NA
LAZATA  Atalanta    2020-09-30  1   2020-08-31  1
ATACAG  Atalanta    2020-10-04  3   2020-09-04  2
NAPATA  Atalanta    2020-10-17  4   2020-09-17  3
ATASAM  Atalanta    2020-10-24  5   2020-09-24  4
CROATA  Atalanta    2020-10-31  6   2020-10-01  3
ATAINT  Atalanta    2020-11-08  7   2020-10-09  3',header=T)

【讨论】:

  • 感谢您的回答。我还有几个问题。查看“跑步者”的网页后,我了解到 x 是数据(这里是列向量 data$Date),并且它根据条件显示向量的长度。正确的?现在他们说,可以使用任何功能。假设我会有一个多列(标志)来指示球队是否赢得了比赛(1 == 胜利,0 其他),我知道我可以在该列上使用 cumsum 来计算一段时间内的胜利次数.我仍然缺少一些东西,因为我的测试都是错误的。可以将“x”设置为 2 列吗?
  • 这应该可以工作:data[,wincount:=runner::runner(x = winflag, k = 30, lag = 1, idx = Date, f = sum),by=Team][]
【解决方案3】:

你可以用一行代码得到这个,使用表的非等连接。

假设fb 是您的输入数据(没有Games30days 列)。像这样:

     Code     Team       Date Day Date - 30d
1: TORATA Atalanta 2020-09-26   2 2020-08-27
2: LAZATA Atalanta 2020-09-30   1 2020-08-31
3: ATACAG Atalanta 2020-10-04   3 2020-09-04
4: NAPATA Atalanta 2020-10-17   4 2020-09-17
5: ATASAM Atalanta 2020-10-24   5 2020-09-24
6: CROATA Atalanta 2020-10-31   6 2020-10-01
7: ATAINT Atalanta 2020-11-08   7 2020-10-09

然后,只需对Team=TeamDate&lt;DateDate&gt;Date - 30d 进行连接,如下所示:

games_played = fb[fb,on=.(Team = Team, Date<Date, Date>`Date - 30d`), nomatch=0][,.("Games30" =  .N), .(Date,Team)]

返回

         Date     Team Games30
1: 2020-09-30 Atalanta       1
2: 2020-10-04 Atalanta       2
3: 2020-10-17 Atalanta       3
4: 2020-10-24 Atalanta       4
5: 2020-10-31 Atalanta       3
6: 2020-11-08 Atalanta       3

该结果可以很容易地与原始结果连接,以获取所有列,如下所示:

games_played[fb, on=.(Team, Date)]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-17
    • 2016-02-19
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    相关资源
    最近更新 更多