【问题标题】:How do I calculate a weighted moving average with custom weights?如何使用自定义权重计算加权移动平均线?
【发布时间】:2019-07-08 20:58:56
【问题描述】:

我正在处理 NHL 球员的表现数据,并且有一个包含以下变量(以及其他变量)的数据框。 war_82 衡量一个完整的 82 场比赛赛季的球员价值。数据跨越 11 个季节,从 2007-2008 年到 2017-2018 年。

 first_name last_name season    war_82
   <chr>      <chr>     <chr>      <dbl>
 1 5EBASTIAN  AHO       2017-2018 -0.560
 2 AARON      DELL      2016-2017  7.50 
 3 AARON      DELL      2017-2018  1.61 
 4 AARON      DOWNEY    2007-2008 -0.560
 5 AARON      EKBLAD    2014-2015  0.350
 6 AARON      EKBLAD    2015-2016 -0.350
 7 AARON      EKBLAD    2016-2017 -1.39 
 8 AARON      EKBLAD    2017-2018 -0.320
 9 AARON      JOHNSON   2007-2008 -1.42 
10 AARON      JOHNSON   2008-2009 -1.19 

我想减少 war_82 指标的季节变化,并创建一个新变量,即加权 war_82。理想情况下,我会查看 3 个季节的数据,并让第 n 季(当前季节)的权重最高,而第 n-1 季和 n-2 季(前两个季节)随着新近度的降低而减少权重。为了论证的缘故,假设权重为 0.5、0.3 和 0.2。

澄清更新:我希望计算加权移动平均线。例如; Sidney Crosby 的 20172018_weighted_war 将由 2017-2018、2016-2017 和 2015-2016 年确定。他的 20162017_weighted_war 将由 2016-2017、2015-2016 和 2014-2015 确定。以此类推。

我有两个主要问题:

1) 你会为此推荐什么方法?我查看了 weighted.mean(),但有些玩家比其他玩家玩得更多,所以我不确定如何指定“w”(权重)参数。例如,Sidney Crosby 在我的数据集中打了所有 11 个赛季,但许多球员只打了 1 或 2 个赛季。我真的不想丢掉出场时间少于 3 个赛季的球员的数据。

2) 您如何确定每个季节的权重?最简单的方法是我上面提到的方法,它的灵感来自于 Marcel 方法 (https://www.beyondtheboxscore.com/2016/2/22/11079186/projections-marcel-pecota-zips-steamer-explained-guide-math-is-fun)。我想您还可以确定第 n-1 季和第 n-2 季对第 n 季的预测效果如何,并将其用作您的权重?

您将如何解决这个问题?非常感谢任何和所有指导!

【问题讨论】:

    标签: r moving-average weighted-average


    【解决方案1】:

    我对 JasonAizkalns 有类似的回答,但它的不同之处足以让我认为它可能值得发布。

    您可以根据季节调整权重。

    编辑:添加了“滚动平均”

    data <- readr::read_table("
    first_name last_name season    war_82
    5EBASTIAN  AHO       2017-2018 -0.560
    AARON      DELL      2016-2017  7.50 
    AARON      DELL      2017-2018  1.61 
    AARON      DOWNEY    2007-2008 -0.560
    AARON      EKBLAD    2014-2015  0.350
    AARON      EKBLAD    2015-2016 -0.350
    AARON      EKBLAD    2016-2017 -1.39 
    AARON      EKBLAD    2017-2018 -0.320
    AARON      JOHNSON   2007-2008 -1.42 
    AARON      JOHNSON   2008-2009 -1.19")
    
    weigth_war <- function(last3_war) {
        player_season <- as.numeric(stringr::str_split_fixed(last3_war, " ", 3))
        if (is.na(player_season[2]))
            player_season[1]
        else if (is.na(player_season[3]))
            weighted.mean(player_season[1:2], c(0.3, 0.7))
        else
            weighted.mean(player_season, c(0.2, 0.3, 0.5))
    }
    
    library(tidyverse)
    data %>%
        mutate(name = paste(first_name, last_name)) %>%
        group_by(name) %>%
        arrange(name, season) %>%
        mutate(last3_war = paste(war_82, lag(war_82), lag(war_82, 2))) %>%
        ungroup() %>%
        rowwise() %>%
        mutate(weighted_war_82 = weigth_war(last3_war)) %>%
        select(name, season, war_82, weighted_war_82)
    

    【讨论】:

    • 我比我更喜欢这个 +1
    • 我认为,但是,根据您的安排声明,您可能想要翻转权重 - 即 c(0.3, 0.7)c(0.2, 0.3, 0.5) - 无论如何,OP 会想要特别注意排序和测试。
    • 嘿@csgroen,非常感谢,这非常有用,几乎完全解决了我的问题。我认为我没有正确解释这一点,但我希望计算加权移动平均线。例如; Sidney Crosby 的20172018_weighted_war 将在 2017-2018、2016-2017 和 2015-2016 年确定。他的20162017_weighted_war 将由 2016-2017、2015-2016 和 2014-2015 确定。以此类推。
    • @LukeSteer,它不是世界上最优雅的代码,但我认为它有效。我不得不使用这个“last3war”丑陋的解决方案来解决滞后问题,因为直接通过时它的表现不符合我的要求。我还必须这样做rowwise(),以便更轻松地编写weigth_war 函数。希望这能解决您的问题!
    • @csgroen - FWIW,我认为tibbletime::rollify 可能有可能使用您的原始功能并避免paste / str_split_fixed 混乱。无论如何,如果你还没有看过那个包,它有一些很酷的功能值得探索。我也认为rowwise 最终可能会消失——我一直在努力改掉这个习惯。
    【解决方案2】:

    您可以按照您的建议使用 weighted.mean(),并按 11 季中的播放季数加权(1 季 -> 0.091、2 -> 0.18 等)。

    【讨论】:

      【解决方案3】:

      我建议在每个帖子中坚持一个问题。第一个问题的蛮力方法是根据季节数明确表示权重:

      library(tidyverse)
      
      df <- tribble(
        ~player, ~season, ~y,
        "dell", 2017, 1,
        "dell", 2018, 5,
        "johnson", 2016, 2,
        "johnson", 2017, 4,
        "johnson", 2018, 5,
        "downey", 2014, 3,
        "downey", 2015, 5
      )
      
      df %>%
        group_by(player) %>%
        arrange(player, season) %>%
        add_count(player, name = "num_seasons") %>%
        mutate(
          wtd = case_when(
            num_seasons == 1 ~ sum(                                           1.000 * nth(y, -1) ),
            num_seasons == 2 ~ sum(                      0.375 * nth(y, -2) + 0.625 * nth(y, -1) ),
            num_seasons == 3 ~ sum( 0.200 * nth(y, -3) + 0.300 * nth(y, -2) + 0.500 * nth(y, -1) )
          )
        )
      #> # A tibble: 7 x 5
      #> # Groups:   player [3]
      #>   player  season     y num_seasons   wtd
      #>   <chr>    <dbl> <dbl>       <int> <dbl>
      #> 1 dell      2017     1           2  3.5 
      #> 2 dell      2018     5           2  3.5 
      #> 3 downey    2014     3           2  4.25
      #> 4 downey    2015     5           2  4.25
      #> 5 johnson   2016     2           3  4.1 
      #> 6 johnson   2017     4           3  4.1 
      #> 7 johnson   2018     5           3  4.1
      

      【讨论】:

      • 嘿@JasonAizkalns,非常感谢;我也更喜欢 csgroen 的解决方案,但我非常感谢您的反馈。我认为我没有正确解释这一点,但我希望计算加权移动平均线。例如; Sidney Crosby 的 20172018_weighted_war 将由 2017-2018、2016-2017 和 2015-2016 确定。他的 20162017_weighted_war 将由 2016-2017、2015-2016 和 2014-2015 确定。以此类推。
      • 我认为您将不得不使用lagnth - 在这种情况下,可能需要一个更丑陋的解决方案(例如我的)。您可能想重新提出问题并创建一个完全可重复的示例来解决核心问题。考虑让事情像我的df 变量一样简单——只是说明问题中出现的问题的基础知识。一旦您了解了方法/攻击,我认为很容易采用您的具体问题。预先准备好所有的“额外内容”会让人更难以理解。希望这是有道理的?
      • 在您的更新中,您提到了Sidney Crosby,但在您提供的示例数据中没有Sidney Crosby。您可能还对“差距”有疑问——如果一名球员参加了 2014 年、2015 年和 2017 年的比赛——也就是说,他们因伤缺席了 2016 年?再一次,也许是一个快速的例子,说明边缘情况和你的预期结果可能会给你更多的牵引力。那时,您可能只想结束这个问题并提出一个新问题。
      猜你喜欢
      • 2012-04-26
      • 2019-01-31
      • 2017-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-06
      • 2023-03-12
      • 2010-10-04
      相关资源
      最近更新 更多