在R中进行子集化的最快方法

时间:2015-04-30 18:56:01

标签: r

我有一个名为main的数据框,有400,000行,我希望将其子集化以检索1行或更多行。

这里的示例是一个数据框,显示了我使用subset函数的子集类型:

main <- data.frame(date = as.POSIXct(c("2015-01-01 07:44:00 GMT","2015-02-02 09:46:00 GMT")),
                   name= c("bob","george"),
                   value=c(1,522), 
                   id= c(5,2))

subset(main, date == "2015-01-01 07:44:00" & name == "bob" & value == 1)

这有效,但速度很慢,我认为这是因为我正在使用400k行数据帧。有关如何更快地进行子集化的任何想法吗?

1 个答案:

答案 0 :(得分:3)

我建议使用键控data.table。以下是如何进行设置(对于修改示例):

require(data.table)
mainDT <- data.table(main)
setkey(mainDT,V1,V2,V3)

我们现在可以使用类似

的语法基于相等条件进行子集化
mainDT[J("a","A")]

mainDT[J(c("a","b"),"A",1)]

哪个子集设置为V1 %in% c("a","b")(相当于V1=="a"|V1=="b")。

这是速度比较:

require(rbenchmark)
benchmark(
  "["       = main[main$V1=="a" & main$V2=="A",],
  "subset"  = subset(main,V1=="a" & V2=="A"),
  "DT[J()]" = mainDT[J("a","A")],
  replications=5
)[,1:6]

在我的电脑上提供这些结果:

     test replications elapsed relative user.self sys.self
1       [            5    5.96       NA      5.38     0.57
3 DT[J()]            5    0.00       NA      0.00     0.00
2  subset            5    6.93       NA      6.20     0.72

因此,使用J进行子集化是即时的,而其他两种方法需要几秒钟。但是,以这种方式使用J进行子集是有限的:

  • 仅适用于平等条件。
  • 对于上面的简单语法,您需要按键的顺序传递参数。但是,您可以使用V1=="a" & V3 == 2选择mainDT[J("a",unique(V2),2)]的位置,但仍然非常快。

您可以使用data.frame完成对data.frame的所有操作。例如,subset(mainDT,V1=="a" & V2=="A")仍然有效。因此,通常将data.frames切换到data.tables没有任何损失。您可以使用setDT(main)转换为data.table。

以下是示例的代码:

n  = 1e7
n3 = 1e3

set.seed(1)
main <- data.frame(
  V1=sample(letters,n,replace=TRUE),
  V2=sample(c(letters,LETTERS),n,replace=TRUE),
  V3=sample(1:n3,n,replace=TRUE),
  V4=rnorm(n))

上述基准测试中的改进会因您的数据而异。当您有许多观察值(n)或密钥的几个唯一值(例如n3)时,使用键控data.table进行子集化的好处应该更大。