在 data.table 中分配多个 lapplys?

Posted

技术标签:

【中文标题】在 data.table 中分配多个 lapplys?【英文标题】:Assignment with multiple lapplys in data.table? 【发布时间】: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"
)

【问题讨论】:

【参考方案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 而不是做这样的事情。 绝对没有冒犯的意思,我喜欢你的解决方案。

以上是关于在 data.table 中分配多个 lapplys?的主要内容,如果未能解决你的问题,请参考以下文章

PHP:在if语句中分配多个变量

如何在 laravel spatie 中分配多个角色和基于多个角色的权限?

如何在一个表的键中分配多个值?

在单个代码行 C# 中分配多个变量

在Python中分配多个值时的奇怪问题[重复]

在一行中分配多个用逗号分隔的变量。 C#