【问题标题】:Avoid overwriting existing columns in data.table functions避免覆盖 data.table 函数中的现有列
【发布时间】:2020-01-22 14:25:13
【问题描述】:

我正在编写一个以 data.table 作为参数的函数。 data.table 的列名部分指定为参数,但并非所有列名都指定,所有原始列都需要维护。在函数内部,需要将一些列添加到 data.table 中。即使在函数内部复制了 data.table,我也想以一种保证不会覆盖现有列的方式添加这些列。鉴于列名未知,确保我不会覆盖列的最佳方法是什么?

这是一种方法:

#x is a data.table and knownvar is a column name of that data.table
f <- function(x,knownvar){
x <- copy(x)
tempcol <- "z"
while(tempcol %in% names(x))
tempcol <- paste0("i.",tempcol)

tempcol2 <- "q"
while(tempcol2 %in% names(x))
tempcol2 <- paste0("i.",tempcol2)

x[, (tempcol):=3] 
eval(parse(text=paste0("x[,(tempcol2):=",tempcol,"+4]"))) 
x
}

请注意,即使我在这里复制 x,我仍然需要此过程以提高内存效率。有没有更简单的方法来做到这一点?可能不使用eval(parse(text=

显然我可以在函数环境中创建一个局部变量(例如向量)(而不是将其显式添加为 data.table 的列),但如果我需要排序/加入数据表。另外,我可能想显式返回一个包含原始变量和新列的 data.table。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    这是使用set 编写函数和使用substitute() + eval() 进行非标准评估的一种方法。

    注意1:如果根据newcols中的列名(而不是knownvar中的列名)创建新列,则newcols中的字符名将转换为符号与as.name()(或等效as.symbol())。

    注意2newvals 中的新列只能以合理的顺序添加,即如果列q 需要列z,则应在列@ 之前添加列z 987654332@.

    library(data.table)
    
    f <- function(x, knownvar) {
    
      ## remove if x should be modified in-place
      x <- copy(x)
    
      ## new column names
      newcols <- setdiff(make.unique(c(names(x), c("z", "q"))), names(x))
    
      ## new column values based on knownvar or new column names
      zcol <- as.name(newcols[1])
      newvals <- list(substitute(3 * knownvar), substitute(zcol + 4))
    
      for(i in seq_along(newvals)) {
        set(x, j = newcols[i], value = eval(newvals[[i]], envir = x))
      } 
    
      return(x)
    
    }
    
    ## example data
    x <- as.data.table(mtcars)
    x[, c("q", "q.1") := .(mpg, 2 * mpg)]
    
    head(f(x, mpg))
    #>     mpg cyl disp  hp drat    wt  qsec vs am gear carb    q  q.1    z  q.2
    #> 1: 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4 21.0 42.0 63.0 67.0
    #> 2: 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4 21.0 42.0 63.0 67.0
    #> 3: 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1 22.8 45.6 68.4 72.4
    #> 4: 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1 21.4 42.8 64.2 68.2
    #> 5: 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2 18.7 37.4 56.1 60.1
    #> 6: 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1 18.1 36.2 54.3 58.3
    

    【讨论】:

    • 如果 x 包含名为“q”和“i.q”的列,这不会中断吗?
    • @Micheal:你是对的,请查看编辑后的回复(虽然可能是一种更简洁的方式)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-04
    • 1970-01-01
    • 1970-01-01
    • 2013-06-02
    • 2021-04-28
    • 2014-06-02
    • 2022-01-22
    相关资源
    最近更新 更多