r - 使用 `data.table` 和 `c()` 进行汇总时可以防止因子强制吗?

标签 r data.table

我希望能够在 data.table 中同时使用汇总函数和标准表达式发现c()效果很好,但它将因子强制转换为整数表示形式。

data.table有没有简单的方法我可以使用命名列表摘要和带有因子值的摘要,并保留实际因子类而不将其转换为整数?

library(data.table)
library(lubridate)
data <- data.table(date = ymd("2019-07-07","2018-05-04",
                          "2019-08-09","2017-06-03"),
                   colour = factor(c("red","blue","green","yellow")),
           group = factor(c("A","B","A","B")),
           value1 = c(5,23,3,1),
           value2 = c(3,2,4,1))

summary_func <- function(x, var_name){
  setNames(list(mean(x),
       sd(x)), paste0(var_name,"_",c("mean","sd")))
}

data[,c(summary_func(value1,var_name = "val1"),
        summary_func(value2,var_name = "val2"),
        first_colour = colour[1]),
     by = group]

结果:

   group val1_mean   val1_sd val2_mean   val2_sd first_colour
1:     A         4  1.414214       3.5 0.7071068            3
2:     B        12 15.556349       1.5 0.7071068            1

我希望结果是:

   group val1_mean   val1_sd val2_mean   val2_sd first_colour
1:     A         4  1.414214       3.5 0.7071068        green
2:     B        12 15.556349       1.5 0.7071068          red

我在下面取得了一些成功,但这些解决方案非常不优雅,我怀疑不是很通用。因此,我希望有一个更简洁的data.table解决这个问题的方法。

我尝试过的事情:

  1. 我发现我可以通过使用 list() 来实现结果围绕列表摘要,并给它们一个非常具体的命名约定( "SF" )。然后,您需要将列排序为列表列和非列表列,然后使用 cbind , lapply ,和rbindlist将列表强制到 data.tables 中。然后,您必须重命名结果列。
tmp1 <- data[,.(first_colour = colour[1],
               SF1 = list(summary_func(value1, "val1")),
               SF2 = list(summary_func(value2, "val2"))),
    by = group]
list_cols <- names(which(sapply(tmp1,is.list)))
grp_cols <- names(tmp1)[!names(tmp1) %in% list_cols]

tmp2 <- tmp1[, do.call(cbind, 
                       c(lapply(mget(list_cols),rbindlist),
                         deparse.level = 0)), by = grp_cols]
setnames(tmp2, gsub("^SF\\d\\.", "", names(tmp2)))
tmp2
  • 我发现如果您创建 c() 的替代版本你可以获得所需的行为。您需要以特定方式解压参数以保留类型和名称。我认为相对于 c() 来说这可能会非常慢和list()因为这两个函数都是基元函数,因此基于编译的 C 代码。
  • c_alt <- function(...){
       blah <- list(...)
       result <- list()
       for(i in 1:length(blah)){
          len <- length(blah[[i]])
          for(j in 1:len){
             result[[length(result) + 1]] <- blah[[i]][[j]]
          }
          if(len > 1){
             names(result)[(length(result)-len):length(result)] <- names(blah[[i]])
          }else{
             names(result)[[length(result)]] <- names(blah)[[i]]
          }
       }
       result
    }
    
    data[,c_alt(summary_func(value1,var_name = "val1"),
            summary_func(value2,var_name = "val2"),
            first_colour = colour[1]),
         by = group]
    

    最佳答案

    一种方法是将颜色转换为字符,提取第一个值并在需要时再次使其因子

    library(data.table)
    
    data[,c(summary_func(value1,var_name = "val1"),
            summary_func(value2,var_name = "val2"),
            first_colour = as.character(colour[1])),
         by = group][, first_colour := factor(first_colour)][]
    
    #   group val1_mean   val1_sd val2_mean   val2_sd first_colour
    #1:     A         4  1.414214       3.5 0.7071068          red
    #2:     B        12 15.556349       1.5 0.7071068         blue
    

    关于r - 使用 `data.table` 和 `c()` 进行汇总时可以防止因子强制吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68451831/

    相关文章:

    r - 如何使用 tidyverse map 在 R 中迭代过滤并写入 csv

    r - 如何在数据框中找到单调序列

    r - 如何以 R "data.table"方式记录非重叠范围(或时间间隔)?

    删除每一列,但其中一些列在 data.table 中

    R并行编程foreach的疑惑

    r - 包含 data.table 名称的变量就地更改了吗?

    在 R 中读取二进制光栅文件

    r - 根据 data.table 中列值的优先级选择组中的行

    r - 使用包中的评估调用包装 data.table

    r - 查找两列最少的行