【问题标题】:dynamic column names seem to work when := is used but not when = is used in data.table [duplicate]动态列名似乎在使用 := 时有效,但在 data.table 中使用 = 时无效 [重复]
【发布时间】:2019-06-20 12:21:27
【问题描述】:

使用这个虚拟数据集

setDT(mtcars_copy<-copy(mtcars))
new_col<- "sum_carb" # for dynamic column referencing

为什么案例 1 有效,但案例 2 无效?

# Case 1 - Works fine
mtcars_copy[,eval(new_col):=sum(carb)] # Works fine


# Case 2:Doesnt work
aggregate_mtcars<-mtcars_copy[,(eval(new_col)=sum(carb))] # error
aggregate_mtcars<-mtcars_copy[,eval(new_col)=sum(carb))] # error
aggregate_mtcars<-mtcars_copy[,c(eval(new_col)=sum(carb))] # Error

如何让Case 2 工作,其中我不希望主表(在这种情况下为mtcars_copy 保存新列)但要将结果存储在单独的聚合表中(aggregate_mtcars

【问题讨论】:

  • 您希望新列重复相同的总和吗?或者您打算在data.table 中按组汇总?

标签: r data.table eval dynamic-columns


【解决方案1】:

一种选择是使用基本 R 函数setNames

aggregate_mtcars <- mtcars_copy[, setNames(.(sum(carb)), new_col)]

或者你可以使用data.table::setnames

aggregate_mtcars <- setnames(mtcars_copy[, .(sum(carb))], new_col)

【讨论】:

  • 是的,但我想知道是否可以避免重命名/设置名称选项。我原来的问题比较复杂,setnames 只会让它变得非常混乱
  • @ashleych 通常,不幸的是,您不能像 R 中的make_name(x,y) = z 那样动态分配/命名。在带有:= 的data.table DT[...] 中只是包设计者实施的该规则的一个例外。
  • 看起来这确实是最有效的方法,那么。
【解决方案2】:

我认为你想要的是在做案例 1 时简单地制作一个副本。

aggregate_mtcars <- copy(mtcars_copy)[, eval(new_col) := sum(carb)]

这会将mtcars_copy 保留为新aggregate_metcars 的单独数据集,但不包含新列。

【讨论】:

    【解决方案3】:

    原因是因为案例 2 使用data.frame 方式在数据框中创建列(作为新列表)。 data.table 中有隐藏参数:with 处理对象返回的方式。可以是data.table,也可以是vector。

    ?data.table :
    默认情况下 with=TRUE 并且 j 在 x 的框架内进行评估;列名可以用作变量。如果数据集中和父范围内的变量名称重叠,您可以使用双点前缀 ..cols 显式引用 'cols 变量父范围,而不是来自您的数据集。

    当 j 是列名的字符向量时,要选择的列位置的数字向量或 startcol:endcol 的形式,并且返回的值始终是 data.table。 with=FALSE 不再需要动态选择列。请注意,x[, cols] 等价于 x[, ..cols] 和 x[, cols, with=FALSE] 和 x[, .SD, .SDcols=cols]。

    # Case 2 :
    aggregate_mtcars<-mtcars_copy[,(get(new_col)=sum(carb))] # error
    aggregate_mtcars<-mtcars_copy[,eval(new_col)=sum(carb))] # error
    aggregate_mtcars<-mtcars_copy[,c(eval(new_col)=sum(carb))] # Error
    
    mtcars_copy[, new_col, with = FALSE ] # gives a data.table
    mtcars_copy[, eval(new_col), with = FALSE ] # this works and create a data.table
    mtcars_copy[, eval(new_col), with = TRUE ] # the default that is used here with error
    mtcars_copy[, get(new_col), with = TRUE ] # works and gives a vector
    
    # Case 2 solution : affecting values the data.frame way
    mtcars_copy[, eval(new_col) ] <- sum(mtcars_copy$carb) # or any vector
    mtcars_copy[[eval(new_col)]] <- sum(mtcars_copy$carb) # or any vector
    

    【讨论】:

      猜你喜欢
      • 2021-08-15
      • 2014-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多