首页 > 解决方案 > 使用按类别的增长率填充 data.table 中的缺失值

问题描述

我有不完整的(时间)序列,我想使用可用的最近值和另一个序列的增长率,按类别(国家)填充缺失值。类别,缺失值不等长。这需要按顺序对变量应用函数:首先,我需要获取最后一个可用数据点(可以是任何地方)并将其除以 1+ 增长率,然后移动到下一个数据点并执行相同操作。

示例数据集和预期结果:

require(data.table)
DT_desired<-data.table(category=c(rep("A",4),rep("B",4)),
           year=2010:2013,
           grwth=c(NA,.05,0.1,0,NA,0.1,0.15,0.2))
DT_desired[,values:=c(cumprod(c(1,DT_desired[category=="A"&!is.na(grwth),grwth]+1)),cumprod(c(1,DT_desired[category=="B"&!is.na(grwth),grwth]+1)))]

DT_example <- copy(DT_desired)[c(1,2,3,5),values:=NA]

我尝试过:你可以通过 for 循环来完成,但这在 R 中效率低下且令人沮丧。我开始喜欢 data.table 的效率,我更愿意以这种方式来做。我已经尝试过数据表的移位功能,它只填充一个缺失值(这是合乎逻辑的,因为它试图同时执行我猜想,当其余部分缺失前一个值时)。

DT_example[,values:=ifelse(is.na(values),shift(values,type = "lead")/(1+shift(grwth,type = "lead")),values),by=category]

我从其他帖子中收集到,您可能可以使用 zoo 包的 rollapply 功能来完成它,但我只是觉得我应该能够在数据表中完成它而无需另一个额外的包,并且解决方案相对简单和优雅,只是我没有足够的经验找到它。

如果我没有注意到适当的帖子,这很可能是重复的,很抱歉,但我发现的内容都没有完全符合我的要求。

标签: rdata.tableinterpolationdata-manipulation

解决方案


不确定这是否已在 SO 之外解决,但前几天引起了我的注意。我很久没有写 Rcpp 了,我认为这是一个很好的做法。我知道您正在寻找本机data.table解决方案,因此请随意接受或放弃:

文件内容foo.cpp

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector fillValues(NumericVector vals, NumericVector gRates){

  int n = vals.size();
  NumericVector out(n);

  double currentValue   = vals[n - 1];
  double currentGrowth  = gRates[n - 1];

  // initial assignment
  out[n - 1] = currentValue;

  for(int i = n - 2; i >= 0; i--){

    if(NumericVector::is_na(vals[i])){
      // If val[i] is na, we need prior values to populate it
      if(!((currentValue || currentValue == 0) && (currentGrowth || currentGrowth == 0))){
        // We need a currentValue and currentGrowth to base growth rate on, throw error
        Rcpp::stop("NaN Values for rates or value when needed actual value");
      } else {
        // Update value
        out[i] = currentValue / (1 + currentGrowth);
      }
    } else {
      out[i] = vals[i];
    }

    // update
    currentValue = out[i];
    if(!NumericVector::is_na(gRates[i])){
      currentGrowth = gRates[i];
    }
  }

  return out;
}

/*** R
require(data.table)
DT_desired<-data.table(category=c(rep("A",4),rep("B",4)),
                       year=2010:2013,
                       grwth=c(NA,.05,0.1,0,NA,0.1,0.15,0.2))

DT_desired[,values:=c(cumprod(c(1,DT_desired[category=="A"&!is.na(grwth),grwth]+1)),cumprod(c(1,DT_desired[category=="B"&!is.na(grwth),grwth]+1)))]

DT_example <- copy(DT_desired)[c(1,2,3,5),values:=NA]

DT_desired[]
DT_example[]

DT_example[, values:= fillValues(values, grwth)][]
*/

然后运行它:

> Rcpp::sourceCpp('foo.cpp')

# Removed output that created example data

> DT_desired[]
   category year grwth values
1:        A 2010    NA  1.000
2:        A 2011  0.05  1.050
3:        A 2012  0.10  1.155
4:        A 2013  0.00  1.155
5:        B 2010    NA  1.000
6:        B 2011  0.10  1.100
7:        B 2012  0.15  1.265
8:        B 2013  0.20  1.518

> DT_example[]
   category year grwth values
1:        A 2010    NA     NA
2:        A 2011  0.05     NA
3:        A 2012  0.10     NA
4:        A 2013  0.00  1.155
5:        B 2010    NA     NA
6:        B 2011  0.10  1.100
7:        B 2012  0.15  1.265
8:        B 2013  0.20  1.518

> DT_example[, values:= fillValues(values, grwth)][]
   category year grwth values
1:        A 2010    NA  1.000
2:        A 2011  0.05  1.050
3:        A 2012  0.10  1.155
4:        A 2013  0.00  1.155
5:        B 2010    NA  1.000
6:        B 2011  0.10  1.100
7:        B 2012  0.15  1.265
8:        B 2013  0.20  1.518

请注意,这是从前向后运行的,因此它假定您要从最近的录音开始,然后从更远的位置开始录音。它还假设您的数据集已排序。


推荐阅读