Проблема векторизации UDF, чтобы позволить mutate () изменить фрейм данных - PullRequest
1 голос
/ 18 апреля 2019

Я пытаюсь написать функцию, которую я могу использовать с dplyr и mutate. В моем реальном примере я хочу передать два столбца и вернуть значение, которое использует операторы ifelse, основанные на каждом столбце, чтобы решить, какое вычисление выполнить.

Увидев, что операторы if не векторизуются, я попытался использовать ifthen, потому что я думал, что они автоматически векторизуются. У меня все еще были проблемы, и я свел вещи к тому, что теперь составляет поиск. У меня 2 скуса. Каждый предмет имеет вес. Я хочу, чтобы предметы весом менее 5 фунтов были маленькими, а остальные - большими

library(dplyr)

x<- data.frame(Sku = c(9, 12), Lbs = c(9, 2))
> x
  Sku Lbs
1   9   9
2  12   2

SizeCalc <- function(Wt) 
{ ifelse (Wt <= 5, 
          Size <- "Small",
          Size <- "Big")
  return (Size)
}

Этот первый предмет большой, а второй маленький. Но если я запускаю это для полного фрейма данных, он думает, что оба элемента большие. Если я отправляю только второй товар, он знает, что он маленький.

> mutate(x[1:2,], Size = SizeCalc(Lbs))
  Sku Lbs Size
1   9   9  Big
2  12   2  Big
> mutate(x[2:2,], Size = SizeCalc(Lbs))
  Sku Lbs  Size
1  12   2 Small

Если я явно векторизирую функцию, она работает:

> SizeCalc_v <- Vectorize(SizeCalc)
> mutate(x[1:2,], Size = SizeCalc_v(Lbs))
  Sku Lbs  Size
1   9   9   Big
2  12   2 Small

Нужно ли мне всегда векторизовать функции, которые я хочу использовать с mutate (), или я упустил что-то еще?

Увидев комментарий, я уточняю. Моя фактическая функция имеет вложенные ifelses, которые дают результаты, используемые в вычислениях, поэтому я не могу просто вернуть результат ifelse. Вот актуальная функция. Входные данные First и Last и даты в формате ГГГГММ. Я вычисляю количество «полугодий» между датами, но Ян считается концом предыдущего года. У меня похожая проблема, когда результат зависит от того, сколько исходного кадра данных я отправляю.

Delta <- function(First, Last) 
{ ifelse (First%%100 <= 6, 
          F <- 2*(First%/%100) + 1, # if in 1st half of year add 1
          F <- 2*(First%/%100) + 2) # if in 2nd half of year add 2
  ifelse (Last%%100 >= 7, 
          L <- 2*(Last%/%100) + 2,  # if in 2nd half of year add 2
          ifelse (Last%%100 >= 2,
                  L <- 2*(Last%/%100) + 1, # if in Feb-Jun 1
                  L <- 2*(Last%/%100)))    # if in Jan, treat as previous year
  return (L-F)
}

1 Ответ

1 голос
/ 18 апреля 2019

Вы определили SizeCalc функцию неправильно.Нет необходимости присваивать значения переменной (Size) внутри ifelse.

ifelse векторизовано, измените свою функцию на

SizeCalc <- function(Wt) ifelse(Wt <= 5, "Small","Big")

, и теперь, если мы используем mutate, она работает как положено.

library(dplyr)
mutate(x, Size = SizeCalc(Lbs))

#  Sku Lbs  Size
#1   9   9   Big
#2  12   2 Small

Чем большеdplyr способ заключается в использовании цепочки

x %>% mutate(Size = SizeCalc(Lbs))

Для более подробной отладки с вашей текущей функцией, что происходит, если вы делаете

ifelse(c(9, 2) <= 5, Size <- "Small", Size <- "Big")

и если вы теперь проверяете Size объект имеет

Size
#[1] "Big"

, и это значение return редактируется из вашей функции.

Вместо этого вы хотите

ifelse(c(9, 2) <= 5, Size <- "Small", Size <- "Big")
#[1] "Big"   "Small"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...