r - перевод dplyr в data.table - PullRequest
1 голос
/ 17 марта 2020

Как я могу сделать ту же обработку с data.table? Я имею в виду, это занимает много времени в моей таблице строк 3,5M.

Данные:

ipoi_pdi <- tibble(
  id = c("1","1","2","3","4","4"),
  tipo_servico = c("Escala Normal", "IFR - 6 horas", "Convocação", "Escala Normal", "Convocação", "Escala Normal")
)

Обработка:

ipoi_pdi %>%
  group_by(
    id
  ) %>%
  mutate(
    tipo_servico = case_when(
      n() == 1 ~ tipo_servico,
      n() > 1 & any(tipo_servico == "IFR - 6 horas") ~ "IFR - 6 horas",
      n() > 1 & any(tipo_servico == "IFR - 12 horas") ~ "IFR - 12 horas",
     TRUE ~ "Não é IFR"
    )
  ) -> ipoi_pdi

Ответы [ 2 ]

2 голосов
/ 17 марта 2020

Существует очень классный пакет для такого перевода, называемый dtplyr:

library(dplyr)
library(dtplyr)
library(data.table)

Единственное изменение, которое вы должны внести в свой исходный код, - это обернуть ваш объект в lazy_dt перед тем, как запустив команду:

lazy_dt(ipoi_pdi) %>% 
  group_by(
    id
  ) %>%
  mutate(
    tipo_servico = case_when(
      n() == 1 ~ tipo_servico,
      n() > 1 & any(tipo_servico == "IFR - 6 horas") ~ "IFR - 6 horas",
      n() > 1 & any(tipo_servico == "IFR - 12 horas") ~ "IFR - 12 horas",
      TRUE ~ "Não é IFR"
    )
  ) -> ipoi_pdi

Теперь, когда вы печатаете объект, он отображает соответствующий код data.table как Call:

print(ipoi_pdi)
#> Source: local data table [?? x 2]
#> Call:   copy(`_DT1`)[, `:=`(tipo_servico = case_when(.N == 1 ~ tipo_servico, 
#>     .N > 1 & any(tipo_servico == "IFR - 6 horas") ~ "IFR - 6 horas", 
#>     .N > 1 & any(tipo_servico == "IFR - 12 horas") ~ "IFR - 12 horas", 
#>     TRUE ~ "Não é IFR")), keyby = .(id)]
#> 
#>   id    tipo_servico 
#>   <chr> <chr>        
#> 1 1     IFR - 6 horas
#> 2 1     IFR - 6 horas
#> 3 2     Convocação   
#> 4 3     Escala Normal
#> 5 4     Não é IFR    
#> 6 4     Não é IFR    
#> 
#> # Use as.data.table()/as.data.frame()/as_tibble() to access results

Преобразуйте ваш объект в data.table и выполните вызов:

ipoi_pdi_dt <- as.data.table(ipoi_pdi)

ipoi_pdi_dt_new <- ipoi_pdi_dt[, `:=`(tipo_servico = case_when(.N == 1 ~ tipo_servico, 
                                                               .N > 1 & any(tipo_servico == "IFR - 6 horas") ~ "IFR - 6 horas", 
                                                               .N > 1 & any(tipo_servico == "IFR - 12 horas") ~ "IFR - 12 horas", 
                                                               TRUE ~ "Não é IFR")), keyby = .(id)]

print(ipoi_pdi_dt_new)
#>    id  tipo_servico
#> 1:  1 IFR - 6 horas
#> 2:  1 IFR - 6 horas
#> 3:  2    Convocação
#> 4:  3 Escala Normal
#> 5:  4     Não é IFR
#> 6:  4     Não é IFR

Чтобы проверить, равны ли результаты:

all.equal(as.data.frame(ipoi_pdi_new), as.data.frame(ipoi_pdi_dt_new))
#> [1] TRUE

Поскольку data.table не имеет эквивалента case_when, эта часть остается той же. Если вы делаете это по соображениям производительности, это должно быть хорошо. В противном случае вы должны использовать кучу ifelse вызовов для его замены.

2 голосов
/ 17 марта 2020
setDT(ipoi_pdi)
ipoi_pdi[, 
         tipo_servico := 
           if (.N == 1) {
             tipo_servico
           } else if (any(tipo_servico == "IFR - 6 horas")) {
             "IFR - 6 horas"
           } else if (any(tipo_servico == "IFR - 12 horas")) {
             "IFR - 12 horas"
           } else {
             "Não é IFR"
           },
         by = id]

PS. После первого if нам не нужно снова проверять, если .N > 1, мы знаем, что это должно быть правдой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...