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



我有一个数据帧(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,则 = 1。 bully_ever是二元的,如果在任何一年中对给定参与者的任何措施报告了欺凌行为,则= 1。

我想在我的 df 中创建一个名为 bully_past 的新二进制变量。 bully_past表示过去任何一年中 cbully = 1 的情况。这与bully_ever略有不同。例如,如果参与者被评估了 4 次:

  • bully_past应该在 4 年级使用第 3、2 和 1 年的信息。
  • bully_past应该在 3 年级使用第 2 年和第 1 年的信息。
  • bully_past应该使用第 1 年和第 2 年的信息。
  • bully_past在第 1 年应该是 NA。

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

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))

这将返回 TRUE/FALSE,但如果您想要零/一,您可以将其更改为

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  

还有一种替代方法,该方法聚合在非等值自连接中。这种方法的好处是,即使对于无序数据,它也可以工作。

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

非等值连接条件仅考虑前几年。因此,每个id的第一年都是根据OP的要求NA的。

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

最新更新