为data.tables编写有效的函数,替换为引用

时间:2016-04-13 17:06:04

标签: r function replace data.table multiple-columns

我有一个data.table,它包含几个具有相同值的二进制列,我想在一次操作中重新编码。我修改了一个最初为data.frames编写的函数,但我不确定我是否真正利用data.table的速度和我修改它的方式:特别是我怀疑函数可能仍在复制值。 / p>

如何确保该函数通过引用替换值?

这是一个玩具数据集:

# Example data:
id <- c(1,2,3,4,5)
fruit <- c("apple", "orange", "banana", "strawbery", "rasberry")
mydate <- c("2015-09-01", "2015-09-02", "2015-11-15", "2016-02-24", "2016-03-08")
eaten <- c("y", "y", "n", "y", "u")
present <- c("n", "n", "y", "y", "y")

dt <- data.table(id, fruit, mydate, eaten, present)
dt[, mydate := as.Date(mydate, format = "%Y-%m-%d")]
dt[, sex := c("m", "f", "f", "m", "f")]

# Columns to update:
bincols <- c("eaten", "present")

在重新编码之前,数据如下所示:

> dt
   id     fruit     mydate eaten present sex
1:  1     apple 2015-09-01     y       n   m
2:  2    orange 2015-09-02     y       n   f
3:  3    banana 2015-11-15     n       y   f
4:  4 strawbery 2016-02-24     y       y   m
5:  5  rasberry 2016-03-08     u       y   f

这是功能:

recode.multi <- function(datacols, oldval, newval) {
  for (i in 1:length(datacols)) {
    datacols[datacols == oldval[i]] = newval[i]
  }
  datacols
}

...应用于数据:

dt[, (bincols) := lapply(.SD, recode.multi, oldval = c("u", "n", "y"), newval = c(NA_real_, 0, 1)), .SDcols = bincols]

...和输出,它根据需要更新值,但不确定它是否在此过程中复制列?

> dt
   id     fruit     mydate eaten present sex
1:  1     apple 2015-09-01     1       0   m
2:  2    orange 2015-09-02     1       0   f
3:  3    banana 2015-11-15     0       1   f
4:  4 strawbery 2016-02-24     1       1   m
5:  5  rasberry 2016-03-08    NA       1   f

我尝试更改最后一个&#39; =&#39;在函数中&#39;:=&#39;但是重新检查是否有数据库&#39;是一个data.table。在函数中添加一个子句来检查是否is.data.table == TRUE没有解决问题(返回相同的错误)。

对于大多数data.table关于此功能的适当方式的任何想法都将非常感激。

3 个答案:

答案 0 :(得分:2)

我愿意......

recodeDT = data.table(old = c("u", "n", "y"), new = c(NA_integer_, 0L, 1L), key = "old")

dt[, (bincols) := lapply(.SD, function(x) recodeDT[.(x), new]), .SDcols = bincols]

为了清晰起见,我认为最好将有限重新映射存储在表格中,但我不知道它是否更有效。如果您将变量存储为因子,则可以简单地调整级别,这应该非常快。您可以使用setattr(x, "levels", z),也许。

旁注:您可能希望将这些代码编码为整数而不是浮点数。

答案 1 :(得分:2)

这与Frank的相似,但是让参数传递给构建翻译向量并返回翻译的函数。您不需要在函数内部执行循环,因为ResourceHandlerlapply和.SDcols函数正在:=内进行循环。

[.data.table

请注意,您的列实际上不是因为您从其中一条评论中看到的因素。他们可能已经建立了一个data.frame作为中间步骤。

答案 2 :(得分:1)

为了确定我的原始解决方案是否正在复制值,我将我的Frank和42的解决方案应用于我的真实数据集,该数据集具有8933个观察值和150个列以使用该函数进行更新。以下git push的结果:

@Amy M:332.82秒

@Frank:0.15秒

@ 42(原创):4.13秒

@ 42(@ Frank&#39;修改):0.05秒

弗兰克和42的解决方案都比我快得多(所以我必须复制)。

我已经重印了以下最快的解决方案(42次改编为Frank&#39;)

system.time