将函数应用于data.table或data.frame中的多对列的最优雅方法是什么?

我经常需要对宽格式的 data.table 或 data.frame 中的一对列应用一些函数或操作。例如,计算患者治疗前后的体重差异。

通常,有多对列需要应用相同的操作。例如,计算患者在治疗前后的体重、bmi、血压、白细胞计数等之间的差异。

在 R 中执行此操作的最简单的方法是什么,尤其是在使用 data.table 包时?我发现以下解决方案可行,但是当变量名称不遵循完美模式时,它们会在现实世界中产生开销。

考虑以下最小的工作示例。目标是计算 a.1 和 a.2、b.1 和 b.2、c.1 和 c.2 的差异,并将它们命名为 a.3、b.3、c.3。我特别不喜欢的是最后必须“手动”重命名列。

library(data.table)

prefixes <- c("a", "b", "c")

one.cols <- paste0(prefixes, ".1")
two.cols <- paste0(prefixes, ".2")
result.cols <- paste0(prefixes, ".3")

# Data usually read from file
DT <- data.table(id = LETTERS[1:5],
                 a.1 = 1:5,
                 b.1 = 11:15,
                 c.1 = 21:25,
                 a.2 = 6:10,
                 b.2 = 16:20,
                 c.2 = 26:30)

DT.res <- cbind(DT[,.(id)], 
      result = DT[,..one.cols] - DT[,..two.cols] 
      )

old <- grep(pattern = "result.*", x = colnames(DT.res), value = T)

setnames(DT.res, old = old, new = result.cols)

DT <- DT[DT.res, on = "id"]

# Gives desired result:
print(DT)
#    id a.1 b.1 c.1 a.2 b.2 c.2 a.3 b.3 c.3
# 1:  A   1  11  21   6  16  26  -5  -5  -5
# 2:  B   2  12  22   7  17  27  -5  -5  -5
# 3:  C   3  13  23   8  18  28  -5  -5  -5
# 4:  D   4  14  24   9  19  29  -5  -5  -5
# 5:  E   5  15  25  10  20  30  -5  -5  -5

DT <- data.table(id = LETTERS[1:5],
                 a.1 = 1:5,
                 b.1 = 11:15,
                 c.1 = 21:25,
                 a.2 = 6:10,
                 b.2 = 16:20,
                 c.2 = 26:30)

DT.reshaped <- reshape(DT, direction = "long",
        varying = mapply(FUN = "c", one.cols, two.cols, SIMPLIFY = F)
)

DT.reshaped <- 
  DT.reshaped[, lapply(.SD, 
                       function(x){ x[1] - x[2] }), 
              keyby = .(id), .SDcols = one.cols]

setnames(DT.reshaped, old = one.cols, new = result.cols)

DT <- DT[DT.reshaped, on = "id"]

# Gives desired result, too:    
print(DT)

 

我更愿意编写如下内容,以获得相同的结果:

DT[, (result.cols) := ..one.cols - ..two.cols]

有没有办法做这样的事情?

回答

1) gv在折叠包中使用 gv 我们可以这样做:

library(collapse)

DT[, (result.cols) := gv(.SD, one.cols) - gv(.SD, two.cols)]

2) gvr我们可以交替使用 gv 的正则表达式变体来消除 one.cols 和 two.cols:

library(collapse)

result.cols <- sub(1, 3, gvr(DT, "1$", "names"))
DT[, (result.cols) := gvr(.SD, "1$") - gvr(.SD, "2$")]

3) cross 使用 dplyr 我们也可以使用 cross 消除 result.cols。

library(dplyr)

DT %>%
  mutate(across(ends_with("1"), .names="{sub(1,3,.col)}") - across(ends_with("2")))

4) data.table如果我们这样写它在data.table中很简单:

DT[, result.cols] <- DT[, ..one.cols] - DT[, ..two.cols]

或者

DT[, (result.cols) := .SD[, one.cols, with=FALSE] - .SD[, two.cols, with=FALSE]]


以上是将函数应用于data.table或data.frame中的多对列的最优雅方法是什么?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>