我有一个data.table
我需要拆分成列表。这是一个示例数据集:
testSet <- data.table(A = 1:2, B = 4:5, C = rep(7:8, times = 50),
D = 9:10, E = 15:16, F = 24:25, G = 27:28,
H = 29:30, I = 32:33, J = 35:36, K = 1:50)
如您所见,它有11列,每列都是数字。我需要按10列中的值进行拆分,以便创建列表列表。我创建了以下功能代码(Macbook Air供参考):
system.time(testSetLists <- split(testSet,
list(testSet[["A"]], testSet[["B"]], testSet[["C"]],
testSet[["D"]], testSet[["E"]], testSet[["F"]],
testSet[["G"]], testSet[["H"]], testSet[["I"]],
testSet[["J"]])))
> user system elapsed
0.759 0.109 0.731
这非常有效,并且完全符合我需要的输出。但是,当我在一列中增加数字范围时,例如在以下数据集中的A
中:
testSet <- data.table(A = 1:5, B = 4:5, C = rep(7:8, times = 50),
D = 9:10, E = 15:16, F = 24:25, G = 27:28,
H = 29:30, I = 32:33, J = 35:36, K = 1:50)
system.time(testSetLists <- split(testSet,
list(testSet[["A"]], testSet[["B"]], testSet[["C"]],
testSet[["D"]], testSet[["E"]], testSet[["F"]],
testSet[["G"]], testSet[["H"]], testSet[["I"]],
testSet[["J"]])))
> user system elapsed
2.139 0.301 2.054
通过向A
添加3个值,您可以看到执行的时间是处理时间的三倍。现在,当我向B
,D
和J
添加更多值时会发生什么?
testSet <- data.table(A = 1:5, B = 4:9, C = rep(7:8, times = 50),
D = 9:14, E = 15:16, F = 24:25, G = 27:28,
H = 29:30, I = 32:33, J = 35:56, K = 1:50)
system.time(testSetLists <- split(testSet,
list(testSet[["A"]], testSet[["B"]], testSet[["C"]],
testSet[["D"]], testSet[["E"]], testSet[["F"]],
testSet[["G"]], testSet[["H"]], testSet[["I"]],
testSet[["J"]])))
> user system elapsed
179.356 21.311 176.562
正如您所看到的,当每列中有100个左右的唯一数据点时,此解决方案是站不住脚的。
我可以使用此功能删除所有空列表:
testSetLists <- testSetLists[sapply(testSetLists, function(x) dim(x)[1]) > 0]
我的问题是:如何在没有极高CPU时间的情况下获取相同的输入并获得相同的输出? R中的任何选项都在桌面上。
答案 0 :(得分:5)
由于split
试图确定所提供因素的每个组合,因此计算花费的时间过长。但是,可以设置drop=TRUE
参数,因此只保留具有元素的组合。在你的最后一个数据集上,在我的电脑上:
system.time(testSetLists <- split(testSet,testSet[,.SD,.SDcols=names(testSet)[1:10]]))
# user system elapsed
#128.111 0.343 128.930
system.time(testSetLists <- split(testSet,testSet[,.SD,.SDcols=names(testSet)[1:10]],drop=TRUE))
# user system elapsed
# 0.048 0.000 0.048
还要注意我是如何选择指示拆分的列,而不是当时手动编写一列。
答案 1 :(得分:2)
最近data.table获取了自己的split
方法。它可以接受要拆分的列名称。没有必要将完整列传递给f
参数,就像data.frame一样。与split.data.frame
不同,它还可以保留分组顺序。
library(data.table)
suppressWarnings( # OP data raises recycling warning
testSet <- data.table(A = 1:5, B = 4:9, C = rep(7:8, times = 50),
D = 9:14, E = 15:16, F = 24:25, G = 27:28,
H = 29:30, I = 32:33, J = 35:56, K = 1:50)
)
system.time(dropF <- split(testSet, testSet[,.SD,.SDcols=names(testSet)[1:10]]))
# user system elapsed
#371.684 4.032 115.058
system.time(dropT <- split(testSet, testSet[,.SD,.SDcols=names(testSet)[1:10]], drop=TRUE))
# user system elapsed
# 0.304 0.004 0.097
system.time(byDropT <- split(testSet, by=names(testSet)[1:10], drop=TRUE, sorted=TRUE))
# user system elapsed
# 0.180 0.000 0.061
all.equal(
dropT[sort(names(dropT))],
byDropT
)
#[1] TRUE
要安装1.9.7版本,请使用:
install.packages("data.table", type = "source", repos = "https://Rdatatable.github.io/data.table")