我有一个data.table,我想拆分成一个列表然后修改。当我在调用split后尝试删除列表中某个data.tables上的列时,我发现了一些奇怪的行为。这是一个MWE(抛出错误并导致我的R会话崩溃):
library(data.table)
d = data.table(level = c(1, 1, 2, 2), value = 1:4)
list = split(d, f = d$level)
list[[1]][, level := NULL]
list
我明白了:
Error in .shallow(x, cols = cols, retain.key = TRUE) : Internal error: length(names)>0 but <length(dt)
答案 0 :(得分:2)
我建议使用l
名称作为变量,而不是list
这似乎是由进程中使用的split.data.frame方法引起的错误
我最近提出了一个新的split.data.table方法,定义如下。它似乎解决了你的问题。
更新2016-03-30:
split.data.table
已在data.table 1.9.7中实现。现在使用可以简单地使用:
library(data.table)
d = data.table(level = c(1, 1, 2, 2), value = 1:4)
l = split(d, by = "level")
l[[1L]][, level := NULL]
l
#$`1`
# value
#1: 1
#2: 2
#
#$`2`
# level value
#1: 2 3
#2: 2 4
下面的旧答案,如果你坚持使用1.9.6或更低版本可能会有用。请注意,它不会像split.data.frame
那样处理因子级别,而在data.table 1.9.7中开发的方法不是这种情况,这与data.frame方法一致。
library(data.table)
split.data.table = function(x, f, drop = FALSE, by, flatten = FALSE, ...){
if(missing(by) && !missing(f)) by = f
stopifnot(!missing(by), is.character(by), is.logical(drop), is.logical(flatten), !".ll" %in% names(x), by %in% names(x))
if(!flatten){
.by = by[1L]
tmp = x[, list(.ll=list(.SD)), by = .by, .SDcols = if(drop) setdiff(names(x), .by) else names(x)]
setattr(ll <- tmp$.ll, "names", tmp[[.by]])
if(length(by) > 1L) return(lapply(ll, split.data.table, drop = drop, by = by[-1L])) else return(ll)
} else {
tmp = x[, list(.ll=list(.SD)), by=by, .SDcols = if(drop) setdiff(names(x), by) else names(x)]
setattr(ll <- tmp$.ll, 'names', tmp[, .(nm = paste(.SD, collapse = ".")), by = by, .SDcols = by]$nm)
return(ll)
}
}
d = data.table(level = c(1, 1, 2, 2), value = 1:4)
l = split.data.table(d, by = "level")
# below setattr to be addressed in split.data.table
invisible(lapply(l, setattr, ".data.table.locked", NULL))
l[[1]][, level := NULL]
l
#$`1`
# value
#1: 1
#2: 2
#
#$`2`
# level value
#1: 2 3
#2: 2 4
我还填写了一份描述您案例的错误报告,您可以在data.table#1481找到它。