【问题标题】:Assignment with multiple lapplys in data.table?在 data.table 中分配多个 lapplys?
【发布时间】:2022-01-13 20:52:06
【问题描述】:

有没有比下面两个更优雅的解决方案来对 data.table 列集执行多个操作?我所说的“更优雅”是指作为一个单行而不是结合中间结果。

请注意,我在此特定示例中使用了by,但该问题也适用于非by 情况。

library(data.table)
# create toy data.table
dt <- data.table( 
    ID=sample(1:10, 50, replace=TRUE),
    A=letters[sample(1:26, 50, replace=TRUE)],
    B=letters[sample(1:26, 50, replace=TRUE)],
    C=letters[sample(1:26, 50, replace=TRUE)],
    D=letters[sample(1:26, 50, replace=TRUE)]
  )

# two sets of columns to process differently
use_all <- c("A","B")
just_first <- c("C","D")


# do these separately, then bind columns.  assumes the `by` column is identical across the two:
results <- data.table(
    dt[, lapply(.SD, function(x) x[1]), by=ID, .SDcols= just_first],
    dt[, lapply(.SD, function(x) list(x)), by=ID, .SDcols= use_all][, .SD, .SDcols=-"ID"]
)

# do these separately, then merge.  doesn't assume the `by` column is identically ordered:
results <- merge(
    dt[, lapply(.SD, function(x) x[1]), by=ID, .SDcols= just_first],
    dt[, lapply(.SD, function(x) list(x)), by=ID, .SDcols= use_all],
    by="ID"
)

【问题讨论】:

    标签: r data.table


    【解决方案1】:
    out <- dt[, Map(function(x, nm) if (nm %in% just_first) x[1] else list(x),
                    .SD, names(.SD)),
               by = ID, .SDcols = c(use_all, just_first)]
    out
    #        ID               A               B      C      D
    #     <int>          <list>          <list> <char> <char>
    #  1:     1       f,b,w,x,g       u,s,y,x,r      f      q
    #  2:     5     f,e,l,t,n,j     v,p,i,w,x,b      f      t
    #  3:     9         t,h,m,j         p,z,m,n      o      q
    #  4:    10 c,b,q,e,n,b,... v,i,w,j,a,s,...      b      a
    #  5:     4 v,j,a,i,i,x,... q,y,h,e,p,n,...      j      b
    #  6:     2 u,g,k,e,w,u,... l,f,z,f,k,p,...      w      h
    #  7:     8     f,c,e,r,h,y     u,k,y,q,e,v      i      e
    #  8:     7             z,d             k,q      a      m
    #  9:     3           d,p,d           a,j,q      n      f
    # 10:     6             v,r             y,o      z      t
    
    # results <- data.table(...) # first of your two `results`
    all.equal(out, results[,c(1,4,5,2,3)]) # column-order is different
    # [1] TRUE
    

    可重现的数据:

    set.seed(42)
    dt <- data.table( 
        ID=sample(1:10, 50, replace=TRUE),
        A=letters[sample(1:26, 50, replace=TRUE)],
        B=letters[sample(1:26, 50, replace=TRUE)],
        C=letters[sample(1:26, 50, replace=TRUE)],
        D=letters[sample(1:26, 50, replace=TRUE)]
      )
    head(dt, 3)
    #       ID      A      B      C      D
    #    <int> <char> <char> <char> <char>
    # 1:     1      f      u      f      q
    # 2:     5      f      v      f      t
    # 3:     1      b      s      t      a
    

    【讨论】:

    • GeneC,这是否符合您的“单线”期望?它适用于您的真实数据吗?
    • 这对我来说是单行的。将名称(.SD)传递给函数的巧妙技巧!这可能太迟钝而无法合并到可调试代码中,但很高兴看到它是如何完成的。
    • 太钝了?您认为很难将其包含在可调试代码中吗?我发现这比许多人(我在 SO 上看到的)倾向于做的事情更具可读性,lapply over indices 并在单个参数 anon-func 内部使用 [-indexing 而不是做这样的事情。
    • 绝对没有冒犯的意思,我喜欢你的解决方案。
    猜你喜欢
    • 2012-07-25
    • 1970-01-01
    • 1970-01-01
    • 2013-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-14
    相关资源
    最近更新 更多