Какой параметр должна иметь функция R, чтобы использовать его в функции mutate из tidyverse?

#r #tidyverse #dplyr

#r #tidyverse #dplyr

Вопрос:

У A есть tibble со столбцом со строками, представляющими часы и минуты. Я хочу привести в порядок этот столбец и преобразовать элементы в целые числа, представляющие только минуты.

Эти строки могут иметь одну из следующих форм:

  • «5» (что означает 5 минут)
  • «XX min» (означает xx минут)
  • «X Std» (означает x часов)
  • «X Std. YY min» (что означает x часов и yy минут)

Я написал функцию для преобразования этих строк в минуты.

  • «5» должно стать 5.
  • «45 мин» должно стать 45.
  • «2 Std» должно стать 120.
  • «1 Std. 30 min» должно стать 90.

Вот как выглядит функция:

 convert_ZA_time <- function(string) {
    if (nchar(string) == 1) {
      result <- as.integer(string)
    }
    else if (endsWith(string, " Std")) {
      result <- as.integer(substring(string, 1, 1)) * 60
    }
    else if (endsWith(string, " min") amp;amp; nchar(string) == 6) {
      result <- as.integer(substring(string, 1, 2))
    }
    else if (endsWith(string, " min") amp;amp; nchar(string) > 6) {
      hour <- as.integer(gsub(" Std.*", "", string, perl = TRUE))
      minute_plus <- gsub("^\d  Std. ", "", string, perl = TRUE)
      minute <- as.integer(gsub(" min$", "", minute_plus))
      result <- hour * 60   minute
    }
    else {result <- NA}
    return(result)
}
  

Тестирование с помощью строк работает просто отлично:

 convert_ZA_time("2 Std. 50 min")
# prints [1] 170
  

Но когда я пытаюсь использовать эту функцию внутри функции tidyverse mutate, я получаю следующую ошибку:

 df <- tibble(datestr = c("5", "45 min", "1 Std", "2 Std. 30 min"))
df2 <- df %>% mutate(minutes = convert_ZA_time(datestr))
# throws error: the condition has length > 1 and only the first element will be used
  

Как мне изменить свою функцию, чтобы правильно использовать ее в mutate?

PS как я понимаю: mutate принимает каждый «datestr» и помещает его в функцию «convert_ZA_time». Но, по-видимому, mutate помещает вектор в функцию?

Спасибо за любую помощь!

Ответ №1:

Ваша функция просто еще не Vectorize является общей.

 convert_ZA_time(c("2 Std. 50 min", "3 Std. 50 min"))
# [1] 170 230
# Warning messages:
# 1: In if (nchar(string) == 1) { :
#   the condition has length > 1 and only the first element will be used
# 2: In if (endsWith(string, " Std")) { :
#   the condition has length > 1 and only the first element will be used
  

Исправить:

 convert_ZA_timev <- Vectorize(convert_ZA_time)
      
convert_ZA_timev(c("2 Std. 50 min", "3 Std. 50 min"))
# 2 Std. 50 min 3 Std. 50 min 
#           170           230 
  

Объяснение

У вас есть if / else structure в вашей функции, как эта:

 fun <- function(x) if (x >= 0) "pos" else "neg"
  

При применении к v элементу с длиной больше единицы он оценивает только первый элемент с предупреждением.

 v <- -2:2

fun(v)
# [1] "neg"
# Warning message:
#   In if (x >= 0) "pos" else "neg" :
#   the condition has length > 1 and only the first element will be used

fun(v[1])
# [1] "neg"
  

Векторизация позволяет функции работать с векторами.

 funv <- Vectorize(fun)
funv(v)
# [1] "neg" "neg" "pos" "pos" "pos"
  

Комментарии:

1. Большое вам спасибо за вашу помощь — это сработало! Должно определенно читать «?Векторизировать» 😉