【问题标题】:Create a panel data frame创建面板数据框
【发布时间】:2025-12-10 14:55:01
【问题描述】:

我想从一个数据集创建一个面板,该面板在每个给定时间段都有一个观察值,这样每个单元在每个时间段都有一个新的观察值。使用以下示例:

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

我在循环方面没有取得多大成功;任何和所有想法将不胜感激。

【问题讨论】:

    标签: r panel


    【解决方案1】:

    1) reshape2 创建一个所有年份的网格gid 交叉的值和rbind 它与frame

    然后使用 reshape2 包 cast 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 ,如图所示。此解决方案不使用插件包。

    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
    • 如果您希望能够省略 g 的计算,前提是已知所有年份都存在。
    • 我不明白,抱歉。在您知道所有年份都存在的情况下,您在哪里消除 g 的计算?
    • 在第一个解决方案中,只需省略以 # 结尾的行,如答案中所述,您将看到它仍然给出相同的结果,前提是输入 frame 中存在所有年份。
    • 知道了。请注意,id 将是这里的一个因素。
    【解决方案2】:

    使用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
    

    【讨论】:

      【解决方案3】:

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

      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
      

      【讨论】: