【发布时间】:2016-10-27 07:47:13
【问题描述】:
我有一个如下所示的数据表列表:
group1 <- data.table(
group = rep(x = c("group1"), each = 16),
amount = rep(x = 7:4, each = 4),
subgr = rep(x = 1:2, each = 8),
ind = rep(x = 0:1, each = 4, times = 2)
)
group2 <- data.table(
group = rep(x = c("group2"), each = 36),
amount = rep(x = 13:8, each = 6),
subgr = rep(x = 1:3, each = 12),
ind = rep(x = 0:1, each = 6, times = 3)
)
mydt <- rbind(group1, group2)
mydt <- lapply(X = split(x = 1:nrow(mydt), f = mydt[["group"]]),
FUN = function(i)mydt[i])
上面显示的对象过于简单,实际列表包含越来越多的data.tables,每个在subgr 中分布的行数和subgr 本身的数量方面的结构略有不同。我想要实现的是:
- 在列表中的每个
data.table中创建多个列,该列等于subgr中唯一值的数量。每个新列都是amount的副本。复制的列数将等于subgr中唯一值的数量。 - 修改每个
subgr中新创建的列(如果ind == 1和amount*4如果ind ==0则说amount*4),使subgr中子组中的其余值不受影响。
也就是说,有这样的东西(这里只显示mydt$group1,但它适用于所有表格):
$group1
group amount subgr ind am1 am2
1: group1 7 1 0 28 7
2: group1 7 1 0 28 7
3: group1 7 1 0 28 7
4: group1 7 1 0 28 7
5: group1 6 1 1 12 6
6: group1 6 1 1 12 6
7: group1 6 1 1 12 6
8: group1 6 1 1 12 6
9: group1 5 2 0 5 20
10: group1 5 2 0 5 20
11: group1 5 2 0 5 20
12: group1 5 2 0 5 20
13: group1 4 2 1 4 8
14: group1 4 2 1 4 8
15: group1 4 2 1 4 8
16: group1 4 2 1 4 8
我知道将data.table 拆分为data.tables 列表不是一个好主意,正如this post 中所述,但对象就是这样。除此之外,拆分与我需要执行的任务有关:
- 数据表包含不同的行数。
- 行被分组为由
subgr定义的子组,并且它们的数量在不同的数据表中也不同,即新列的数量在整个列表中会有所不同。
也就是说,整个data.table 无法一次处理,因为group 变量中的每个组将创建不同数量的列。
到目前为止,我尝试的是使用this post 接受的答案中的第二种解决方案编写一个函数:
myfun <- function(data, quantity, region, index) {
data <- lapply(data, function(i) {
i[ , eval(paste0("am", unique(i[[region]]))) := i[[quantity]]]
})
data <- lapply(X = data, FUN = function(i) {
rep.names <- paste0("am", unique(i[[region]]))
i[ , eval(rep.names) := lapply(.SD, function(j) {
ifelse(i[["ind"]] == 1L, j*2L, j*4L)
}), by = region, .SDcols = rep.names]
})
return(data)
}
myfun(mydt, quantity = "amount", region = "subgr", index = "ind")
它没有按预期工作,它会根据条件修改所有变量中的整个值范围。但是,它会发出警告,指出问题所在。这里只是第一个警告,其他都一样:
Warning messages:
1: In `[.data.table`(i, , `:=`(eval(rep.names), lapply(.SD, ... :
RHS 1 is length 16 (greater than the size (8) of group 1). The last
8 element(s) will be discarded.
也就是说,它只使用 LHS 上必须使用的行,然后将整个列用于 RHS。显然我在这里遗漏了一些重要的东西。与 [this post][3] 中接受的答案的第二种解决方案的区别在于,有多个列可供使用,而在我的情况下只有一个 (amount)。
有人可以帮忙吗?
【问题讨论】:
-
从 data.table 1.9.7 开始,您可以使用
split(mydt, by="group")进行拆分。如果您有超过 ~1000 个唯一值subgr,您还应该在创建:=之前使用alloc.col。 -
@jangorecki:谢谢,这是有用的信息。版本 1.9.7 尚未发布,想了解更多有关此功能的信息。你能提供更多关于
alloc.col的细节吗? -
也许是
?alloc.col
标签: r data.table conditional subset multiple-columns