我有一个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关于此功能的适当方式的任何想法都将非常感激。
答案 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的相似,但是让参数传递给构建翻译向量并返回翻译的函数。您不需要在函数内部执行循环,因为ResourceHandler
,lapply
和.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