【问题标题】:Conditional matching of two lists with multi-column data.frames两个列表与多列 data.frames 的条件匹配
【发布时间】:2013-06-19 18:37:00
【问题描述】:

我有一个 data.frames 列表,每个 data.frames 中有多个列。每个 data.frame 具有相同的结构。 此外,我还有另一个包含多个 data.frames 的列表。

假设这是两个列表:

firstlist <- list(a=data.frame(AA=5:1,
                        BB=1:5),
           b=data.frame(AA=5:1,
                        BB=1:5),
           c=data.frame(AA=5:1,
                        BB=1:5))
secondlist <- list(a=data.frame(AA=1:10,
                        BB=c(0,0,1,0,0,1,1,0,0,0)),
           b=data.frame(AA=1:10,
                        BB=c(0,1,0,0,0,0,1,0,0,0)),
           c=data.frame(AA=1:10,
                        BB=c(1,0,0,0,0,1,1,0,0,0)))

现在我想将 CC 列添加到 firstlist 中的所有 data.frames 中,并将它们相应地填充到 secondlist 中 BB 列中的值。

问题是:我需要检查 firstlist 中 AA 或 BB 中的行是否包含 secondlist 中 AA 中的值,并用 secondlist 中 BB 中的值填充 firstlist 中的新列 CC。

上面示例数据的预期结果是:

> firstlist
$a
     AA BB CC
  1  5  1  0
  2  4  2  0
  3  3  3  1
  4  2  4  0
  5  1  5  0

$b
    AA BB CC
  1  5  1  0
  2  4  2  1
  3  3  3  0
  4  2  4  1
  5  1  5  0

$c
    AA BB CC
  1  5  1  1
  2  4  2  0
  3  3  3  0
  4  2  4  0
  5  1  5  1

我需要使用 For 循环还是有其他方法?

更新: 有关布尔数据,请参阅Thell's solution,有关所有数据类型,请参阅 eddie's solution

提前谢谢你!

【问题讨论】:

  • 您能否向我们展示您的数据的预期结果?第一部分对我来说有点不清楚......“我需要检查 firstlist 中的 AA 还是 BB 中的行......”
  • @Arun 我已经编辑了这个问题。添加了预期的结果。换句话说:我需要检查 firstlist 的每个 data.frame 中的 AA 或 BB 列中的任何行是否包含与 secondlist 的同名 data.frame 中 AA 列中的行相同的值。如果是这样,我需要用 secondlist 中 BB 的相应值填充 firstlist 中的新列 CC。听起来更复杂,但我不知道如何更好地描述它。
  • $b栏CC0,1,0,1,0怎么样?你能解释一下吗?
  • 我在注释代码时遇到问题。这是因为在 secondlist $b 中,BB 列在 2 和 7 处为 1。在 firstlist 中,第 2 行 BB 和第 4 AA 行中有 2。
  • CC 真的是 TRUE/FALSE 还是只是一个例子?

标签: r list dataframe


【解决方案1】:

如果 CC 是真正的布尔值...

f <- function(a,b) cbind( a, CC=b$BB[ match( a$AA, b$AA ) ] |
                                b$BB[ match( a$BB, b$AA ) ]   )
mapply( f, firstlist, secondlist, SIMPLIFY=F )

直截了当、快速且保持名字......

示例与 lapply 版本的基准::

Unit: milliseconds
          expr       min       lq   median       uq      max neval
   this mapply  1.726471 1.840671 1.870504 1.939473 13.88875   100
 Arun's lapply  2.930061 3.048110 3.134402 3.209786 14.61630   100

【讨论】:

    【解决方案2】:

    这是另一种相对较短的方式(假设secondlist 中的BB 是二进制的(只有0 和另一个值):

    lapply(seq_along(firstlist), function(ix) {
        tt <- secondlist[[ix]][secondlist[[ix]]$BB != 0, ]
        transform(firstlist[[ix]], CC = 1 * (firstlist[[ix]]$AA %in% tt$AA | 
            firstlist[[ix]]$BB %in% tt$AA))
    })
    

    【讨论】:

    • 谢谢!因为它是二进制的,所以效果很好。只是一个表面问题:有没有办法保留“firstlist”的“名字”?我可以恢复它们,因为它们也存储在一个额外的向量中,但保留它们会很好。
    • 你可以用setNames() 包裹lapply 像:out &lt;- setNames(lapply(...), names(firstlist))
    【解决方案3】:
    lapply(seq_along(firstlist),
           function(i) {
             d.1 = merge(firstlist[[i]], secondlist[[i]], by = "AA", sort = FALSE)
             names(d.1) = c("AA", "BB", "CC")
             d.2 = suppressWarnings(merge(firstlist[[i]], secondlist[[i]], by.x = "BB", by.y = "AA", sort = FALSE))
             names(d.2) = c("BB", "AA", "CC")
             d.1$CC = 0 + (d.1$CC | d.2$CC)
             d.1
           })
    

    您可能想要重命名上面的列而不是取消警告。

    【讨论】:

    • 我认为比这个更复杂,因为您不会为第一个列表中与 BB 列匹配的人重复条目。
    • 是的,这段代码没有考虑到 BB 形式的 firstlist。它也不保留 data.frames 和列的名称。但这可能是一个很好的开始。
    • @eddi 太棒了!它做了我想要的例子。我会尝试将此应用于实际数据,并会在完成后立即报告。
    • @eddi 您的代码运行良好,但我无法使其适应我的实际数据。这就是我接受另一个答案的原因。
    猜你喜欢
    • 2020-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-14
    • 2013-02-14
    • 1970-01-01
    相关资源
    最近更新 更多