Распространение значений из одного столбца на несколько новых столбцов с помощью data.table - PullRequest
1 голос
/ 04 августа 2020

У меня есть таблица Customer_ID, показывающая выплаты по годам. Первый (из многих) заказчик выглядит так:

 ID    Payment    Year
112          0    2004
112          0    2005
112          0    2006
112       9592    2007
112      12332    2008
112       9234    2011
112       5400    2012
112       7392    2014
112       8321    2015

Обратите внимание, что отсутствуют некоторые годы. Мне нужно создать 10 новых столбцов, показывающих Платежи за предыдущие 10 лет для каждой строки. Результирующая таблица должна выглядеть так:

 ID    Payment    Year   T-1  T-2  T-3  T-4  T-5  T-6  T-7  T-8  T-9 T-10   
112          0    2004  NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
112          0    2005     0 NULL NULL NULL NULL NULL NULL NULL NULL NULL
112          0    2006     0    0 NULL NULL NULL NULL NULL NULL NULL NULL
112        952    2007     0    0    0 NULL NULL NULL NULL NULL NULL NULL
112       1232    2008   952    0    0    0 NULL NULL NULL NULL NULL NULL
112        924    2011  NULL NULL 1232  952    0    0    0 NULL NULL NULL 
112        500    2012   924 NULL NULL 1232  952    0    0    0 NULL NULL 
112        392    2014  NULL  500  924 NULL NULL 1232  952    0    0    0
112        821    2015   392 NULL  500  924 NULL NULL 1232  952    0    0

(я знаю, что это дублирующие данные - она ​​готовится для прогнозной модели, в которой предыдущие платежи (и другая информация) будут использоваться для прогнозирования текущего годовой платеж)

В SQL я бы оставил присоединиться к таблице самому себе, присоединившись к ID и Year = (Year-1) et c ... но я не могу понять, как это сделать это в R.

Я также думал об использовании dplyr для группировки по идентификатору, а затем изменять новые столбцы с помощью задержки перед разгруппировкой. Но мои столы очень большие, и я думаю, что это будет слишком медленно. В идеале я бы хотел использовать вместо этого data.table, но не могу понять, как.

Любая помощь очень ценится.

Ответы [ 2 ]

2 голосов
/ 04 августа 2020

Сначала вы выполняете слияние с комбинацией всех дат и идентификаторов, чтобы получить недостающие годы:

dftot <- merge(df,CJ(Year =seq(min(df$Year),max(df$Year),1),ID = unique(df$ID)),all = T,by = "Year")
dftot[,ID := ID.y]
dftot[,c("ID.x","ID.y") := NULL]
dftot[,Year := as.numeric(Year)]
dftot <- dftot[order(Year)]

    Year Payment  ID
 1: 2004       0 112
 2: 2005       0 112
 3: 2006       0 112
 4: 2007    9592 112
 5: 2008   12332 112
 6: 2009      NA 112
 7: 2010      NA 112
 8: 2011    9234 112
 9: 2012    5400 112
10: 2013      NA 112
11: 2014    7392 112
12: 2015    8321 112

Затем вы создаете столбцы с задержкой и повторно выбираете строки, в которых нет отсутствующих Payement:

dftot[,c(paste0("T-",1:10)) := lapply(1:10,function(i){
  c(rep(NA,i),Payment[1:(.N-i)])
  }),by = ID ][!is.na(Payment)]




   Year Payment  ID  T-1  T-2   T-3   T-4  T-5   T-6   T-7  T-8 T-9 T-10
1: 2004       0 112   NA   NA    NA    NA   NA    NA    NA   NA  NA   NA
2: 2005       0 112    0   NA    NA    NA   NA    NA    NA   NA  NA   NA
3: 2006       0 112    0    0    NA    NA   NA    NA    NA   NA  NA   NA
4: 2007    9592 112    0    0     0    NA   NA    NA    NA   NA  NA   NA
5: 2008   12332 112 9592    0     0     0   NA    NA    NA   NA  NA   NA
6: 2011    9234 112   NA   NA 12332  9592    0     0     0   NA  NA   NA
7: 2012    5400 112 9234   NA    NA 12332 9592     0     0    0  NA   NA
8: 2014    7392 112   NA 5400  9234    NA   NA 12332  9592    0   0    0
9: 2015    8321 112 7392   NA  5400  9234   NA    NA 12332 9592   0    0

Это должно быть достаточно эффективным и обрабатывать несколько идентификаторов

Данные

library(data.table)
df <- setDT(read.table(text = "ID    Payment    Year
112          0    2004
                       112          0    2005
                       112          0    2006
                       112       9592    2007
                       112      12332    2008
                       112       9234    2011
                       112       5400    2012
                       112       7392    2014
                       112       8321    2015",header = T))
0 голосов
/ 04 августа 2020

Вот базовый вариант R, аналогичный решению @ denis

u <- merge(df1,
  data.frame(ID = unique(df1$ID), Year = min(df1$Year):max(df1$Year)),
  by = c("ID", "Year"), all = TRUE
)

subset(cbind(u, `colnames<-`(do.call(
  rbind,
  lapply(
    Reduce(c, c(NA, u$Payment), accumulate = TRUE)[1:nrow(u)],
    function(x) `length<-`(head(rev(x), 10), 10)
  )
), paste0("T-", 1:10))), !is.na(Payment))

, так что

    ID Year Payment  T-1  T-2   T-3   T-4  T-5   T-6   T-7  T-8 T-9 T-10
1  112 2004       0   NA   NA    NA    NA   NA    NA    NA   NA  NA   NA
2  112 2005       0    0   NA    NA    NA   NA    NA    NA   NA  NA   NA
3  112 2006       0    0    0    NA    NA   NA    NA    NA   NA  NA   NA
4  112 2007    9592    0    0     0    NA   NA    NA    NA   NA  NA   NA
5  112 2008   12332 9592    0     0     0   NA    NA    NA   NA  NA   NA
8  112 2011    9234   NA   NA 12332  9592    0     0     0   NA  NA   NA
9  112 2012    5400 9234   NA    NA 12332 9592     0     0    0  NA   NA
11 112 2014    7392   NA 5400  9234    NA   NA 12332  9592    0   0    0
12 112 2015    8321 7392   NA  5400  9234   NA    NA 12332 9592   0    0

Data

> dput(df1)
structure(list(ID = c(112L, 112L, 112L, 112L, 112L, 112L, 112L, 
112L, 112L), Payment = c(0L, 0L, 0L, 9592L, 12332L, 9234L, 5400L,
7392L, 8321L), Year = c(2004L, 2005L, 2006L, 2007L, 2008L, 2011L,
2012L, 2014L, 2015L)), class = "data.frame", row.names = c(NA,
-9L))
...