代码之家  ›  专栏  ›  技术社区  ›  89_Simple

使用dplyr/data.table插入新行

  •  3
  • 89_Simple  · 技术社区  · 6 年前

    样本数据

    set.seed(123)
    df <- data.frame(year = c(rep(1980:1994, each = 9), rep(1995, times = 8), rep(1996:2012, each = 9), 
                              rep(2013, times = 7), rep(2014, times = 9)),
                     ref.doy = sample(120:180, 312, replace = T),
                     x = rnorm(312))
    

    每年,如果 ref.doy 不是9,那么我想插入额外的新行,这只是最后一行的副本。

    例如,如果1995年只有8个 参考doy ,我想把第八排复制到第九排。如果2013年,只有8个 参考doy ,然后我想复制第7行并将其复制为第8行和第9行,依此类推。

    我目前的解决方案是一个for循环:

    x <- df %>% group_by(year) %>% dplyr::mutate(y.length = n())
    year.vec <- 1980:2014
    temp.list <- list()
    
    for(y in seq_along(year.vec)){
    
      yr <- year.vec[y]
      temp <- x %>% dplyr::filter(year == yr)  
    
      if(unique(temp$y.length) != 9) {
    
        lastrow <- temp[nrow(temp), ]
        lastrow.repeat <- as.data.frame(lapply(lastrow, rep, 9 - nrow(temp))) 
        full.data  <- rbind(data.frame(temp), lastrow.repeat)         
        temp.list[[y]] <- full.data
    
        } else {
        temp.list[[y]] <- temp
      }
    }
    
    newdata <- rbindlist(temp.list)
    

    dplyr data.table 它自己。

    2 回复  |  直到 6 年前
        1
  •  2
  •   Ronak Shah    6 年前

    以您最近两年的数据为样本,2013年和2014年分别有5个条目和9个条目。我们 filter 少于9行的组,对于这些组,我们重复最后一行 9 - n() 时间,并使用将这些行添加到原始数据帧 bind_rows .

    df1 <- tail(df, 14)
    
    library(dplyr)
    
    df1 %>% 
        bind_rows(df1 %>%
                   group_by(year) %>%
                   #suggested by @Henrik
                   filter(n() < 9) %>%
                   slice(rep(n(), 9 - n()))) %>%
         arrange(year)
    
    
    #   year ref.doy          x
    #1  2013     126  0.9171749
    #2  2013     168 -2.6609228
    #3  2013     167  1.1102771
    #4  2013     120 -0.4849876
    #5  2013     167  0.2306168
    #6  2013     167  0.2306168
    #7  2013     167  0.2306168
    #8  2013     167  0.2306168
    #9  2013     167  0.2306168
    #10 2014     164 -0.2951578
    #11 2014     158  0.8719650
    #12 2014     149 -0.3484724
    #13 2014     129  0.5185038
    #14 2014     120 -0.3906850
    #15 2014     147 -1.0927872
    #16 2014     150  1.2100105
    #17 2014     143  0.7409000
    #18 2014     148  1.7242622
    

    将其应用于原始数据帧,并检查每个数据帧的行数 year

    df2 <- df %>% 
              bind_rows(df %>%
                          group_by(year) %>%
                          filter(n() < 9) %>%
                          slice(rep(n(), 9 - n()))) %>%
              arrange(year)
    
    
    df2 %>%
       group_by(year) %>%
       summarise(no_of_rows = n())
    # A tibble: 35 x 2
    # year no_of_rows
    #   <dbl>      <int>
    # 1  1980          9
    # 2  1981          9
    # 3  1982          9
    # 4  1983          9
    # 5  1984          9
    # 6  1985          9
    # 7  1986          9
    # 8  1987          9
    # 9  1988          9
    #10  1989          9
    # ... with 25 more rows
    

    或者正如@Henrik所提到的,最简单的方法是在每组的最后一行重复 9-n() 时间无关。

    df %>% 
       group_by(year) %>% 
       slice(c(1:n(), rep(n(), 9 - n())))
    
        2
  •  2
  •   Jaap    6 年前

    使用 :

    library(data.table)
    setDT(df)
    
    df[, ri := rowid(year)]
    
    df2 <- df[CJ(year = year, ri = 1:9, unique = TRUE), on = .(year, ri)
              ][, (2:3) := lapply(.SD, zoo::na.locf), .SDcols = 2:3
                ][, ri := NULL][]
    

    从而得到期望的结果:

    > df2[year %in% c(1995,2013)]
        year ref.doy           x
     1: 1995     160  1.05418102
     2: 1995     170  1.14526311
     3: 1995     167 -0.57746800
     4: 1995     179  2.00248273
     5: 1995     146  0.06670087
     6: 1995     139  1.86685184
     7: 1995     144 -1.35090269
     8: 1995     120  0.02098359
     9: 1995     120  0.02098359
    10: 2013     179  0.43528895
    11: 2013     126  0.71517841
    12: 2013     126  0.91717492
    13: 2013     168 -2.66092280
    14: 2013     167  1.11027710
    15: 2013     120 -0.48498760
    16: 2013     167  0.23061683
    17: 2013     167  0.23061683
    18: 2013     167  0.23061683
    

    它的作用是:

    1. df[, ri := rowid(year)] 添加行号 year
    2. CJ(year = year, ri = 1:9, unique = TRUE) )每年有九排。结果现在将包含没有9行的年份的空行。
    3. 在空行中填入 (2:3) := lapply(.SD, zoo::na.locf), .SDcols = 2:3
    4. 最后,移除 ri 列,因为它不再需要 ri := NULL

    @Henrik在评论中发布了一个更好的选择:

    df2 <- df[ , .SD[c(1:.N, rep(.N, 9 - .N))], by = year]