#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. Большое вам спасибо за вашу помощь — это сработало! Должно определенно читать «?Векторизировать» 😉