复杂的条件变异:仅使用给定参与者的过去观察来创建具有条件变异的新变量?

Complex conditional mutating: Create new variable with conditional mutating using only past observations for a given participant?

我有一个数据框 (fbwb),在一组参与者中使用多项措施 (1-3) 对欺凌行为 (1-6) 进行了多项评估。 df 看起来像这样:

fbwb <- read.table(text="id year bully1 bully2 bully3 cbully bully_ever 
100 1 NA 1 NA 1 1
100 2 1 1 NA 1 1
100 3 NA 0 NA 0 1
101 1 NA NA 1 1 1
102 1 NA 1 NA 1 1
102 2 NA NA NA NA 1
102 3 NA 1 1 1 1
102 4 0 0 0 0 1
103 1 NA 1 NA 1 1
103 2 NA 0 0 0 1", header=TRUE)

其中 bully1、bully2 和 bully3 是二进制变量,如果在相应的度量中报告了欺凌行为,则每个变量 = 1。 cbully 是二进制的,如果给定年份的 3 个欺凌变量中的任何一个 = 1,则 cbully = 1。 bully_ever 是二元的,如果针对给定参与者在任何一年的任何测量中报告了欺凌行为,则 = 1。

我想在我的 df 中创建一个名为 bully_past 的新二进制变量。 bully_past 表示 cbully = 1 in ANY PAST YEAR 时的情况。这与 bully_ever 略有不同。例如,如果参与者已被评估 4 次:

我已经尝试了很多东西,但最近的演绎如下:

fbwb <- fbwb %>%
  dplyr::group_by(id) %>%
  dplyr::mutate(bully_past = case_when(cbully == 1 & year == (year - 1) |
                                         cbully == 1 & year == (year - 2) |
                                         cbully == 1 & year == (year - 3) |
                                         cbully == 1 & year == (year - 4) |
                                         cbully == 1 & year == (year - 5) ~ 1,
                                       (is.na(cbully) & year == (year - 1) &
                                         is.na(cbully) & year == (year - 2) &
                                         is.na(cbully) & year == (year - 3) &
                                         is.na(cbully) & year == (year - 4) &
                                         is.na(cbully) & year == (year - 5)) ~ NA_real_,
                                       TRUE ~ 0)) %>%
  dplyr::ungroup()

这不起作用,因为指示使用哪些年份的语法不正确 - 因此它生成一列 NA 值。我做了其他尝试,但我没能考虑到所有前几年的观察结果。

可以使用以下代码在 Stata 中完成:

gen bullyingever = bullying
sort iid time
replace bullyingever = 1 if bullying[_n - 1]==1 & iid[_n - 1]==iid
replace bullyingever = 1 if bullying[_n - 2]==1 & iid[_n - 2]==iid
replace bullyingever = 1 if bullying[_n - 3]==1 & iid[_n - 3]==iid
replace bullyingever = 1 if bullying[_n - 4]==1 & iid[_n - 4]==iid
replace bullyingever = 1 if bullying[_n - 5]==1 & iid[_n - 5]==iid

我感谢任何关于如何在 R 中完成此操作的输入,最好使用 dplyr。

在这里,我们可以编写一个辅助函数,它可以使用 cumsum(保存事件的累积帐户,让您查看过去)和 lag() 来查看以前的事件,以便仅查看当前值的后面。所以我们有

had_previous_event <- function(x) {
  lag(cumsum(!is.na(x) & x==1)>0)
}

然后您可以将其与您的 dplyr 链一起使用

fbwb %>%
  arrange(id, year) %>% 
  group_by(id) %>%
  mutate(bully_past = had_previous_event(cbully))

这个 returns TRUE/FALSE 但如果你想要 zero/one 你可以把它改成

  mutate(bully_past = as.numeric(had_previous_event(cbully)))

一个解决方案可以使用 dplyrifelse 作为:

library(dplyr)

  fbwb  %>% group_by(id) %>%
  arrange(id, year) %>%
  mutate(bully_past_year = ifelse(is.na(lag(cbully)), 0L, lag(cbully))) %>%
  mutate(bully_past = ifelse(cumsum(bully_past_year)>0L, 1L, 0 )) %>%
  select(-bully_past_year) %>% as.data.frame()

  #    id   year bully1 bully2 bully3 cbully bully_ever bully_past
  # 1  100    1     NA      1     NA      1          1          0
  # 2  100    2      1      1     NA      1          1          1
  # 3  100    3     NA      0     NA      0          1          1
  # 4  101    1     NA     NA      1      1          1          0
  # 5  102    1     NA      1     NA      1          1          0
  # 6  102    2     NA     NA     NA     NA          1          1
  # 7  102    3     NA      1      1      1          1          1
  # 8  102    4      0      0      0      0          1          1
  # 9  103    1     NA      1     NA      1          1          0
  # 10 103    2     NA      0      0      0          1          1  

有另一种方法 聚合在 non-equi self-join 中。这种方法的好处是它甚至可以处理无序数据。

library(data.table)
# coerce to data.table
bp <- setDT(fbwb)[
  # non equi self-join and aggregate within the join
  fbwb, on = .(id, year < year), as.integer(any(cbully)), by = .EACHI][]
# append new column
fbwb[, bully_past := bp$V1][]
     id year bully1 bully2 bully3 cbully bully_ever bully_past
 1: 100    1     NA      1     NA      1          1         NA
 2: 100    2      1      1     NA      1          1          1
 3: 100    3     NA      0     NA      0          1          1
 4: 101    1     NA     NA      1      1          1         NA
 5: 102    1     NA      1     NA      1          1         NA
 6: 102    2     NA     NA     NA     NA          1          1
 7: 102    3     NA      1      1      1          1          1
 8: 102    4      0      0      0      0          1          1
 9: 103    1     NA      1     NA      1          1         NA
10: 103    2     NA      0      0      0          1          1

non-equi 连接条件仅考虑前几年。因此,根据 OP 的要求,每个 id 的第一年是 NA

any() 函数 returns TRUE 如果至少有一个值是 TRUE (在强制类型逻辑之后)。在R中,整数值1L对应于逻辑值TRUE