创建一个面板数据框。

4
我希望能够从数据集中创建一个面板,其中每个给定时间段都有一个观测值,以便每个单位在每个时期都有一个新的观测值。使用以下示例:
id <- seq(1:4)
year <- c(2005, 2008, 2008, 2007)
y <- c(1,0,0,1)
frame <- data.frame(id, year, y)
frame

 id year y
1  1 2005 1
2  2 2008 0
3  3 2008 0
4  4 2007 1

对于每个唯一的ID,我希望在2005年、2006年、2007年和2008年(本框架的下限和上限时间)有一个独特的观察值,并将结果y设置为0,以便在没有现有观察情况的所有时间内,新框架看起来像这样:

 id year y
1  1 2005 1
2  1 2006 0
3  1 2007 0
4  1 2008 0
....
13  4 2005 0
14  4 2006 0
15  4 2007 1
16  4 2008 0

我在循环方面没有取得太大的成功;非常感谢您提供任何想法。

3个回答

4

1) reshape2 创建由所有年份和id值交叉的网格g,并使用rbind将其与frame合并。

然后使用reshape2包,将frame从长格式转换为宽格式,再使用melt将其转换回长格式。最后按照需要重新排列行和列。

以#结尾的行只是为了确保每个年份都出现,如果我们知道这是正确的,那么可以省略这些行。以##结尾的行只是为了重新排列行和列,如果这不重要,那么也可以省略该行。

library(reshape2)

g <- with(frame, expand.grid(year = seq(min(year), max(year)), id = unique(id), y = 0)) #
frame <- rbind(frame, g) #

wide <- dcast(frame, year ~ id, fill = 0, fun = sum, value.var = "y")
long <- melt(wide, id = "year", variable.name = "id", value.name = "y")

long <- long[order(long$id, long$year), c("id", "year", "y")] ##

提供:

> long
   id year y
1   1 2005 1
2   1 2006 0
3   1 2007 0
4   1 2008 0
5   2 2005 0
6   2 2006 0
7   2 2007 0
8   2 2008 0
9   3 2005 0
10  3 2006 0
11  3 2007 0
12  3 2008 0
13  4 2005 0
14  4 2006 0
15  4 2007 1
16  4 2008 0

2) aggregate 更简洁的解决方案是只运行以 # 结尾的两行代码,然后再跟上一个 aggregate。该解决方案不需要使用任何附加包。

g <- with(frame, expand.grid(year = seq(min(year), max(year)), id = unique(id), y = 0)) #
frame <- rbind(frame, g) # 

aggregate(y ~ year + id, frame, sum)[c("id", "year", "y")]

这个解决方案与解决方案(1)给出的答案相同,但是正如评论者所指出的,解决方案(1)中将id转换为因子变量,而在此解决方案中它不是。


这里重新整形的特定原因是什么?使用以下代码不就可以了吗?merge(frame, g, by=c("id", "year"), all=TRUE)(其中 g 不包含 y=0)。 - Arun
如果您想要能够省略计算 g,即使已知所有年份都存在,也不能这样做。 - G. Grothendieck
抱歉,我不太明白。在所有年份都已知的情况下,您是在哪里消除了计算“g”的过程? - Arun
在第一个解决方案中,只需忽略以#结尾的行,就像答案中所述的那样,您将看到它仍然会提供相同的结果,前提是所有年份都出现在输入“frame”中。 - G. Grothendieck
明白,这里的id将是一个因素。 - Arun

3

使用 data.table

require(data.table)
DT <- data.table(frame, key=c("id", "year"))
comb <- CJ(1:4, 2005:2008) # like 'expand.grid', but faster + sets key
ans <- DT[comb][is.na(y), y:=0L] # perform a join (DT[comb]), then set NAs to 0
#     id year y
#  1:  1 2005 1
#  2:  1 2006 0
#  3:  1 2007 0
#  4:  1 2008 0
#  5:  2 2005 0
#  6:  2 2006 0
#  7:  2 2007 0
#  8:  2 2008 0
#  9:  3 2005 0
# 10:  3 2006 0
# 11:  3 2007 0
# 12:  3 2008 0
# 13:  4 2005 0
# 14:  4 2006 0
# 15:  4 2007 1
# 16:  4 2008 0

0

也许不是一种优雅的解决方案,但无论如何:

df <- expand.grid(id=id, year=unique(year))
frame <- frame[frame$y != 0,]
df$y <- 0
df2 <- rbind(frame, df)
df2 <- df2[!duplicated(df2[,c("id", "year")]),]
df2 <- df2[order(df2$id, df2$year),]
rownames(df2) <- NULL
df2
# id year y
# 1   1 2005 1
# 2   1 2006 0
# 3   1 2007 0
# 4   1 2008 0
# 5   2 2005 0
# 6   2 2006 0
# 7   2 2007 0
# 8   2 2008 0
# 9   3 2005 0
# 10  3 2006 0
# 11  3 2007 0
# 12  3 2008 0
# 13  4 2005 0
# 14  4 2006 0
# 15  4 2007 1
# 16  4 2008 0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接