7

我有这个data.frame:

df <- data.frame(id=c('A','A','B','B','B','C'), amount=c(45,66,99,34,71,22))

id | amount 
-----------
A  |   45   
A  |   66   
B  |   99
B  |   34 
B  |   71
C  |   22

我需要扩展它,以便bydata.frame 中的每个组的长度相同(用零填充),如下所示:

id | amount 
-----------
A  |   45   
A  |   66  
A  |   0     <- added 
B  |   99
B  |   34 
B  |   71
C  |   22
C  |   0     <- added 
C  |   0     <- added 

这样做最有效的方法是什么?

笔记

对我得到的实际100 万行 data.frame提供的一些解决方案进行基准测试:

             plyr   | data.table  |  unstack
          -----------------------------------
Elapsed:   139.87s  |    0.09s    |   2.00s
4

4 回答 4

4

我确定有一个基本的 R 解决方案,但这是一个在包中使用ddply的解决plyr方案

library(plyr)
##N: How many values should be in each group
N = 3
ddply(df, "id", summarize, 
      amount = c(amount, rep(0, N-length(amount))))

给出:

  id amount
1  A     45
2  A     66
3  A      0
4  B     99
5  B     34
6  B     71
7  C     22
8  C      0
9  C      0
于 2013-01-31T09:06:00.547 回答
4

一种使用方式data.table

df <- structure(list(V1 = structure(c(1L, 1L, 2L, 2L, 2L, 3L), 
          .Label = c("A  ", "B  ", "C  "), class = "factor"), 
          V2 = c(45, 66, 99, 34, 71, 22)), 
          .Names = c("V1", "V2"), 
          class = "data.frame", row.names = c(NA, -6L))

require(data.table)
dt <- data.table(df, key="V1")

# get maximum index
idx <- max(dt[, .N, by=V1]$N)

# get final result
dt[, list(V2 = c(V2, rep(0, idx-length(V2)))), by=V1]

#     V1 V2
# 1: A   45
# 2: A   66
# 3: A    0
# 4: B   99
# 5: B   34
# 6: B   71
# 7: C   22
# 8: C    0
# 9: C    0
于 2013-01-31T09:07:35.880 回答
3

这是在基础 R 中使用unstackand的另一种方式stack

# ensure character id col
df <- transform(df, id=as.character(id))
# break into a list by id
u <- unstack(df, amount ~ id)
# get max length
max.len <- max(sapply(u, length))
# pad the short ones with 0s
filled <- lapply(u, function(x) c(x, numeric(max.len - length(x))))
# recombine into data.frame
stack(filled)

#   values ind
# 1     45   A
# 2     66   A
# 3      0   A
# 4     99   B
# 5     34   B
# 6     71   B
# 7     22   C
# 8      0   C
# 9      0   C
于 2013-01-31T09:36:44.733 回答
1

这个怎么样?

out <- by(df, INDICES = df$id, FUN = function(x, N) {
  x <- droplevels(x)
  lng <- nrow(x)
  dif <- N - lng
  if (dif == 0) return(x)
  make.list <- lapply(1:dif, FUN = function(y) data.frame(id = levels(x$id), amount = 0))
  rbind(x, do.call("rbind", make.list))
  }, N = max(table(df$id))) # N could also be an integer
do.call("rbind", out)

    id amount
A.1  A     45
A.2  A     66
A.3  A      0
B.3  B     99
B.4  B     34
B.5  B     71
C.6  C     22
C.2  C      0
C.3  C      0
于 2013-01-31T09:09:49.830 回答