【问题标题】:For each row check if value in one column exists in two other columns对于每一行,检查一列中的值是否存在于其他两列中
【发布时间】:2016-12-04 18:22:14
【问题描述】:

假设我们有以下data frame

df <- data.frame(X1 = 1:5, X2 = 6:10, X3 = c(6, 2, 3, 0, 2))

  X1 X2 X3
1  1  6  6
2  2  7  2
3  3  8  3
4  4  9  0
5  5 10  2

我想添加一个由逻辑值组成的新列 (X4)。对于每一行:如果X3 等于X1X2,则X4 应为TRUE,否则为FALSE

我试过了:

mutate(df, X4 = X3 %in% c(X2, X1))

  X1 X2 X3    X4
1  1  6  6  TRUE # OK
2  2  7  2  TRUE # OK
3  3  8  3  TRUE # OK
4  4  9  0 FALSE # OK
5  5 10  2  TRUE # expected to be FALSE

最重要的是,我的真实df非常很大,所以我想避免使用for-loops。我会优先考虑最短(更少的代码)和最快的解决方案。

【问题讨论】:

  • 我认为你需要mutate(df, X4 = X3 == X1 | X3 == X2)c(X2, X1) 将连接列 X1 和 X2,因此您正在检查 X3 中的元素是否来自 X1X2 组合。

标签: r dplyr


【解决方案1】:

您可以进行矢量化,这可能是最快的:

df$X4 <- with(df, X3==X1 | X3==X2)

基准测试

library(microbenchmark)
df <- data.frame(X1 = 1:5, X2 = 6:10, X3 = c(6, 2, 3, 0, 2))

f1 <- function(df) apply(df[1:3], 1, FUN = anyDuplicated)>0
f2 <- function(df) Reduce(`|`, lapply(df[1:2], `==`, df[,3]))
f3 <- function(df) with(df, X3==X1 | X3==X2)

all(f1(df)==f2(df))
#[1] TRUE
all(f1(df)==f3(df))
#[1] TRUE

res <- microbenchmark(f1(df), f2(df), f3(df))

print(res, order="mean")

# Unit: microseconds
   # expr     min       lq      mean  median      uq     max neval
 # f3(df)  14.115  15.3980  17.57113  17.537  17.965  40.634   100
 # f2(df)  79.130  80.8405  86.41780  85.118  88.325 124.468   100
 # f1(df) 223.273 225.6255 235.95907 228.619 238.243 497.445   100

【讨论】:

    【解决方案2】:

    我们可以使用Reduce

    Reduce(`|`, lapply(df[1:2], `==`, df[,3]))
    #[1]  TRUE  TRUE  TRUE FALSE FALSE
    

    基准测试

    在更大的数据上更有意义

    library(microbenchmark)
    set.seed(24)
    df <- data.frame(X1= sample(1:5, 1e6, replace=TRUE), X2 = sample(1:10, 1e6, replace=TRUE),
           X3 = sample(1:10, 1e6, replace=TRUE))
    
    f2 <- function(df) Reduce(`|`, lapply(df[1:2], `==`, df[,3]))
    f3 <- function(df) with(df, X3==X1 | X3==X2)
    microbenchmark(f1(df), f2(df), f3(df))
    #Unit: milliseconds
    #   expr         min         lq       mean     median         uq      max neval
    
    # f2(df)    8.191218   10.83333   23.28081   16.42744   22.26866  143.025   100
    # f3(df)    8.154506   10.58878   19.17879   11.49179   22.41255  144.510   100
    

    apply 比我想象的要慢,但 Reduce 没有那么慢..

    【讨论】:

    • anyDuplicateddf1 &lt;- data.frame(X1 = 1:3, X2 = c(1, 1, 2), X3 = 9) 不起作用?
    • @zx8754 是的,你是对的。这个想法是基于位置
    • 回复here后找到你的帖子,也许只是删除任何重复的选项?减少仍然可以正常工作。
    【解决方案3】:

    使用 的解决方案。

    library(dplyr)
    
    df %>%
      rowwise() %>%
      mutate(X4 = any(c(X1, X2) %in% X3)) %>%
      ungroup()
    
    # # A tibble: 5 x 4
    #      X1    X2    X3 X4   
    #   <int> <int> <dbl> <lgl>
    # 1     1     6  6.00 T    
    # 2     2     7  2.00 T    
    # 3     3     8  3.00 T    
    # 4     4     9  0    F    
    # 5     5    10  2.00 F  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-07
      • 1970-01-01
      • 1970-01-01
      • 2019-02-22
      • 2020-10-11
      • 1970-01-01
      • 2022-01-21
      • 2022-09-26
      相关资源
      最近更新 更多