сокращение повторяющихся задач в data.table в R - PullRequest
0 голосов
/ 26 мая 2020

Я замечаю, что делаю одно и то же несколько раз, только с немного разными значениями:

HCCtreshold <- 40000

  claimsMonthly[, HCC12mnth := +(HCCtreshold < claim12month)][ HCC12mnth == 1, `:=` (aboveHCCth12mnth = (claim12month - HCCtreshold))][is.na(aboveHCCth12mnth),aboveHCCth12mnth := 0]
  claimsMonthly[, HCC11mnth := +(HCCtreshold < claim11month)][ HCC11mnth == 1, `:=` (aboveHCCth11mnth = (claim11month - HCCtreshold))][is.na(aboveHCCth11mnth),aboveHCCth11mnth := 0]
  claimsMonthly[, HCC10mnth := +(HCCtreshold < claim10month)][ HCC10mnth == 1, `:=` (aboveHCCth10mnth = (claim10month - HCCtreshold))][is.na(aboveHCCth10mnth),aboveHCCth10mnth := 0]

Итак, началось примерно так:

  k <- seq.default(from = 8, to = 12, by = 1)
  claimsMonthly[paste0("HCC", k, "mnth") := lapply(k, function(x) (+(HCCtreshold < paste0("HCC", k, "mnth"))))]

я получаю сообщение об ошибке :

Error: Check that is.data.table(DT) == TRUE. Otherwise, := and `:=`(...) are defined for use in j, once only and in particular ways. See help(":=").

Я тоже пробовал:

 for(k in 8:12){
    claimsMonthly[, paste0("HCC", k, "mnth") := +(HCCtreshold < paste0("HCC", k, "mnth"))]
  }

столбцы созданы правильно, но я получаю в них неправильные значения. Я получаю 1 везде

Я не уверен, что делаю не так?

1 Ответ

1 голос
/ 27 мая 2020

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

  1. Вы можете программно определить имена в левой части :=, если вы обернете вектор в c(...), например, DT[ c(vec_of_names) := list(some, values)].

  2. Вы можете программно получать значения переменных с вектором имен переменных и mget. Хотя я обычно думаю, что mget может указывать на проблемный код c, я считаю, что здесь он работает с низким риском. (Хотя mget и get обычно извлекают переменные из операционной среды, часто .GlobalEnv, из операции data.table, а затем извлекают столбцы так же легко.)

  3. Вместо этого двойного касания присваивания с помощью == 1, а затем is.na(...), мы можем использовать некоторые логические уловки и функцию data.table::fcoalesce. (Если вы не знакомы, fcoalesce работает как функция coalesce SQL, которая представляет собой удобный для векторов способ поиска первого не- NA значения в аргументах векторов.

    fcoalesce(c(1, 2, NA, NA), c(11, 12, 13, NA), c(21, 22, 23, 24))
    # [1]  1  2 13 24
    

    Мы можем использовать fcoalesce(some + math * calc, 0) для вычисления и, если NA, заменить его на 0. (Мы используем его для above* переменных ниже, и не обязательно для логических переменных HCC*. Он может примените и туда, если хотите. Если эти HCC* переменные выбрасываются, это просто не имеет значения.)

Поддельные данные:

library(data.table)
set.seed(42)
hccthreshold <- 50
dat <- data.table( claim10month = sample(99, 10), claim11month = sample(99, 10), claim12month = sample(99, 10) )
dat$claim11month[5] <- NA
dat
#     claim10month claim11month claim12month
#  1:           91           46           90
#  2:           92           71           14
#  3:           28           91           96
#  4:           80           25           91
#  5:           61           NA            8
#  6:           49           89           49
#  7:           69           97           37
#  8:           13           11           84
#  9:           60           95           41
# 10:           64           51           76

Во-первых, давайте программно определим имена столбцов, с которыми мы хотим работать, а затем создадим те же векторы для новых переменных (я большой поклонник определения и адаптации этих имен переменных программно, так что если вы получите частичный набор данных, ваш код по-прежнему работает. Вы можете подумать о настройке проверок и сигналов тревоги, чтобы обнаружить что-то не так. Например, stopifnot(length(claimnames) == 12L), если вы ожидаете, что всегда будет ровно 12 месяцев.)

claimnames <- grep("^claim[0-9]+month", colnames(dat), value = TRUE)
hccnames <- gsub("^claim", "HCC", claimnames)
abovenames <- gsub("^claim", "aboveHCC", claimnames)
claimnames
# [1] "claim10month" "claim11month" "claim12month"
hccnames
# [1] "HCC10month" "HCC11month" "HCC12month"
abovenames
# [1] "aboveHCC10month" "aboveHCC11month" "aboveHCC12month"

И теперь мы можем обработать t Данные.

dat[, c(hccnames) := lapply(mget(claimnames), `>`, hccthreshold) ]
dat[, c(abovenames) := Map(function(hcc, clm) fcoalesce(clm - hcc * hccthreshold, 0),
                           mget(hccnames), mget(claimnames)) ]
dat
#     claim10month claim11month claim12month HCC10month HCC11month HCC12month aboveHCC10month aboveHCC11month aboveHCC12month
#  1:           91           46           90       TRUE      FALSE       TRUE              41              46              40
#  2:           92           71           14       TRUE       TRUE      FALSE              42              21              14
#  3:           28           91           96      FALSE       TRUE       TRUE              28              41              46
#  4:           80           25           91       TRUE      FALSE       TRUE              30              25              41
#  5:           61           NA            8       TRUE         NA      FALSE              11               0               8
#  6:           49           89           49      FALSE       TRUE      FALSE              49              39              49
#  7:           69           97           37       TRUE       TRUE      FALSE              19              47              37
#  8:           13           11           84      FALSE      FALSE       TRUE              13              11              34
#  9:           60           95           41       TRUE       TRUE      FALSE              10              45              41
# 10:           64           51           76       TRUE       TRUE       TRUE              14               1              26

Я решил оставить переменные HCC* как logical вместо ваших +(...) целых чисел, но их можно напрямую переводить и решать вам.

...