【问题标题】:Identifying list elements contained in another list that are both elements of a data frame识别另一个列表中包含的同时是数据框元素的列表元素
【发布时间】:2022-08-04 22:31:56
【问题描述】:

我有两个数据框,DF1,DF2,每个都有两列(a,b)。一列 (a) 是唯一标识符,另一列是 (b) 列,其中包含包含列表的元素。该列表包含标签名称。我想搜索 DF2$b 元素以查看它们是否包含在 DF1$b 中,如果是,我想创建一个新列 DF2$c,它采用 DF1a 中的标识符。棘手的部分是,如果唯一标识符是数据框中存在的最小联合,我只想采用唯一标识符。作为一些背景,这些数据来自系统发育树。 DF2 是 DF1 的子样本。 DF2 中的所有提示都包含在 DF1 中。我想将 DF2 的节点与 DF1 的节点进行比较(节点名称不同),但我可以从每个节点的后代的提示中识别节点。

如果我用一个例子来解释会更容易:

df1 <- data.frame(a = c(1486, 1485, 1484, 1483, 1482, 1481, 1480, 1479))
df1$b = list(c(\"KC792204\", \"KF150733\", \"KC792205\"), c(\"KC792204\", \"KF150733\", \"KC792205\", \"JX987740\", \"KX148108\", \"JX987724\"), c(\"KC792204\", \"KF150733\", \"KC792205\", \"KC791848\"), c(\"KJ201900\", \"KJ201899\", \"KF535207\"), c(\"KJ201900\", \"KJ201899\", \"KF535207\", \"AB817119\", \"AB817100\"), c(\"GU731662\", \"GU731661\", \"KP319229\", \"KY428876\"), c(\"GU731662\", \"GU731661\", \"MT826960\"), c(\"GU731662\", \"GU731661\", \"MT826960\", \"AM689535\", \"GU731663\"))

df2 <- data.frame(a = c(8645, 1247, 5879, 1548, 2487, 1245, 1247, 3695))
df2$b = list(c(\"KC792204\", \"KF150733\"), c(\"KC792204\", \"KC792205\", \"KC791848\"), c(\"KJ201900\", \"KF535207\"), c(\"KC792204\", \"JX987740\", \"KX148108\", \"JX987724\"), c(\"GU731662\", \"GU731661\", \"MT826960\", \"GU731663\"), c(\"KJ201900\", \"KJ201899\", \"AB817119\", \"AB817100\"), c(\"GU731661\", \"KP319229\", \"KY428876\"), c(\"GU731662\", \"MT826960\"))

我想在 df2 中创建一个新列 df2$c,它标识 df1 中包含 df2$b 的最小列表(或节点)。这个新列由 df1$a(唯一标识符)创建。在示例中, df2$c (按顺序)

c(\"1486,1484,1483,1485,1479,1482,1481,1480\")

以前两个为例:

df2$a is c(\"KC792204\", \"KF150733\")

这个可以在df1$b[1], df1$b[2], df1$b[3], or 1486, 1485, or 1484.找到,因为我在找最小长度的列表,所以结果是1486。1486是最小长度的列表,包含了所有被搜索的标签。 df2$b is c(\"KC792204\", \"KF150733\", \"KC791848\") 中的下一个列表。这个结果是 1484,因为只有 df$1b 中的列表 1484 包含这三个标签。

我努力了:

df2$c <- ifelse(df2$b %in% df1$b, df1$a, \'other\')

但我将列表作为一个整体而不是每个列表中的元素进行比较。我还需要找到包含搜索标签的最小列表。

    标签: r if-statement dplyr phylogeny ape


    【解决方案1】:

    这是一种使用data.table 和辅助函数的方法

    library(data.table)
    setDT(df1)[, l:=sapply(b,length)]
    f <- function(k) df1[sapply(df1$b,\(i) all(k %chin% i))][l==min(l),a]
    setDT(df2)[, c:=sapply(b,f)]
    

    输出 (df2)

           a                                   b     c
       <num>                              <list> <num>
    1:  8645                   KC792204,KF150733  1486
    2:  1247          KC792204,KC792205,KC791848  1484
    3:  5879                   KJ201900,KF535207  1483
    4:  1548 KC792204,JX987740,KX148108,JX987724  1485
    5:  2487 GU731662,GU731661,MT826960,GU731663  1479
    6:  1245 KJ201900,KJ201899,AB817119,AB817100  1482
    7:  1247          GU731661,KP319229,KY428876  1481
    8:  3695                   GU731662,MT826960  1480
    

    解释:

    • 第 1 行:加载库
    • 第 2 行:向 df1 添加一列,指示 b 中向量的长度 (l)
    • 第 3 行:定义接收字符向量 (k) 的辅助函数 (f),检查以将 df1 中的行限制为 k 的所有元素都在 b 中找到的行,并且在这些行中,返回 a 值,其中 l 被最小化
    • 第4行:将f应用于df2中b的每个值,将结果分配给c

    2022 年 8 月 4 日更新:

    OP 已询问是否可以调整上面的辅助函数,以便从 df1 中的行中选择 a 值,其中 df2$b 中的 p 多个元素在 df1$b 中找到。这里是对辅助函数的一种可能调整:

    f <- function(k, p=1) {
      df1[sapply(df1$b,\(i) mean(k %chin% i)>=p)][l==min(l),a]
    } 
    

    请注意,由于k %chin% i 返回一个逻辑向量,其均值只是 k(即 df2$b)中的元素在i 中的比例,即df1%b..sapply() 仍然返回一个逻辑向量,因为我们随后会询问该比例是否等于或超过p。请注意,由于p 的默认值为1,因此在不指定p 的情况下使用此函数将返回与原始辅助函数相同的结果。

    要从行中选择 a 值是否 95% 的元素匹配,请像以前一样调用修改后的辅助函数 f,但将 p 设置为 0.95

    setDT(df2)[, c:=sapply(b,f, p=0.95)]
    

    【讨论】:

    • 谢谢-这很有效,您的解释非常有用。我有一个后续问题。有没有办法适应这一点,所以我可以设置要在 b 中找到的 k 元素的百分比。正如目前所写的那样,这必须是 100%。在我的数据集中,有几个例子,其中 b 的列表有 500 个值长,而在 b 中只找到了 499 个。我想设置一些东西,所以我可以说,如果在 b 中找到 K 的 95% 的元素,那么继续。
    • 我认为我的编辑为您的问题提供了一种解决方案。看看它是否适合您的需要。
    【解决方案2】:

    这是一种选择:

    library(data.table) # for %chin%
    
    df1 <- data.frame(a = c(1486, 1485, 1484, 1483, 1482, 1481, 1480, 1479))
    df1$b = list(c("KC792204", "KF150733", "KC792205"), c("KC792204", "KF150733", "KC792205", "JX987740", "KX148108", "JX987724"), c("KC792204", "KF150733", "KC792205", "KC791848"), c("KJ201900", "KJ201899", "KF535207"), c("KJ201900", "KJ201899", "KF535207", "AB817119", "AB817100"), c("GU731662", "GU731661", "KP319229", "KY428876"), c("GU731662", "GU731661", "MT826960"), c("GU731662", "GU731661", "MT826960", "AM689535", "GU731663"))
    
    df2 <- data.frame(a = c(8645, 1247, 5879, 1548, 2487, 1245, 1247, 3695))
    df2$b = list(c("KC792204", "KF150733"), c("KC792204", "KC792205", "KC791848"), c("KJ201900", "KF535207"), c("KC792204", "JX987740", "KX148108", "JX987724"), c("GU731662", "GU731661", "MT826960", "GU731663"), c("KJ201900", "KJ201899", "AB817119", "AB817100"), c("GU731661", "KP319229", "KY428876"), c("GU731662", "MT826960"))
    
    df2$c <- df1$a[
      Rfast::colMaxs(
        outer(
          seq_along(df1$b),
          seq_along(df2$b),
          function(i, j) mapply(
            function(x, y) all(y %chin% x),
            df1$b[i],
            df2$b[j]
          )
        )/lengths(df1$b)
      )
    ]
    df2$c
    #> [1] 1486 1484 1483 1485 1479 1482 1481 1480
    

    如果一行可能不匹配,则应修改上述内容:

    m <- outer(
      seq_along(df1$b),
      seq_along(df2$b),
      function(i, j) mapply(
        function(x, y) all(y %chin% x),
        df1$b[i],
        df2$b[j]
      )
    )
    df2$c <- ifelse(colSums(m) == 0L, NA, df1$a[Rfast::colMaxs(m/lengths(df1$b))])
    

    【讨论】:

      猜你喜欢
      • 2019-07-12
      • 1970-01-01
      • 2012-08-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-14
      • 2022-11-14
      • 2021-12-13
      • 1970-01-01
      相关资源
      最近更新 更多