【问题标题】:naming a list when returning values from data.table从 data.table 返回值时命名列表
【发布时间】:2013-05-14 19:41:36
【问题描述】:

当将项目返回到data.table 时,如果它们自动采用变量的名称会很好。如何做到这一点?这就是我的意思:

require(data.table)
x = data.table(a=1:10, id=1:2)
x[,{s = sum(a); p=prod(a); y = sqrt(abs(s*p)); z = y+1; list(y, z)},by=id]

#   id V1   V2
#1:  1 25  945
#2:  2 30 3840

如果将列标记为sp,而不是V1V2,那就太好了。在这里做这件事没什么大不了的,但是如果你有 20 列,那就真的很痛苦了。关于如何做到这一点的任何想法?

编辑:我更改了问题以明确为什么我不只是做 list(name = value)

【问题讨论】:

  • 哦,看来是相关的。我猜FR仍然开放?有没有办法在 R 中更简洁地执行此操作,然后执行list(x=x, y=y, z=z)。我知道这不是 data.table 的事情,但是在 R 中生成这个表达式而不是手动生成这个表达式的最快方法是什么?
  • Hrm,看起来@GSee 用link 删除了该评论。反正我也很好奇这个。
  • 是的,我删除了评论,因为我认为这是一个不同的功能请求。
  • 正如@Justin 和其他人所提到的,解决方案只是命名列表的元素。这是base R 的东西,与data.table 没什么关系。话虽如此,我当然可以看到自动化名称的好处。但是,我发现了很多陷阱和极端情况。一个可靠的解决方案是什么样的?可靠我的意思是“在所有情况下都可以预测”。目前,可以实现DT[, list(mean(x), sd(x))]$V1 并确定这将返回mean(x)。如果存在极端情况,则会牺牲确定性。
  • @RicardoSaporta 是的,所以也许有这样的选择,dt[,list(...),makeNames=TRUE]

标签: r list data.table named columnname


【解决方案1】:

如果我遗漏了一些东西,请原谅我...但您正在寻找的不是 data.table 的标准 list 语法吗?恕我直言,它更简洁明了。

x[, 
  list(s = sum(a),
       p = prod(a)),
  by=id] 

#    id  s    p
# 1:  1 25  945
# 2:  2 30 3840

您也可以将此list 构建为expressioneval

foo <- expression(list(s=sum(a), p=prod(a)))

x[, eval(foo), by=id]

然后可以将其扩展为一个函数(使用 plyr 中的 as.quoted 代替它很方便):

expression_maker <- function(funs, cols, names) {
   require(plyr)
   list_contents <- paste0(names, '=', funs, '(', cols, ')', collapse=',')
   as.quoted(paste('list(', list_contents, ')'))[[1]]
}

output <- expression_maker(funs=c('sum', 'prod'), cols=c('a', 'a'), names=c('s', 'p'))
x[, eval(output), by=id]

...但是有龙!


每个 OP 的编辑:

x[,{s = sum(a); p=prod(a); y = sqrt(abs(s*p)); z = y+1; list(y, z)},by=id]

我会在函数中执行此操作并直接返回data.table

yourfun <- function(a) {
  s <- sum(a)
  p <- prod(a)
  y <- sqrt(abs(s*p))
  z <- y+1
  data.table(y, z)
}

x[, yourfun(a), by=id]

【讨论】:

  • 如果它们从同一来源获取信息,例如x[,{mylm&lt;-lm(a~id);data.frame(mylm$fitted.values,mylm$residuals)}],则将它们放在单独的列表项中可能效率低下。也许这有点做作,但我认为有用途。
  • @Justin:这只是一个非常简单的例子。在我的真实代码中,我有一个复杂的表达式被评估,它采用中间值。最后我返回一个最终结果。
  • 仍然不确定我是否跟随。如果您正在寻找最少的字符,我的列表版本会丢失几个等号。如果您正在运行复杂的函数和事物,为什么不采取setnames 的简单步骤,或者更改您的函数以返回命名的 data.tables 本身? @Alex 查看我的编辑
【解决方案2】:

其他两个答案的混合 - 在列表中命名它们:

x[,{s = sum(a); p=prod(a); y = sqrt(abs(s*p)); z = y+1;
    list(s = y, p = z)}, by=id]

或者构造一个data.table

x[,{s = sum(a); p=prod(a); y = sqrt(abs(s*p)); z = y+1;
    data.table(y, z)}, by=id]

这是使用Hmisc 的另一个选项(这比手动命名要慢,但可能比data.table 快):

library(Hmisc)
x[,{s = sum(a); p=prod(a); y = sqrt(abs(s*p)); z = y+1;
    llist(y, z)}, by=id]

【讨论】:

    【解决方案3】:

    如果您有大量的变量并且您正在寻找一种编程方式来解决这个问题,您可以将列的名称放在一个向量中,然后使用 sapply.SDcols 例如:

    ## sample data
    set.seed(7)
    DT <- as.data.table(matrix(round(runif(130, 1, 100)), ncol=26))
    setnames(DT, LETTERS)
    
    
    ## These are the columns we will compute on
    Cols <- c("A", "G", "M", "W", "Z")
    
    DT[,sapply(.SD,mean),.SDcols=Cols]
    
    #    A    G    M    W    Z 
    # 25.0 41.2 55.6 43.0 56.0     
    

    如果你想对每个变量计算不同的函数,那么使用标准的list(nm=function(x))

    【讨论】:

    • 我猜你的意思是DT[,sapply(.SD,mean),.SDcols=Cols]?无论如何,这就是我在 SO 上看到的很多内容。
    • 哦,这个结果不再是data.table,这就是命名成功的原因,对吧?
    • 混乱修复:DT[,c(mean=as.list(sapply(.SD,mean))),.SDcols=Cols]。 @下方评论:哦,对了。
    • 这不是必需的。只需改用lapply
    猜你喜欢
    • 2021-04-19
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-15
    • 1970-01-01
    相关资源
    最近更新 更多