动态地将变量传递给data.table

时间:2016-11-18 17:49:02

标签: r data.table

SO #24833247几乎涵盖了将列名动态传递给函数中的data.table的所有用例。但是它错过了我目前试图解决的问题:将变量传递给i表达式。

我试图将一些数据清理代码重构为一个函数,在我将数据提取到NA

之后将某些值转换为data.table

例如,给出以下内容:

dt <- data.table(colA = c('A', 'b', '~', 'd', ''), colB = c('', '?', 'a1', 'a2', 'z4'))
dt[colA %in% c('~', ''), colA := NA]
dt[colB %in% c('~', ''), colB := NA]

我想要一个泛型函数,用'~'替换'?'''NA值,而不必显式编码每个转换。

dt <- data.table(colA = c('A', 'b', '~', 'd', ''), colB = c('', '?', 'a1', 'a2', 'z4'))
clearCol(dt, colA)
clearCol(dt, colB)

j表达式是直截了当的

clearCol <- function(dt, f) {
  f = substitute(f)
  dt[,(f) := NA]
}
clearCol(data.table(colA = c('A', 'b', '~', 'd', '',)), colA)[]
    x
1: NA
2: NA
3: NA
4: NA
5: NA

但是,扩展它以将变量添加到i表达式失败:

clearCol <- function(dt, f) {
  f = substitute(f)
  dt[(f) %in% c('~', ''),(f) := NA]
}
clearCol(data.table(colA = c('A', 'b', '~', 'd', '')), colA)[]
 Error in match(x, table, nomatch = 0L) : 'match' requires vector arguments

交换到这似乎有效,但是verbose = TRUE缺少输出(与顶部的硬编码方法相比)让我担心在给定大数据集I&#时它不能很好地扩展39;正在与

合作
clearCol <- function(dt, f) {
  f = deparse(substitute(f))
  dt[get(f) %in% c('~', ''),(f) := NA]
}
clearCol(data.table(colA = c('A', 'b', '~', 'd', '')), colA)[]
   colA
1:    A
2:    b
3:   NA
4:    d
5:   NA

还有另一种做我想做的事吗?

1 个答案:

答案 0 :(得分:1)

您可以follow FAQ 1.6获取详细输出:

cc = function(d, col, vs = c("~", ""), verb = FALSE){
  col = substitute(col)
  ix  = substitute(col %in% vs)
  d[eval(ix), as.character(col) := NA, verbose = verb ][]
}

dt <- data.table(colA = c('A', 'b', '~', 'd', ''), colB = c('', '?', 'a1', 'a2', 'z4'))
cc(dt, colA, verb = TRUE)

给出了

Creating new index 'colA'
Starting bmerge ...done in 0 secs
Detected that j uses these columns: <none> 
Assigning to 2 row subset of 5 rows
Dropping index 'colA' due to update on 'colA' (column 1)
   colA colB
1:    A     
2:    b    ?
3:   NA   a1
4:    d   a2
5:   NA   z4

但是,请注意详细输出在这里说的内容。它正在创建一个索引(假设你没有做某事来创建它,这似乎很可能,因为数据只是刚读入)...然后它正在删除该索引(因为它被列的编辑无效) 。这几乎听起来不像是有助于提高效率的东西。

如果你真的想有效地做到这一点,有几个选择:

  1. 中阅读数据时使用na.strings
  2. 如果您有大量列,并且某种程度上无法执行#1
  3. ,请使用set