如何有效地将订单变量添加到大数据框中

时间:2014-03-14 13:20:38

标签: r performance split

我有一个类似于以下的数据框,但有55.000个观察结果和大约50.000个组:

d <- structure(list(a = structure(c(1L, 1L, 1L, 2L, 2L, 3L, 3L), .Label = c("A", 
"B", "C"), class = "factor"), b = c(1, 1, 2, 1, 2, 1, 2)), .Names = c("a", 
"b"), row.names = c(1L, 3L, 2L, 4L, 5L, 6L, 7L), class = "data.frame")

在此数据框中,每个组再次根据变量“b”进行排序。我现在想根据分组变量“a”分割数据帧,并添加一个向量,指示每个子数据帧的每个元素的排序号。所以结果应该是这样的:

structure(list(a = structure(c(1L, 1L, 1L, 2L, 2L, 3L, 3L), .Label = c("A", 
"B", "C"), class = "factor"), b = c(1, 2, 1, 1, 2, 1, 2), order = c(1, 
2, 3, 1, 2, 1, 2)), .Names = c("a", "b", "order"), row.names = c("1", 
"2", "3", "4", "5", "6", "7"), class = "data.frame")

我能够通过split()函数得到这个结果,这个测试数据框上有一个我自己的gmark()函数(gmark()假设输入已经排序):

gmark <- function(input){
  x = 0
  result = vector()
  for(i in input){
    x <- x+1
    result <- append(result, x)
  }
  result
}

x <- split(d, d$a)
x <- lapply(x, function(x){cbind(x, order = gmark(x$b))})
x <- unsplit(x, a)

然而,一旦我将此应用于更大的数据框,split()变得非常慢并且不会返回。有没有办法更有效地在更大的数据框架上得到这个结果?

2 个答案:

答案 0 :(得分:2)

以下是data.table包的解决方案。这会快得多。

require(data.table)
DT <- as.data.table(DF)
DT[, order := 1:.N, by=a]
> DT
   a b order
1: A 1     1
2: A 2     2
3: A 1     3
4: B 1     1
5: B 2     2
6: C 1     1
7: C 2     2

:=是一个data.table运算符,它通过引用添加列(意味着不会创建数据副本)。 .N是一个特殊的变量,包含每个组的长度(这里,它将保持3,2,2对应于A,B,C)。

答案 1 :(得分:1)

您的代码无法完全运行。试试这个(倒数第二行有所不同):

d <- data.frame(
    a = sample(LETTERS[1:5],5e4,replace=TRUE),
    b = sample(letters[1:10],5e4,replace=TRUE)) 
x <- split(d,d$a)
y <- lapply(x, function(x){cbind(x, order = 1:nrow(x))})
z <- unsplit(y,d$a)