【问题标题】:data.table: Create new character column based on indicator columns values and namesdata.table:根据指标列值和名称创建新的字符列
【发布时间】:2020-07-16 03:05:28
【问题描述】:

我有一个包含 1.6x10^8 记录的 data.table,我想根据值为 1 的指示符列名称创建一个新的字符列。

例如,

library(data.table)
DT <- data.table::data.table(ID=c("a","a","a","b","b"),
                             drugA=c(1,1,1,0,0),
                             drugB=c(0,1,1,1,0),
                             drugC=c(0,0,1,0,1))

   ID drugA drugB drugC
1:  a     1     0     0
2:  a     1     1     0
3:  a     1     1     1
4:  b     0     1     0
5:  b     0     0     1

### NOTE: I know the paste0(...,collapse) argument might be helpful in concatenating the drug names as an intermediate step
   ID drugA drugB drugC          exposure
1:  a     1     0     0             drugA
2:  a     1     1     0       drugA+drugB
3:  a     1     1     1 drugA+drugB+drugC
4:  b     0     1     0             drugB
5:  b     0     0     1             drugC

我希望它尽可能健壮,并且完全依赖 data.table 语法和/或其他有用的包/功能(例如 dcast);我不想创建一个广泛的用户定义函数,因为考虑到我的 data.table 大小,运行它需要很长时间。

我查看了其他帖子,但找不到与我的情况和所需输出相似的内容。

任何帮助将不胜感激。

【问题讨论】:

    标签: r data.table calculated-columns dcast


    【解决方案1】:
    library('data.table')
    DT[, id := .I]
    df <- melt(DT, id.vars = 'id', measure.vars = c("drugA", "drugB", "drugC"))
    df[value == 1, expose := 'exposure']
    df[value == 0, expose := 'no_exposure'][, value := NULL]
    df <- dcast(df, id ~ expose, fun.aggregate = function(x) paste0(x, collapse = "+"), value.var = 'variable')
    DT[df, on = 'id'][, id := NULL][]
    #    ID drugA drugB drugC          exposure no_exposure
    # 1:  a     1     0     0             drugA drugB+drugC
    # 2:  a     1     1     0       drugA+drugB       drugC
    # 3:  a     1     1     1 drugA+drugB+drugC            
    # 4:  b     0     1     0             drugB drugA+drugC
    # 5:  b     0     0     1             drugC drugA+drugB
    

    【讨论】:

      【解决方案2】:

      我们可以按行序列进行分组,将 .SDcols 指定为“药物”列,将 Data.table 的子集 (.SD) 转换为 logical,使用它来子集列名和paste他们在一起

      library(data.table)
      DT[,  exposure := paste(names(.SD)[as.logical(.SD)], collapse= '+'), 
             1:nrow(DT), .SDcols = drugA:drugC]
      DT
      #   ID drugA drugB drugC          exposure
      #1:  a     1     0     0             drugA
      #2:  a     1     1     0       drugA+drugB
      #3:  a     1     1     1 drugA+drugB+drugC
      #4:  b     0     1     0             drugB
      #5:  b     0     0     1             drugC
      

      或者不是按行分组,我们可以遍历列,将值更改为列名,然后将 pastedo.call 并删除 NAgsub 元素

      DT[, exposure := gsub("NA\\+|\\+NA", "", do.call(paste, 
         c(Map(function(x, y) names(.SD)[(NA^!x) * y], .SD, 
         seq_along(.SD)), sep="+"))), .SDcols = drugA:drugC]
      

      【讨论】:

      • @theneil 我添加了一个应该比第一个更快的选项
      • 您的第一篇代码发布耗时约 25 分钟,而您的第二篇代码发布耗时约 10 分钟。这是在 1.6x10^8 行数据上。谢谢
      猜你喜欢
      • 1970-01-01
      • 2020-01-29
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 2021-11-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多