【问题标题】:Match value in dataframe to other occurences in other columns将数据框中的值与其他列中的另一个匹配项匹配
【发布时间】:2021-08-12 08:53:47
【问题描述】:

我有一个如下所示的数据框:

df <- data.frame(a = c('x', 'y', 'z', 't', 'm'), b = c('x', 'x', 'y', NA, 'm'))

> df
  a    b
1 x    x
2 y    x
3 z    y
4 t <NA>
5 m    m

现在,对于“a”和“b”列中的每个值,我想查看它是否存在于“a”和“b”的任何其他行中并返回匹配项。因此,对于第 1 行,我想查看 'x' 或 'y' 是否存在于第 2:5 行的 a 或 b 列中,然后返回 'TRUE'。

我想要的结果是:

> df$match = c(TRUE, TRUE, TRUE, FALSE, FALSE)
> df
  a    b match
1 x    x  TRUE
2 y    x  TRUE
3 z    y  TRUE
4 t <NA> FALSE
5 m    m FALSE

似乎无法找到一种方法来做到这一点。我一直在尝试使用 dplyr:

df %>%
  mutate(match = a %in% b | a %in% a | b %in% b | b %in% a)

但这只是将所有内容都返回为 TRUE。此外,如果 b 为 NA,那么它也将匹配任何其他不希望的 NA 值。

使用按行操作也不起作用,这只是检查行内的值。

【问题讨论】:

  • 如果一个存在而另一个不存在,它将返回 TRUE?
  • 如果您的意思是所需结果中的第 3 行,它应该返回 TRUE,因为 'b' 列中的 'y' 存在于 'a' 列的第 2 行中。否则我可能无法正确理解您的问题

标签: r dplyr


【解决方案1】:

这是使用purrr::imap 解决您的问题的tidyverse 方法:

  • 由于我使用公式快捷方式来定义我的函数.x 参数指的是值,.y 参数指的是位置/名称
  • 我首先转置您的数据集(认为这样可能更容易)然后遍历每一列并检查是否可以在其他列中找到任何元素
  • 为了检查值的存在,我使用.y 参数从原始数据集中删除每列的相应索引,例如转置数据集中的第一列元素与中的值完全相同原始数据集的第一行
library(dplyr)
library(purrr)

df %>%
  t() %>%
  as_tibble(.name_repair = "unique") %>%
  imap_lgl(~ any(unlist(.x) %in% unlist(df[-as.integer(gsub("\\.{3}(\\d)", "\\1", .y)), ]))) %>%
  unlist() -> df$match

  a    b match
1 x    x  TRUE
2 y    x  TRUE
3 z    y  TRUE
4 t <NA> FALSE
5 m    m FALSE

【讨论】:

    【解决方案2】:

    您可以尝试使用igraph 的选项,如下所示

    library(igraph)
    
    transform(
      merge(
        df,
        stack(membership(components(graph_from_data_frame(replace(df, is.na(df), "NA"))))),
        by.x = "a", by.y = "ind"
      ),
      Match = ave(values, values, FUN = length) > 1
    )
    

    给你

      a    b values Match
    1 m    m      3 FALSE
    2 t <NA>      2 FALSE
    3 x    x      1  TRUE
    4 y    x      1  TRUE
    5 z    y      1  TRUE
    

    或者我们可以像下面这样使用dplyr(对不起,我的知识非常有限,一定有比我更好的解决方案)

    df %>%
      left_join(df %>%
        mutate(b = fcoalesce(b, a)) %>%
        graph_from_data_frame() %>%
        components() %>%
        membership() %>%
        stack(),
      by = c("a" = "ind")
      ) %>%
      group_by(values) %>%
      mutate(Match = n() > 1) %>%
      ungroup() %>%
      select(-values)
    

    给了

    # A tibble: 5 x 3
      a     b     Match
      <chr> <chr> <lgl>
    1 x     x     TRUE
    2 y     x     TRUE
    3 z     y     TRUE
    4 t     NA    FALSE
    5 m     m     FALSE
    

    【讨论】:

    • 你太谦虚了,这是一个很好的解决方案。
    • @AnoushiravanR 谢谢。您的解决方案看起来要短得多。酷!
    • 你也是!我希望我知道igprah:D
    • @AnoushiravanR 我(个人)认为igraph 比dplyr 容易:P 我相信你很快就会掌握它。
    • 图论我忘记了很多,所以我想我必须事先复习一下。谢谢我要问你很多关于igraph的问题。
    【解决方案3】:

    我认为这也可以。由于NA %in% c(NA, 'c') 结果为 TRUE,我们可以添加更多条件来检查当前值是否为非 NA

    df <- data.frame(a = c('x', 'y', 'z', 't', 'm'), b = c('x', 'x', 'y', NA, 'm'))
    
    library(tidyverse)
    df %>%
      mutate(xx = map_lgl(row_number(), ~ (a[.x] %in% c(a[-.x], b[-.x]) | b[.x] %in% c(a[-.x], b[-.x])) & !is.na(a[.x]) & !is.na(b[.x]) ))
    
    #>   a    b    xx
    #> 1 x    x  TRUE
    #> 2 y    x  TRUE
    #> 3 z    y  TRUE
    #> 4 t <NA> FALSE
    #> 5 m    m FALSE
    

    由reprex package (v2.0.0) 于 2021-08-12 创建

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-11
      • 2018-06-25
      • 1970-01-01
      • 1970-01-01
      • 2015-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多