【问题标题】:R - Mutating column value based on condition involving other columns' groupsR - 根据涉及其他列组的条件改变列值
【发布时间】:2018-07-22 19:58:13
【问题描述】:

我有来自数据表df 的四列,我想从中得出第五列。当前的四个列是 - yearmonthidconflict。现在conflict 列只有 1 和 0,对于给定的 id 分组,一旦在一年中出现 1,那么在该年剩余的月份中出现 1。我想将conflict 列更改为新列conflict_mutated,如下所示:如果我们在一个给定的年份,其中任何一个月都包含 1 并且前一年在任何月份都包含 1,我想要当年的月份为conflict_mutated 全为 1,同时保留所有旧的 1。

如果我们有这样的数据:

year month id conflict
1989 6     33 0
1989 7     33 0
1989 8     33 1
1989 9     33 1
1989 10    33 1
1989 11    33 1
1989 12    33 1
1990 1     33 0
1990 3     33 0
1990 3     33 0
1990 4     33 0
1990 5     33 1
1990 6     33 1
1990 7     33 1
1990 8     33 1
1990 9     33 1
1990 10    33 1
1990 11    33 1
1990 12    33 1

所以我希望在第 1、2、3 和 4 个月期间 conlfict 中的 0 为 1,因为它们是相同的 id,并且 1989(前一年)和 1990 中都有 1。前面的示例数据将如下所示:

year month id conflict conflict_mutated
1989 6     33 0        0
1989 7     33 0        0
1989 8     33 1        1
1989 9     33 1        1
1989 10    33 1        1
1989 11    33 1        1
1989 12    33 1        1
1990 1     33 0        1
1990 3     33 0        1
1990 3     33 0        1
1990 4     33 0        1
1990 5     33 1        1
1990 6     33 1        1
1990 7     33 1        1
1990 8     33 1        1
1990 9     33 1        1
1990 10    33 1        1
1990 11    33 1        1
1990 12    33 1        1

我有一个解决方案,但需要将近 3 天才能完成。如下:

conflict_mutated = df$conflict

for (i in 1:length(nrow(df)) {
  if (df$year[i] != 1989 & any(filter(df, id == df$id[i], 
    year == (df$year[i] - 1))$conflict == 1) & 
    any(filter(df, id == df$id[i], year == df$year[i])$conflict == 1)) 
        {conflict_mutated[i] = 1}

有没有什么方法可以利用 group_by 和 mutate 来让这更快或更好?考虑到分组年份必须考虑并在条件逻辑中与不同的 id 相结合,无法考虑如何完成。

【问题讨论】:

    标签: r group-by dplyr


    【解决方案1】:
    foo  <- read_csv('df1.csv')
    #print(foo, n =40)
    ## A tibble: 40 x 4
    #    year month    id conflict
    #   <int> <int> <int>    <int>
    # 1  1989     6    33        0
    # 2  1989     7    33        0
    # 3  1989     8    33        1
    # 4  1989     9    33        1
    # 5  1989    10    33        1
    # 6  1989    11    33        1
    # 7  1989    12    33        1
    # 8  1990     1    33        0
    # 9  1990     3    33        0
    #10  1990     3    33        0
    #11  1990     4    33        0
    #12  1990     5    33        1
    #13  1990     6    33        1
    #14  1990     7    33        1
    #15  1990     8    33        1
    #16  1990     9    33        1
    #17  1990    10    33        1
    #18  1990    11    33        1
    #19  1990    12    33        1
    #20  1991     1    33        0
    #21  1989     6    34        0
    #22  1989     7    34        0
    #23  1989     8    34        1
    #24  1989     9    34        1
    #25  1989    10    34        1
    #26  1989    11    34        1
    #27  1989    12    34        1
    #28  1990     1    34        0
    #29  1990     3    34        0
    #30  1990     3    34        0
    #31  1990     4    34        0
    #32  1990     5    34        1
    #33  1990     6    34        1
    #34  1990     7    34        1
    #35  1990     8    34        1
    #36  1990     9    34        1
    #37  1990    10    34        1
    #38  1990    11    34        1
    #39  1990    12    34        1
    #40  1991     1    34        0
    bar  <-  foo %>% group_by(id, year) %>% dplyr::summarize(yrtot = sum(conflict))
    library(data.table)
    bar  %<>% ungroup() %>% group_by(id)  %>%  dplyr::mutate(lastyrtot=shift(yrtot, n=1))
    foo  %<>%  left_join( bar)  %>% 
            dplyr::mutate(conflict_mutate = ifelse(yrtot>1 & lastyrtot >1,1,0) )
    foo %<>% dplyr::mutate(conflict_mutate  =  ifelse(is.na(lastyrtot), conflict, conflict_mutate)) %>% select(-yrtot, -lastyrtot) 
    
    #R> print(foo, n=40)
    ## A tibble: 40 x 5
    #    year month    id conflict conflict_mutate
    #   <int> <int> <int>    <int>           <dbl>
    # 1  1989     6    33        0               0
    # 2  1989     7    33        0               0
    # 3  1989     8    33        1               1
    # 4  1989     9    33        1               1
    # 5  1989    10    33        1               1
    # 6  1989    11    33        1               1
    # 7  1989    12    33        1               1
    # 8  1990     1    33        0               1
    # 9  1990     3    33        0               1
    #10  1990     3    33        0               1
    #11  1990     4    33        0               1
    #12  1990     5    33        1               1
    #13  1990     6    33        1               1
    #14  1990     7    33        1               1
    #15  1990     8    33        1               1
    #16  1990     9    33        1               1
    #17  1990    10    33        1               1
    #18  1990    11    33        1               1
    #19  1990    12    33        1               1
    #20  1991     1    33        0               0
    #21  1989     6    34        0               0
    #22  1989     7    34        0               0
    #23  1989     8    34        1               1
    #24  1989     9    34        1               1
    #25  1989    10    34        1               1
    #26  1989    11    34        1               1
    #27  1989    12    34        1               1
    #28  1990     1    34        0               1
    #29  1990     3    34        0               1
    #30  1990     3    34        0               1
    #31  1990     4    34        0               1
    #32  1990     5    34        1               1
    #33  1990     6    34        1               1
    #34  1990     7    34        1               1
    #35  1990     8    34        1               1
    #36  1990     9    34        1               1
    #37  1990    10    34        1               1
    #38  1990    11    34        1               1
    #39  1990    12    34        1               1
    #40  1991     1    34        0               0
    

    【讨论】:

    • 感谢您的回复!从数据表中可能不清楚,但 conflict 可能会在明年结束,因此并非所有未来月份都编码为 1。换句话说,我只想在 conflict_mutated 中更改 0,如果两者上一年和当前年份包含 1。因此,并非所有未来月份都应更改为 1,因为某些年份可能没有任何 1 开头。另外,我不完全确定,但我认为您的解决方案没有考虑到varyingids。
    • 我使用 dplyr 和 data.table 工具修改了我的答案。我稍微扩展了数据集,以包含 1991 年的“未来”观察结果和第二个“id”。
    猜你喜欢
    • 2023-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多