【问题标题】:For loop that references prior rows引用先前行的 for 循环
【发布时间】:2019-11-23 21:04:38
【问题描述】:

我有兴趣根据一组规则过滤掉数据。

我有一个数据集,其中包含一支球队在某个时刻获胜概率为 0.8 的所有比赛的比赛数据。我想做的是找到获胜概率达到 0.8 的那个点,然后删除所有游戏,直到下一个游戏数据开始。该数据集包含许多游戏,因此一旦游戏结束,新游戏的数据就会开始,其中获胜概率会回到 0.5 左右。

以下是相关的列,每一行都是游戏中的一个游戏:

  • game_id = 每个游戏的唯一编号
  • team = 最终获胜概率为 0.8 的团队
  • play_id = 每次播放后增加的数量(但由于某种原因不需要按顺序)
  • win_per = num 显示在记录的比赛开始时球队获胜的概率是多少

示例 df

df = data.frame(game_id = c(122,122,122,122,122,144,144,144,144,144),
team = c("a","a","a","a","a", "b","b","b","b","b"),
play_id = c(1,5,22,25,34, 45,47,55,58,66),
win_per = c(.5,.6,.86,.81,.85,.54,.43,.47,.81,.77))

所以在这个小例子中,我记录了两支球队(a 和 b)的 5 场比赛,他们在比赛的某个时刻都获得了至少 0.8 的 win_prob。在这两种示例情况下,我都希望在达到 0.8 标记之后删除所有播放,无论 win_prob 是继续上升还是回落到 0.8 以下。

因此,团队 a 将删除最后两行数据(win_prob == .81 和 .85),而团队 b 将删除最后一行数据(win_prob = .77)

我正在想象运行一个 for 循环来检查任何一行中的团队是否与前一行中的团队相同,如果是,则找到具有最低 play-id 的 win_prob >= .8(因为这将是团队第一次达到 0.8),然后以某种方式删除该匹配之后的其余行,直到团队!= 前一行的团队。

当然,您也可能知道更好的方法。非常感谢您帮助我!

【问题讨论】:

  • 我应该注意,play_id 将为每个录制的游戏重新启动,因此它们不会在整个数据集中继续保持更大的数字

标签: r for-loop


【解决方案1】:

无需使用循环,整个选择可以使用 dplyr 包在 1 行中执行:

df = data.frame(game_id = c(122,122,122,122,122,144,144,144,144,144),
                team = c("a","a","a","a","a", "b","b","b","b","b"),
                play_id = c(1,5,22,25,34, 45,47,55,58,66),
                win_per = c(.5,.6,.86,.81,.85,.54,.43,.47,.81,.77))


library(dplyr)
#group by team
#find the first row that exceeds .80 and add temp column
#save the row from 1 to the row that exceeds 0.80
#remove temp column
df %>% group_by(team, game_id) %>% 
       mutate(g80= min(which(win_per>=0.80))) %>% 
       slice(1:g80) %>% 
       select(-g80)

# A tibble: 7 x 4
# Groups:   team [2]
  game_id team  play_id win_per
    <dbl> <fct>   <dbl>   <dbl>
1     122 a           1    0.5 
2     122 a           5    0.6 
3     122 a          22    0.86
4     144 b          45    0.54
5     144 b          47    0.43
6     144 b          55    0.47
7     144 b          58    0.81

【讨论】:

  • 所以我想我发现了一个错误。我没有明确说明同一支球队在本赛季后期或接下来的赛季中的不同比赛中多次出现在此数据中,因此 group_by 将所有这些数据放在一起。想象一下我给出的示例中的团队 a 与团队 b,然后在某个地方,团队 a 与团队 g 或团队 b 与团队 r 等等。
  • @JeffHenderson,如果是这样,那么group_by(team, game_id),我在上面进行了编辑以反映每个唯一团队和游戏 ID 的搜索。
  • @JeffHenderson,上面的编辑回答了你的问题吗?
【解决方案2】:

这是在ave 中使用cumsum 的基本R 方式

subset(df, ave(win_per > 0.8, game_id, FUN = function(x) c(0, cumsum(x)[-length(x)])) == 0)

#  game_id team play_id win_per
#1     122    a       1    0.50
#2     122    a       5    0.60
#3     122    a      22    0.86
#6     144    b      45    0.54
#7     144    b      47    0.43
#8     144    b      55    0.47
#9     144    b      58    0.81

并在dplyr中使用类似的概念

library(dplyr)
df %>% group_by(game_id) %>% filter(lag(cumsum(win_per > 0.8) == 0, default = TRUE))

【讨论】:

  • 这很好用!还有一个问题。如果我想做相反的事情,代码是什么?假设我想删除导致 win_per .3 或更低的第一行的行,然后为该 game_id 保留其他所有内容?
  • @JeffHenderson 在这种情况下,你可以这样做df %&gt;% group_by(game_id) %&gt;% filter(cumsum(win_per &gt; 0.3) != 0)
  • 这似乎不起作用,在 win_per 降至 0.3 或更低之前,我仍然看到行。请记住,win_per 的大多数第一行开始于 0.5 左右,然后最终下降到 0.3 或更低,然后再回升。我希望在 win_per 下降到 .3 之前删除所有行,并在每个 game_id 之后保留该行与 .3 以及所有行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-01
  • 2021-07-07
  • 1970-01-01
  • 2020-03-03
  • 1970-01-01
  • 2021-02-28
相关资源
最近更新 更多