Mutate_at останавливается, когда он не может интерполировать группу, tryCatch не работает

#r #syntax #interpolation #na #dplyr

#r #синтаксис #интерполяция #na #dplyr

Вопрос:

У меня есть следующие данные:

 library(data.table)
DT <- structure(list(country = c("Germany", "Germany", "Germany", "Germany", 
"Germany", "France", "France", "France", "France", "France", 
"UK", "UK", "UK", "UK", "UK"), year = c(2000, 2001, 2002, 2003, 
2004, 2000, 2001, 2002, 2003, 2004, 2000, 2001, 2002, 2003, 2004
), a = c(NA, NA, NA, NA, NA, NA, 1000, NA, 1600, NA, 1000, NA, 
1000, NA, NA), b = c(NA, NA, NA, NA, NA, NA, 1000, NA, 2200, 
NA, 1000, NA, 1000, NA, NA)), row.names = c(NA, -15L), class = c("data.table", 
"data.frame"))
 

Я пытаюсь интерполировать некоторые значения.

Я пытался воссоздать эту ошибку (что, конечно, очень логичная ошибка, потому что для Германии нет данных):

 Error: Problem with `mutate()` input `a`.
x need at least two non-NA values to interpolate
i Input `count` is `(structure(function (..., .x = ..1, .y = ..2, . = ..1) ...`.
i The error occurred in group 123: value = "group", country = "Arthur", State = "Nebraska".
Run `rlang::last_error()` to see where the error occurred.
 

С помощью следующего кода:

 library(tidyverse)
library(zoo)
st_example %>%
  group_by(country) %>%
  mutate_at(vars(a),~na.fill(.x,c(NA, "extend", NA))) %>% 
  filter(!is.na(a))
 

К сожалению, я не получаю ожидаемую ошибку.

Моя проблема в том, что при mutate_at сбое он не переходит к следующей группе. Я пытался построить a tryCatch вокруг mutate_at(vars(a:b),~na.fill(.x,c(NA, "extend", NA))) %>% , но безуспешно.

Как мне указать mutate_at продолжить, если он обнаружит ошибку?

Ответ №1:

Ваша ошибка выдается zoo::na.fill , а не mutate_at() . Запуск rlang::last_error() с консоли выявил бы это.

 zoo::na.fill(c("hello",NA), c(NA, "extend", NA))
Error in approx(wix, unlist(object[wix]), xout = wrng) : 
  need at least two non-NA values to interpolate
 

Вы можете взломать его вместе с чем-то вроде этого:

 DT %>%
  group_by(country) %>%
  mutate_at(
    vars(a),
    ~ tryCatch(
        as.numeric(na.fill(.x,c(NA, "extend", NA))),
        error = function(error) .x
    )
  ) %>%
  filter(!is.na(a))
 

Кроме того, нет причин использовать data.table в коде примера — dplyr принудит data.table объекты к data.frame .

Ответ №2:

Следующее должно работать без использования tryCatch():

 DT %>%
  split(.$country) %>%
  purrr::map(~mutate(., a = as.numeric(na.fill(.x$a, c(NA, "extend", NA))))) %>%
  bind_rows()
 

Ответ №3:

Если целью является выполнение линейной интерполяции по столбцам a по странам, то:

 library(dplyr)
library(zoo)

DT %>% 
  group_by(country) %>%
  mutate(a = na.approx(a, na.rm = FALSE)) %>%
  ungroup
 

или для интерполяции всех числовых столбцов:

 DT %>% 
  group_by(country) %>%
  mutate(across(where(is.numeric), ~ na.approx(., na.rm = FALSE))) %>%
  ungroup