【问题标题】:Mutate a new column based on the index of nearest TRUE value from another column根据与另一列最接近的 TRUE 值的索引来改变新列
【发布时间】:2020-03-19 06:43:14
【问题描述】:

我有一个数据框,其中一列指定为组代码,另外两列包含逻辑向量。我想根据以下条件改变一个新列:

  1. 数据框将首先根据列x进行分组
  2. 获取TRUE值在b中的索引
  3. 新列应包含bTRUE 值之前最接近的TRUE 值的索引。如果a中有多个TRUE值,则只获取与b最近的TRUE值的索引。
  4. 生成的索引值将与b 中的TRUE 值放在同一行。

这是我的示例数据:

x = rep(c(1:5), each = 10)

a = c(TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE,
  FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
  FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
  FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, 
  FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE)

b = c(FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,
  FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, 
  FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
  FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, 
  FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE)

df <- data.frame(x ,a, b)

我的代码没有给出我想要的结果:

df %>%
  group_by(x) %>%
  mutate(xx = ifelse(b == TRUE, 
                     which(b)[findInterval(which(a), which(b))], 
                     NA))

我想要的输出如下所示:

   x     a     b xx
1  1  TRUE FALSE NA
2  1 FALSE FALSE NA
3  1 FALSE FALSE NA
4  1 FALSE  TRUE  1
5  1 FALSE FALSE NA
6  1 FALSE FALSE NA
7  1  TRUE FALSE NA
8  1 FALSE FALSE NA
9  1 FALSE FALSE NA
10 1 FALSE  TRUE  7
11 2 FALSE FALSE NA
12 2 FALSE FALSE NA
13 2 FALSE FALSE NA
14 2 FALSE FALSE NA
15 2 FALSE FALSE NA
16 2 FALSE FALSE NA
17 2 FALSE FALSE NA
18 2 FALSE  TRUE NA
19 2 FALSE FALSE NA
20 2 FALSE FALSE NA
21 3 FALSE FALSE NA
22 3 FALSE FALSE NA
23 3  TRUE FALSE NA
24 3 FALSE FALSE NA
25 3 FALSE FALSE NA
26 3 FALSE FALSE NA
27 3 FALSE FALSE NA
28 3 FALSE FALSE NA
29 3 FALSE FALSE NA
30 3 FALSE FALSE NA
31 4 FALSE FALSE NA
32 4 FALSE FALSE NA
33 4 FALSE FALSE NA
34 4  TRUE FALSE NA
35 4 FALSE FALSE NA
36 4  TRUE FALSE NA
37 4 FALSE FALSE NA
38 4 FALSE FALSE NA
39 4 FALSE  TRUE 36
40 4 FALSE FALSE NA
41 5 FALSE FALSE NA
42 5  TRUE FALSE NA
43 5 FALSE FALSE NA
44 5 FALSE FALSE NA
45 5 FALSE FALSE NA
46 5 FALSE FALSE NA
47 5 FALSE FALSE NA
48 5 FALSE FALSE NA
49 5 FALSE  TRUE 42
50 5 FALSE FALSE NA

我也想过将数据框转换为列表并使用 map() 但我不知道如何从这里开始......

df %>% split(.$x) %>%
  map(~mutate(xx = ifelse(b == TRUE, 
                          which(b)[findInterval(which(a), which(b))], 
                          NA)))

【问题讨论】:

    标签: r indexing dplyr


    【解决方案1】:

    使用findIntervaldplyr 版本。

    library(dplyr)
    
    df %>%
      mutate(row = row_number(), xx = NA) %>%
      group_by(x) %>%
      mutate(xx = replace(xx, b,
                  row[a][findInterval(row[b], row[a])][seq_len(sum(b))])) %>%
      select(-row) %>%
      data.frame()
    

    返回:

    #   x     a     b xx
    #1  1  TRUE FALSE NA
    #2  1 FALSE FALSE NA
    #3  1 FALSE FALSE NA
    #4  1 FALSE  TRUE  1
    #5  1 FALSE FALSE NA
    #6  1 FALSE FALSE NA
    #7  1  TRUE FALSE NA
    #8  1 FALSE FALSE NA
    #9  1 FALSE FALSE NA
    #10 1 FALSE  TRUE  7
    #11 2 FALSE FALSE NA
    #12 2 FALSE FALSE NA
    #13 2 FALSE FALSE NA
    #14 2 FALSE FALSE NA
    #15 2 FALSE FALSE NA
    #16 2 FALSE FALSE NA
    #17 2 FALSE FALSE NA
    #18 2 FALSE  TRUE NA
    #19 2 FALSE FALSE NA
    #20 2 FALSE FALSE NA
    #21 3 FALSE FALSE NA
    #22 3 FALSE FALSE NA
    #23 3  TRUE FALSE NA
    #24 3 FALSE FALSE NA
    #25 3 FALSE FALSE NA
    #26 3 FALSE FALSE NA
    #27 3 FALSE FALSE NA
    #28 3 FALSE FALSE NA
    #29 3 FALSE FALSE NA
    #30 3 FALSE FALSE NA
    #31 4 FALSE FALSE NA
    #32 4 FALSE FALSE NA
    #33 4 FALSE FALSE NA
    #34 4  TRUE FALSE NA
    #35 4 FALSE FALSE NA
    #36 4  TRUE FALSE NA
    #37 4 FALSE FALSE NA
    #38 4 FALSE FALSE NA
    #39 4 FALSE  TRUE 36
    #40 4 FALSE FALSE NA
    #41 5 FALSE FALSE NA
    #42 5  TRUE FALSE NA
    #43 5 FALSE FALSE NA
    #44 5 FALSE FALSE NA
    #45 5 FALSE FALSE NA
    #46 5 FALSE FALSE NA
    #47 5 FALSE FALSE NA
    #48 5 FALSE FALSE NA
    #49 5 FALSE  TRUE 42
    #50 5 FALSE FALSE NA
    

    主要逻辑在mutate这一行,我们replaceNA的值在b位置由最接近的a值的索引(行号)。

    【讨论】:

    • 这正是我正在寻找的解决方法。感谢您解释解决方案背后的逻辑。我刚刚将它应用到我的真实数据集上,它就奏效了!
    【解决方案2】:

    不是dplyr,但这种by 方法有效(虽然不是很优雅)。 by 在内部将数据拆分为 x-groups,存储在 w 中,其中 bTRUE,并返回 value-else-NA-vector,其中 value 是 @ a == TRUE的987654329@对应w的。

    df$xx <- as.numeric(unlist(by(df, df$x, function(s) {
      o <- rep(NA, nrow(s))
      if (!(any(s$a) & any(s$b))) o
      else {
        w <- which(s$b)
        y <- cumsum(s$a)[w]
        mapply(function(z, v) o[v] <<- rownames(s)[el(which(cumsum(s$a) == z))], y, w)
        return(o)
      }
    })))
    

    结果

    df
    #    x     a     b xx
    # 1  1  TRUE FALSE NA
    # 2  1 FALSE FALSE NA
    # 3  1 FALSE FALSE NA
    # 4  1 FALSE  TRUE  1
    # 5  1 FALSE FALSE NA
    # 6  1 FALSE FALSE NA
    # 7  1  TRUE FALSE NA
    # 8  1 FALSE FALSE NA
    # 9  1 FALSE FALSE NA
    # 10 1 FALSE  TRUE  7
    # 11 2 FALSE FALSE NA
    # 12 2 FALSE FALSE NA
    # 13 2 FALSE FALSE NA
    # 14 2 FALSE FALSE NA
    # 15 2 FALSE FALSE NA
    # 16 2 FALSE FALSE NA
    # 17 2 FALSE FALSE NA
    # 18 2 FALSE  TRUE NA
    # 19 2 FALSE FALSE NA
    # 20 2 FALSE FALSE NA
    # 21 3 FALSE FALSE NA
    # 22 3 FALSE FALSE NA
    # 23 3  TRUE FALSE NA
    # 24 3 FALSE FALSE NA
    # 25 3 FALSE FALSE NA
    # 26 3 FALSE FALSE NA
    # 27 3 FALSE FALSE NA
    # 28 3 FALSE FALSE NA
    # 29 3 FALSE FALSE NA
    # 30 3 FALSE FALSE NA
    # 31 4 FALSE FALSE NA
    # 32 4 FALSE FALSE NA
    # 33 4 FALSE FALSE NA
    # 34 4  TRUE FALSE NA
    # 35 4 FALSE FALSE NA
    # 36 4  TRUE FALSE NA
    # 37 4 FALSE FALSE NA
    # 38 4 FALSE FALSE NA
    # 39 4 FALSE  TRUE 36
    # 40 4 FALSE FALSE NA
    # 41 5 FALSE FALSE NA
    # 42 5  TRUE FALSE NA
    # 43 5 FALSE FALSE NA
    # 44 5 FALSE FALSE NA
    # 45 5 FALSE FALSE NA
    # 46 5 FALSE FALSE NA
    # 47 5 FALSE FALSE NA
    # 48 5 FALSE FALSE NA
    # 49 5 FALSE  TRUE 42
    # 50 5 FALSE FALSE NA
    

    【讨论】:

    • 您的解决方案很有趣。我以前从未使用过by。我会剖析每个部分,我可能会学到一两个新东西。感谢您的帮助!
    • @mand3rd 基本上bysplit .. &lt;doing stuff&gt; ... unsplit,见?by?split
    猜你喜欢
    • 1970-01-01
    • 2021-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-05
    • 1970-01-01
    • 2012-04-08
    相关资源
    最近更新 更多