R вменяют Кальману на больших данных - PullRequest
0 голосов
/ 19 апреля 2020

У меня большой набор данных, 4666972 шт. из 5 переменных.
Я хочу вменять один столбец, MPR, с Кальман метод на основе каждой группы.

> str(dt)
Classes ‘data.table’ and 'data.frame':  4666972 obs. of  5 variables:
 $ Year : int  1999 2000 2001 1999 2000 2001 1999 2000 2001 1999 ...
 $ State: int  1 1 1 1 1 1 1 1 1 1 ...
 $ CC   : int  1 1 1 1 1 1 1 1 1 1 ...
 $ ID   : chr  "1" "1" "1" "2" ...
 $ MPR  : num  54 54 55 52 52 53 60 60 65 70 ...

Я попробовал приведенный ниже код, но через некоторое время он вышел из строя.

> library(imputeTS)
> data.table::setDT(dt)[, MPR_kalman := with(dt, ave(MPR, State, CC, ID, FUN=na_kalman))]

Я не знаю, как повысить эффективность времени и успешно вменять без сбоев.

Лучше ли разделить набор данных с помощью ID, чтобы составить список и вписать каждый из них с помощью for loop?

> length(unique(hpms_S3$Section_ID))
[1] 668184

> split(dt, dt$ID)

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

Есть ли какой-нибудь отличный способ сделать или как я могу оптимизировать код, который я сделал?

Я привожу простой пример:

# dt
Year  State   CC   ID    MPR    
2002     15   3     3     NA  
2003     15   3     3     NA  
2004     15   3     3    193   
2005     15   3     3    193  
2006     15   3     3    348  
2007     15   3     3    388  
2008     15   3     3    388  
1999     53   33    1     NA  
2000     53   33    1     NA       
2002     53   33    1     NA      
2003     53   33    1     NA   
2004     53   33    1     NA     
2005     53   33    1    170  
2006     53   33    1    170        
2007     53   33    1    330      
2008     53   33    1    330          

РЕДАКТИРОВАТЬ :
Поскольку @ r2evans упоминается в комментарии, я изменил код:

> setDT(dt)[, MPR_kalman := ave(MPR, State, CC, ID, FUN=na_kalman), by = .(State, CC, ID)]

Error in optim(init[mask], getLike, method = "L-BFGS-B", lower = rep(0,  : 
  L-BFGS-B needs finite values of 'fn'

Я получил ошибку выше. Я нашел post здесь для обсуждения этой ошибки. Тем не менее, даже если я использую na_kalman(MPR, type = 'level'), я все равно получил ошибку. Я думаю, что могут быть некоторые повторяющиеся значения в группах, так что это привело к ошибке.

1 Ответ

2 голосов
/ 19 апреля 2020

Возможно, разделение должно выполняться с помощью оператора data.table by=, возможно, более эффективно.

Поскольку у меня не установлено imputeTS (есть несколько вложенных зависимостей, которых у меня нет ), Я подделаю вменение, используя zoo::na.locf, оба вперед / назад. Я не предлагаю, чтобы это был ваш механизм вменения, я использую его для демонстрации более распространенного паттерна с data.table.

myimpute <- function(z) zoo::na.locf(zoo::na.locf(z, na.rm = FALSE), fromLast = TRUE, na.rm = FALSE)

Теперь некоторые эквивалентные вызовы, один с вашим with(dt, ...) и моим альтернативы (которые на самом деле являются пошаговыми инструкциями до моего окончательного предложения 5):

dt[, MPR_kalman1 := with(dt, ave(MPR, State, CC, ID, FUN = myimpute))]
dt[, MPR_kalman2 := with(.SD, ave(MPR, State, CC, ID, FUN = myimpute))]
dt[, MPR_kalman3 := with(.SD, ave(MPR, FUN = myimpute)), by = .(State, CC, ID)]
dt[, MPR_kalman4 := ave(MPR, FUN = myimpute), by = .(State, CC, ID)]
dt[, MPR_kalman5 := myimpute(MPR), by = .(State, CC, ID)]
#     Year State CC ID MPR MPR_kalman1 MPR_kalman2 MPR_kalman3 MPR_kalman4 MPR_kalman5
#  1: 2002    15  3  3  NA         193         193         193         193         193
#  2: 2003    15  3  3  NA         193         193         193         193         193
#  3: 2004    15  3  3 193         193         193         193         193         193
#  4: 2005    15  3  3 193         193         193         193         193         193
#  5: 2006    15  3  3 348         348         348         348         348         348
#  6: 2007    15  3  3 388         388         388         388         388         388
#  7: 2008    15  3  3 388         388         388         388         388         388
#  8: 1999    53 33  1  NA         170         170         170         170         170
#  9: 2000    53 33  1  NA         170         170         170         170         170
# 10: 2002    53 33  1  NA         170         170         170         170         170
# 11: 2003    53 33  1  NA         170         170         170         170         170
# 12: 2004    53 33  1  NA         170         170         170         170         170
# 13: 2005    53 33  1 170         170         170         170         170         170
# 14: 2006    53 33  1 170         170         170         170         170         170
# 15: 2007    53 33  1 330         330         330         330         330         330
# 16: 2008    53 33  1 330         330         330         330         330         330

Два метода дают одинаковые результаты, но последний сохраняет многие из показателей эффективности памяти, которые могут сделать data.table предпочтительнее.

Использование with(dt, ...) является анти-паттерном в одном случае и серьезным риском в другом. Что касается «риска», поймите, что data.table может многое сделать за кулисами, так что вычисления / вызовы функций в компоненте j= (второй аргумент) видят только данные, которые имеют отношение к делу. Ярким примером является группировка, но другим (не связанным с этим) примером data.table является условная замена, как в dt[is.na(x), x := -1]. Со ссылкой на входную таблицу dt внутри этого, если когда-либо будет что-то в первом аргументе (условная замена) или by= аргументе, то это терпит неудачу.

MPR_kalman2 уменьшает это с помощью .SD, который является data.table способом замены данных, которые будут использоваться, на "S ubset D ata " ( ref ). Но он по-прежнему не использует существенную эффективность data.table в работе с группами в оперативной памяти.

MPR_kalman3 работает над этим, группируя снаружи, все еще используя with, но не (как в * 1042). *) более дружественным образом.

MPR_kalman4 исключает использование with, поскольку действительно MPR, видимый для ave, все равно есть только в каждой группе. И потом, когда вы думаете об этом, так как ave не дана группирующая переменная, она просто передает все данные MPR напрямую в myimpute. Исходя из этого, у нас есть MPR_kalman5, прямой метод, который работает по обычным схемам data.table.

Хотя я не знаю , что это уменьшит ваш сбой, это намеревался очень эффективно использовать память (data.table).

...