R 中基于日期和其他条件的累计和使用 data.table
Cumulative Sum in R based on Date and other conditions using data.table
我有一些足球数据(2020/2021 意甲联赛),我想计算每支球队在过去 n 天的比赛次数(可以说是过去 30 天的简化)。因此,条件是球队、比赛当天(严格小于)和同一天 - 30(大于或等于)。
我想知道使用 data.table(单独)的最佳方法是什么,更重要的是,代码背后的逻辑。我会在团队和日期上循环,但我认为这很麻烦,我相信有一种方法可以在一行中完成它。
下面给出了一个示例,结果是我所期望的(日期和日期可能看起来具有误导性,因为有些比赛被推迟了,但这并不重要。数据按日期分类)。非常感谢。
代码
团队
日期
天
日期 - 30 天
过去 30 天玩过的游戏
虎田
亚特兰大
2020-09-26
2
2020-08-27
不适用
拉扎塔
亚特兰大
2020-09-30
1
2020-08-31
1
ATACAG
亚特兰大
2020-10-04
3
2020-09-04
2
纳帕塔
亚特兰大
2020-10-17
4
2020-09-17
3
阿塔萨姆
亚特兰大
2020-10-24
5
2020-09-24
4
克罗地亚
亚特兰大
2020-10-31
6
2020-10-01
3
ATAINT
亚特兰大
2020-11-08
7
2020-10-09
3
您可以将 runner
与 data.table
结合使用来计算 运行 Date
window 计数:
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)
你可以用一行代码得到这个,使用 table 自身的非相等连接。
假设 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=Team
、Date<Date
和 Date>Date - 30d
上进行连接,如下所示:
games_played = fb[fb,on=.(Team = Team, Date<Date, Date>`Date - 30d`), nomatch=0][,.("Games30" = .N), .(Date,Team)]
哪个returns
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)]
这是一种实现方式,只有 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 < 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)
我有一些足球数据(2020/2021 意甲联赛),我想计算每支球队在过去 n 天的比赛次数(可以说是过去 30 天的简化)。因此,条件是球队、比赛当天(严格小于)和同一天 - 30(大于或等于)。
我想知道使用 data.table(单独)的最佳方法是什么,更重要的是,代码背后的逻辑。我会在团队和日期上循环,但我认为这很麻烦,我相信有一种方法可以在一行中完成它。
下面给出了一个示例,结果是我所期望的(日期和日期可能看起来具有误导性,因为有些比赛被推迟了,但这并不重要。数据按日期分类)。非常感谢。
代码 | 团队 | 日期 | 天 | 日期 - 30 天 | 过去 30 天玩过的游戏 |
---|---|---|---|---|---|
虎田 | 亚特兰大 | 2020-09-26 | 2 | 2020-08-27 | 不适用 |
拉扎塔 | 亚特兰大 | 2020-09-30 | 1 | 2020-08-31 | 1 |
ATACAG | 亚特兰大 | 2020-10-04 | 3 | 2020-09-04 | 2 |
纳帕塔 | 亚特兰大 | 2020-10-17 | 4 | 2020-09-17 | 3 |
阿塔萨姆 | 亚特兰大 | 2020-10-24 | 5 | 2020-09-24 | 4 |
克罗地亚 | 亚特兰大 | 2020-10-31 | 6 | 2020-10-01 | 3 |
ATAINT | 亚特兰大 | 2020-11-08 | 7 | 2020-10-09 | 3 |
您可以将 runner
与 data.table
结合使用来计算 运行 Date
window 计数:
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)
你可以用一行代码得到这个,使用 table 自身的非相等连接。
假设 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=Team
、Date<Date
和 Date>Date - 30d
上进行连接,如下所示:
games_played = fb[fb,on=.(Team = Team, Date<Date, Date>`Date - 30d`), nomatch=0][,.("Games30" = .N), .(Date,Team)]
哪个returns
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)]
这是一种实现方式,只有 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 < 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)