代码之家  ›  专栏  ›  技术社区  ›  Julien Massardier

用平均增长的中间值桥接最后一个和下一个非NA值

  •  2
  • Julien Massardier  · 技术社区  · 7 年前

    用中间值填充数据帧列中丢失的NAS,中间值从最后一个非NA值逐渐增长到下一个非NA值的好方法是什么?

    下面是一个例子:对于列成本,我想获得列成本估算,其中,2014年至2016年期间,成本每年增加31美元,将上一个已知成本595美元与下一个已知成本720美元桥接起来。

    enter image description here

    我想出的代码很长。有没有一种优雅的方法可以做到这一点?

    library(data.table)
    data = data.table(year=2000:2018,
                      cost = c(100,120,NA,200,220,NA,NA,300,350,470,500,NA,NA,595,NA,NA,NA,720,800))
    
    data[,cost_nas:=as.numeric(is.na(cost))]
    
    ## consecutive nas so far for each row:
    data[, consecutive_nas_so_far := seq_len(.N), by=rleid(cost_nas)]
    data[cost_nas==0,consecutive_nas_so_far:=0]
    
    # total number of consecutive nas in the sequence
    data[,total_number_of_consec_nas:=ifelse(consecutive_nas_so_far>0&shift(consecutive_nas_so_far,1,type = "lead")==0,consecutive_nas_so_far,NA)]
    data[cost_nas==0,total_number_of_consec_nas:=0]
    data[,total_number_of_consec_nas:=zoo::na.locf(total_number_of_consec_nas,fromLast=T)]
    
    #get last and next known values for cost:
    data[,cost_previous:=zoo::na.locf(cost)]
    data[,cost_following:=zoo::na.locf(cost,fromLast=T)]
    
    # apply the formula to calculate the gradual increase from cost_previous to cost_following
    data[,cost_esti:=round(consecutive_nas_so_far*(cost_following-cost_previous)/(total_number_of_consec_nas+1)+cost_previous,0)]
    data[is.na(cost_esti),cost_esti:=cost]
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   MKR    7 年前

    你可以 re-write data.table操作使用 zoo::na.locf data.table::rleid . 添加2列,每个列用于 lastNonNA nextNonNA 使用 na.locf . rleid 将为您提供连续的不同组 NA . 现在您可以编写逻辑来填充 使用 linear 之间 拉斯特诺娜 下一个 .

    library(data.table)
    library(zoo)
    #Data
    data = data.table(year=2000:2018,
           cost = c(100,120,NA,200,220,NA,NA,300,350,470,500,NA,NA,595,NA,NA,NA,720,800))
    
    data[,':='(lastNonNA = na.locf(cost, fromLast = FALSE), 
    nextNonNA = na.locf(cost, fromLast = TRUE), Group_NA = rleid(is.na(cost)))][
      ,':='(IDX = 1:.N), by=Group_NA][
      ,':='(cost = ifelse(is.na(cost), lastNonNA + IDX*((nextNonNA - lastNonNA)/(.N+1)),cost)), 
        by=Group_NA][,.(year, cost)]
    
    #    year     cost
    # 1: 2000 100.0000
    # 2: 2001 120.0000
    # 3: 2002 160.0000   #Filled
    # 4: 2003 200.0000
    # 5: 2004 220.0000
    # 6: 2005 246.6667  #Filled 
    # 7: 2006 273.3333  #Filled
    # 8: 2007 300.0000
    # 9: 2008 350.0000
    # 10: 2009 470.0000
    # 11: 2010 500.0000
    # 12: 2011 531.6667 #Filled
    # 13: 2012 563.3333 #Filled
    # 14: 2013 595.0000
    # 15: 2014 626.2500 #Filled 
    # 16: 2015 657.5000 #Filled
    # 17: 2016 688.7500 #Filled
    # 18: 2017 720.0000
    # 19: 2018 800.0000