具有自定义时间片的时间序列数据的平均值 window
Average over time series data with custom time slice window
我正在使用 R 中的一些网球排名数据,它给出了 ATP 巡回赛中所有球员的网球排名随时间的演变。
可以在此处找到我使用的数据示例,给出了 2000 年的排名数据:https://github.com/JeffSackmann/tennis_atp/blob/master/atp_rankings_00s.csv
清理数据:
rankings <- read_csv("data/atp/atp_rankings_00s.csv")
rankings = rankings %>%
mutate(rankingDate = lubridate::ymd(ranking_date) ) %>%
select(-ranking_date)
现在,假设我想追踪每个玩家在整个十年中的时间演变,并计算他们在此期间的平均排名。然后我可以写:
rankings %>%
group_by(player) %>%
summarise(
meanRanking = mean(rank, na.rm = TRUE),
)
但是,假设我想要更多东西。我想沿时间轴切分这些数据,并计算这些切分的平均排名。因此,对于 start=01-01-2000, end=01-01-2008, skip=2 years
之类的东西,我可以表示从 2000 年 1 月 1 日到 2008 年 1 月 1 日期间超过 2 年时间 windows 的排名。如何在 R 中编写这样的“时间切片”代码?
试用 zoo
包中的滚动功能
library(zoo)
set.seed(2137)
my_data <- rnorm(100)
zoo::rollmean(my_data, 10)
根据数据类型和数据的时间频率,它可能看起来像这样
rankings %>%
group_by(player) %>%
summarise(
meanRanking = zoo::rollmean(rank, k = 2, na.rm = TRUE),
)
以下是我如何获取 two-year 数据切片:
rankings %>%
mutate(floor = 2 * floor(lubridate::year(rankingDate) / 2),
slice = paste(floor, floor + 1, sep = '-')) %>%
select(-floor) %>%
group_by(player, slice) %>%
summarize(average_ranking = mean(rank))
#> # A tibble: 13,537 x 3
#> # Groups: player [5,711]
#> player slice average_ranking
#> <int> <chr> <dbl>
#> 1 100149 2000-2001 1332
#> 2 100149 2004-2005 1052
#> 3 100183 2004-2005 1477
#> 4 100236 2000-2001 1106.
#> 5 100236 2002-2003 780
#> 6 100236 2004-2005 779.
#> 7 100428 2000-2001 939.
#> 8 100428 2002-2003 976
#> 9 100474 2000-2001 1298.
#> 10 100474 2002-2003 981
我们可以用它来查看在任何 two-year 时期平均排名前 5 的球员的轨迹,观察明星们进入和退出竞争。
rankings %>%
mutate(floor = 2 * round(lubridate::year(rankingDate) / 2),
slice = paste(floor, floor + 1, sep = '-')) %>%
select(-floor) %>%
group_by(player, slice) %>%
summarize(average_ranking = mean(rank)) %>%
filter(any(average_ranking < 5)) %>%
ggplot(aes(slice, average_ranking, group = player, color = factor(player))) +
geom_line(size = 1) +
coord_cartesian(ylim = c(0, 100)) +
theme_light(base_size = 16) +
theme(legend.position = 'none')
您的数据相当大,data.table 可以大大提高速度。这是一个非常快速的方法,它使用了一个灵活的函数f(s,e,p,u)
,它允许你传入任何开始(s
)或结束(e
)日期,一个整数周期(例如 2 表示 2 年),以及时间单位 (u
),其取值 "y"
、"m"
或 "d"
,分别代表年、月、日
f <- function(s,e,p, u=c("y","m","d")) {
u=match.arg(u)
uf = list("y"=years,"m"=months,"d"=days)
data.table(s = seq(as.Date(s), as.Date(e),by=paste(p,u)))[,`:=`(e=s %m+% uf[[u]](p), period=1:.N)]
}
然后您只需将该函数应用于non-equi join
中的排名
setDT(rankings)
rankings[f("2000-01-01", "2008-01-01",2), on=.(ranking_date>=s, ranking_date<=e)] %>%
.[,.(ranking=mean(rank,na.rm=T)), by=.(player,period )]
输出:
player period ranking
1: 101736 1 2.769231
2: 102338 1 5.211538
3: 101948 1 4.730769
4: 103017 1 23.259615
5: 102856 1 2.538462
---
13543: 105996 5 1780.500000
13544: 105050 5 1665.333333
13545: 105757 5 1781.000000
13546: 121555 5 1328.500000
13547: 106018 5 1508.000000
3 个月 windows,只需使用 p
=3 和 u
="m"
调用 f
rankings[f("2000-01-01", "2008-01-01",3, "m"), on=.(ranking_date>=s, ranking_date<=e)] %>%
.[,.(ranking=mean(rank,na.rm=T)), by=.(player,period )]
产出(3个月windows)
player period ranking
1: 101736 1 1.000000
2: 102338 1 2.666667
3: 101948 1 2.333333
4: 103017 1 4.000000
5: 102856 1 5.500000
---
62491: 105517 33 1502.000000
62492: 104405 33 1588.000000
62493: 104576 33 1588.000000
62494: 105500 33 1679.000000
62495: 108698 33 1844.000000
我正在使用 R 中的一些网球排名数据,它给出了 ATP 巡回赛中所有球员的网球排名随时间的演变。
可以在此处找到我使用的数据示例,给出了 2000 年的排名数据:https://github.com/JeffSackmann/tennis_atp/blob/master/atp_rankings_00s.csv
清理数据:
rankings <- read_csv("data/atp/atp_rankings_00s.csv")
rankings = rankings %>%
mutate(rankingDate = lubridate::ymd(ranking_date) ) %>%
select(-ranking_date)
现在,假设我想追踪每个玩家在整个十年中的时间演变,并计算他们在此期间的平均排名。然后我可以写:
rankings %>%
group_by(player) %>%
summarise(
meanRanking = mean(rank, na.rm = TRUE),
)
但是,假设我想要更多东西。我想沿时间轴切分这些数据,并计算这些切分的平均排名。因此,对于 start=01-01-2000, end=01-01-2008, skip=2 years
之类的东西,我可以表示从 2000 年 1 月 1 日到 2008 年 1 月 1 日期间超过 2 年时间 windows 的排名。如何在 R 中编写这样的“时间切片”代码?
试用 zoo
包中的滚动功能
library(zoo)
set.seed(2137)
my_data <- rnorm(100)
zoo::rollmean(my_data, 10)
根据数据类型和数据的时间频率,它可能看起来像这样
rankings %>%
group_by(player) %>%
summarise(
meanRanking = zoo::rollmean(rank, k = 2, na.rm = TRUE),
)
以下是我如何获取 two-year 数据切片:
rankings %>%
mutate(floor = 2 * floor(lubridate::year(rankingDate) / 2),
slice = paste(floor, floor + 1, sep = '-')) %>%
select(-floor) %>%
group_by(player, slice) %>%
summarize(average_ranking = mean(rank))
#> # A tibble: 13,537 x 3
#> # Groups: player [5,711]
#> player slice average_ranking
#> <int> <chr> <dbl>
#> 1 100149 2000-2001 1332
#> 2 100149 2004-2005 1052
#> 3 100183 2004-2005 1477
#> 4 100236 2000-2001 1106.
#> 5 100236 2002-2003 780
#> 6 100236 2004-2005 779.
#> 7 100428 2000-2001 939.
#> 8 100428 2002-2003 976
#> 9 100474 2000-2001 1298.
#> 10 100474 2002-2003 981
我们可以用它来查看在任何 two-year 时期平均排名前 5 的球员的轨迹,观察明星们进入和退出竞争。
rankings %>%
mutate(floor = 2 * round(lubridate::year(rankingDate) / 2),
slice = paste(floor, floor + 1, sep = '-')) %>%
select(-floor) %>%
group_by(player, slice) %>%
summarize(average_ranking = mean(rank)) %>%
filter(any(average_ranking < 5)) %>%
ggplot(aes(slice, average_ranking, group = player, color = factor(player))) +
geom_line(size = 1) +
coord_cartesian(ylim = c(0, 100)) +
theme_light(base_size = 16) +
theme(legend.position = 'none')
您的数据相当大,data.table 可以大大提高速度。这是一个非常快速的方法,它使用了一个灵活的函数f(s,e,p,u)
,它允许你传入任何开始(s
)或结束(e
)日期,一个整数周期(例如 2 表示 2 年),以及时间单位 (u
),其取值 "y"
、"m"
或 "d"
,分别代表年、月、日
f <- function(s,e,p, u=c("y","m","d")) {
u=match.arg(u)
uf = list("y"=years,"m"=months,"d"=days)
data.table(s = seq(as.Date(s), as.Date(e),by=paste(p,u)))[,`:=`(e=s %m+% uf[[u]](p), period=1:.N)]
}
然后您只需将该函数应用于non-equi join
中的排名setDT(rankings)
rankings[f("2000-01-01", "2008-01-01",2), on=.(ranking_date>=s, ranking_date<=e)] %>%
.[,.(ranking=mean(rank,na.rm=T)), by=.(player,period )]
输出:
player period ranking
1: 101736 1 2.769231
2: 102338 1 5.211538
3: 101948 1 4.730769
4: 103017 1 23.259615
5: 102856 1 2.538462
---
13543: 105996 5 1780.500000
13544: 105050 5 1665.333333
13545: 105757 5 1781.000000
13546: 121555 5 1328.500000
13547: 106018 5 1508.000000
3 个月 windows,只需使用 p
=3 和 u
="m"
f
rankings[f("2000-01-01", "2008-01-01",3, "m"), on=.(ranking_date>=s, ranking_date<=e)] %>%
.[,.(ranking=mean(rank,na.rm=T)), by=.(player,period )]
产出(3个月windows)
player period ranking
1: 101736 1 1.000000
2: 102338 1 2.666667
3: 101948 1 2.333333
4: 103017 1 4.000000
5: 102856 1 5.500000
---
62491: 105517 33 1502.000000
62492: 104405 33 1588.000000
62493: 104576 33 1588.000000
62494: 105500 33 1679.000000
62495: 108698 33 1844.000000