展开数据框

时间:2016-02-29 20:21:14

标签: r dplyr

我想在某些条件下扩展数据框。它有点类似于这个问题expand data frames inside data frame,但不完全相同。

我有一个数据框:

df = data.frame(ID = c(3,3,3,3, 17,17,17, 74, 74, 210, 210, 210, 210), amount = c(101, 135, 101, 68,  196, 65 ,135, 76, 136, 15, 15, 15 ,15), week.number = c(4, 6, 8, 10, 2, 5, 7, 2, 6, 2, 3, 5, 6))

我希望扩展每个ID的数据框,给定min和max week.number,并在此扩展的amount列中包含0。最小周数。数字为1,最大周数。数字为10.预期结果为:

df1 <- data.frame(ID = c(rep(3,10), rep(17, 10), rep(74, 10), rep(210, 10)),
              amount = c(0, 0, 0, 101, 0, 135, 0, 101, 0, 68, 0, 196,
                         0, 0, 65, 0, 135, 0, 0, 0, 0, 76, 0, 0, 0,
                         136, 0, 0, 0, 0, 0, 15, 15, 0, 15, 15, 0, 0,
                         0, 0))

(实际上,我有成千上万的ID和周数从1到160)。

有一种简单,快捷的方法吗?

谢谢!

2 个答案:

答案 0 :(得分:5)

以下是使用tidyr

执行此操作的方法
library(tidyr)
complete(df, ID, weeek.number = 1:10, fill = list(amount = 0))
#Source: local data frame [40 x 3]
#
#      ID weeek.number amount
#   (dbl)        (dbl)  (dbl)
#1      3            1      0
#2      3            2      0
#3      3            3      0
#4      3            4    101
#5      3            5      0
#6      3            6    135
#7      3            7      0
#8      3            8    101
#9      3            9      0
#10     3           10     68
#..   ...          ...    ...

基地R的方法是使用expand.gridmerge

newdf <- merge(expand.grid(ID = unique(df$ID), weeek.number = 1:10), df, all.x = TRUE)
newdf$amount[is.na(newdf$amount)] <- 0   # replace NA with 0

答案 1 :(得分:5)

使用data.table(tx到Frank以更正结果的长度):

require(data.table)
dt<-as.data.table(df)
f<-function(x,y,len=max(y)) {res<-numeric(len);res[y]<-x;res}
dt[,list(amount=f(amount,weeek.number,10)),by=ID]
#     ID amount
# 1:   3      0
# 2:   3      0
# 3:   3      0
# 4:   3    101
# 5:   3      0
# 6:   3    135
# 7:   3      0
# 8:   3    101
# 9:   3      0
#10:   3     68
# ......

修改

我刚注意到你的amountweeek.number实际上定义了一个sparseVector,即一个主要由零组成的向量,其中只保留非零元素的索引。因此,您可以尝试使用Matrix包:

require(Matrix)
dt[,list(as.vector(sparseVector(amount,weeek.number,10))),by=ID]

获得与上面相同的结果。