Заполните пропущенные значения в data.table, используя темп роста по категориям - PullRequest
0 голосов
/ 27 ноября 2018

У меня есть неполные (временные) ряды, в которых я хотел бы заполнить пропущенные значения, используя доступные недавние значения и темпы роста из другого ряда, по категориям (странам).Категории, пропущенные значения не равны длине.Это требует применения функции к переменной последовательно: сначала мне нужно взять последнюю доступную точку данных (которая может быть где угодно) и разделить ее на 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]

Из других публикаций я узнал, что вы, вероятно, можете сделать это с помощью функции rollapply пакета zoo, но у меня только появилось ощущение, что я смогу сделать это в таблице данных без еще одного дополнительного пакета, и что решение относительнопростой и элегантный, просто я не достаточно опытен, чтобы его найти.

Это может быть дубликатом и извините, если я не заметил соответствующий пост, но ничего из того, что я нашел, не получилось именно так, как я хочу.

1 Ответ

0 голосов
/ 29 ноября 2018

Не уверен, что это было решено за пределами 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

Обратите внимание, что это выполняется задом наперед, поэтому предполагается, что вы хотите начать с самой последней записи и перейти к записи с дальнейших задних сторон.Также предполагается, что ваш набор данных отсортирован.

...