首页 > 解决方案 > 根据分组数据框中的先前值确定结果

问题描述

我有一个格式如下的数据框:

pair group group_rank win_prob
<int> <int>   <chr>    <dbl>
 1     1      first     0.6
 1     2      second    0.4
 2     3      first     0.5
 2     4      second    0.5

它是使用以下代码片段生成的:

library(tidyverse)

df <- tibble(pair = rep(c("A", "B"), each = 2),
            group = seq(1:4),
            group_rank = c("first", "second", "first", "second"),
            win_prob = c(0.6, 0.4, 0.5, 0.5))

我的目标是将“赢”分配给每对中的一组,将“输”分配给另一组。换句话说,我想生成以下具有新列结果的数据框:

pair group group_rank win_prob outcome
<int> <int>    <chr>      <dbl> <chr>  
  1     1     first       0.6   win    
  1     2     second      0.4   loss   
  2     3     first       0.5   loss   
  2     4     second      0.5   win

将“赢”或“输”分配给结果变量应基于 group_rank 和 win_prob 变量中的相应值。更具体地说,每次我想首先检查 group_rank == "first" 的组是否赢了,通过检查它的 win_prob >= runif(1) (伯努利轨迹)。

如果条件满足,我想给这个组分配“win”。如果条件不满足,我想分配“损失”。

在确定 group_rank == "first" 的组是否获胜后,我想将相反的结果分配给 group_rank == "second" 的组。因此,如果已将“第一”组分配为“赢”,则应将第二组分配为“输”,反之亦然。

在伪代码中,它应该是这样的,但诀窍是如何在分组数据框中查看“第一”组的结果,同时确定“第二”组的结果:

for pair in pairs: 
    if group_rank == ``first'' and win_prob >= runif(1):
        outcome <- ``win''
    else:
        outcome <- ``loss''

    if group_rank == ``second'':
        if outcome == ``win'' for group with group_rank == ``first'':
            outcome <- ``loss''
        else:
            outcome <- ``win''

在 tidyverse 框架中是否有一种简单的方法来实现这一点?

标签: rdplyrtidyverse

解决方案


使用data.table一个可以做到这一点:

res <- c("win", "lose") # Not a good name but this is one of two possible results.
setDT(df)[, 
          outcome := {
            temp = win_prob[1] >= runif(1); 
            ifelse(c(temp, temp), res, rev(res))
          }, 
          by = pair]
df
   pair group group_rank win_prob outcome
1:    A     1      first      0.6     win
2:    A     2     second      0.4    lose
3:    B     3      first      0.5    lose
4:    B     4     second      0.5     win

使用dplyr

df %>%
  group_by(pair) %>%
  mutate(temp = win_prob[1] >= runif(1)) %>%
  mutate(outcome = ifelse(temp, res, rev(res))) %>%
  select(-temp)

注意:
两种解决方案都假设数据已经排序,因此对于每一对,group_rank first 总是出现在上面。


推荐阅读