如何使用 dplyr 创建条件且高效的滚动平均值

问题描述 投票:0回答:1

我正在处理逐个棒球数据,并希望创建许多滚动平均值,其中一些是基于另一列的条件。数据有 600 万行,因此理想情况下该方法效率不会太低。我知道 dplyr 可能不是提高效率的最佳选择 - 但如果可能的话希望利用它。使用 32 GB 内存,所以我确实有一点回旋余地

这是数据示例:

mydata <- data.frame(pitch_type = c("FB", "SI", "CU", "FB", "CH", "FB", "FS", "SL", "FB", "CH"), 
                      velocity = c(99, 97, 83, 97, 85, 101, 82, 84, 100, 83))
mydata
   pitch_type velocity
1          FB       99
2          SI       97
3          CU       83
4          FB       97
5          CH       85
6          FB       101
7          FS       82
8          SL       84
9          FB      100
10         CH       83

在我的实际代码中,我有按投手分组、按时间顺序排序等的数据,但基本上我只想能够计算某些投球类型的滚动平均值。当音高类型不等于我想要计算的值时,我也无法获得 NA 值,我希望它恢复到之前的计算。

这是我正在寻找的示例。在这里,我想计算最后两次观察的平均速度,其中itch_type ==“FB”:

mydata_updated
   pitch_type velocity l2_velo_fb
1          FB       99         NA
2          SI       97         NA
3          CU       83         NA
4          FB       97      98.00
5          CH       85      98.00
6          FB      101      99.00
7          FS       82      99.00
8          SL       84      99.00
9          FB      100      99.25
10         CH       83      99.25

看起来相对简单,但我一生都无法在网上找到与我正在寻找的类似的例子。在创建新列时,我有许多不同的列和条件需要完成,因此为每个过滤器创建新的数据框远非理想。

我确实找到了这个例子:

mutate(last1000FBvelo = ifelse(pitch_type %in% c("FB"),
rollapply(release_speed, 1000, mean, fill = NA, align = 'right', na.rm = TRUE), NA),

但我需要它恢复到之前的值,而不是 NA。此外,其中一些列的运行时间大约需要 30 分钟。

我还意识到有许多软件包可以计算滚动平均值(zoo、RccpRoll、slider、runner 是我遇到过的软件包)。很难说出什么对于我的用例来说是最有效的 - 假设其中一个可以实现条件过滤。

任何意见都将不胜感激

另外 - 并不重要,甚至没有必要,但如果有一个简单的选项来使用加权移动平均线,对最近的观察结果进行更多的权重,那就太棒了。

r dplyr zoo rolling-computation
1个回答
0
投票

我不确定

99.25
,但这里有一个方法:

library(dplyr)
# library(zoo)
mydata %>%
  mutate(
    l2_velo_fb = if (first(pitch_type == "FB")) {
        zoo::rollmeanr(velocity, 2, na.pad = TRUE) 
      } else rep(NA_real_, n()),
    .by=pitch_type) |>
  mutate(l2_velo_fb = zoo::na.locf(l2_velo_fb, na.rm = FALSE))
#    pitch_type velocity l2_velo_fb
# 1          FB       99         NA
# 2          SI       97         NA
# 3          CU       83         NA
# 4          FB       97       98.0
# 5          CH       85       98.0
# 6          FB      101       99.0
# 7          FS       82       99.0
# 8          SL       84       99.0
# 9          FB      100      100.5
# 10         CH       83      100.5

if (...) zoo::rollmeanr(..) else NA
实际上只是一个很小的效率:如果您不想计算非
FB
数据的滚动平均值,那么在
if (.)
之前使用
rollmeanr
可以让我们避免计算和丢弃结果。 (这也是我按
pitch_type
分组的原因。)

我认为这是不正确的,因为一个简单的 2 宽滚动右均值是:

filter(mydata, pitch_type == "FB") %>%
  mutate(vb=zoo::rollmeanr(velocity, 2, na.pad = TRUE))
#   pitch_type velocity    vb
# 1         FB       99    NA
# 2         FB       97  98.0
# 3         FB      101  99.0
# 4         FB      100 100.5

.by=
的使用基于
dplyr_1.1.0
或更新版本。如果你年纪大了,那就改成

mydata %>%
  group_by(pitch_type) %>%
  mutate(
    l2_velo_fb = ...
  ) %>%
  ungroup() %>% ...
© www.soinside.com 2019 - 2024. All rights reserved.