Функция, использующая векторный индекс, а не значение во внутренних data.frame с помощью dplyr :: mutate - PullRequest
0 голосов
/ 07 декабря 2018

Проблема:

У меня есть функция, которая использует аргумент для индексации внутреннего data.frame, но возвращает целое число.Однако когда я запускаю функцию в dplyr::mutate для создания новой переменной на основе другой переменной в data.frame, я получаю сообщение об ошибке:

Error in mutate_impl(.data, dots) : 
  Evaluation error: duplicate subscripts for columns.

Это, вероятно, вызвановнутренним индексированием фрейма данных с использованием позиции индекса переменной вместо ее значения.

Как мне решить эту проблему?

Пример:

В этой функции мне нужно индексировать внутренний data.frame и использовать это при расчете результата.: unction и data:

toyfun <- function(thing1){

  thing2 <- data.frame(a = 0, b = 0, c = 0, d = 0)
  thing2[, thing1] <- 1

  thing3 <- sum(thing2[1,]) + thing1

  return(thing3)
}


toydat <- tibble(thing1 = c(4, 3, 2, 1, 1, 2))

Функция работает так, как ожидается:

toyfun(thing1 = toydat$thing1[1])
#[1] 5

Но если я хочу вычислить функцию с каждым элементом переменной в tibble или data.frame при mutate происходит сбой:

toydat %>% 
  mutate(thing4 = toyfun(thing1 = thing1))
# Error in mutate_impl(.data, dots) : 
#  Evaluation error: duplicate subscripts for columns.

Если мы просто используем первые 4 строки (или меньше) из toydat, и обратите внимание, что внутренний data.frame в toyfun имеет ширину 4 столбца , он отлично работает

toydat[1:4,] %>% 
  mutate(thing4 = toyfun(thing1 = thing1))
# # A tibble: 4 x 2
#   thing1 thing4
#    <dbl>  <dbl>
# 1      4      5
# 2      3      4
# 3      2      3
# 4      1      2

Но опять же, если мы используем 5 строк, поэтому, перебирая значение индекса внутреннего data.frame, мы снова терпим неудачу:

toydat[1:5,] %>% 
  mutate(thing4 = toyfun(thing1 = thing1))
# Error in mutate_impl(.data, dots) : 
#   Evaluation error: duplicate subscripts for columns.

Суть проблемы

Этот результат, по-видимому, иллюстрирует, что проблема заключается в том, что внутренняя индексация использует значение индекса из thing1, а не его фактическое значение.Что странно, поскольку, как показано в примере с 4 строками выше, мы можем видеть, что возвращаемые значения в thing4 являются такими, какими они должны быть при использовании значений thing1 для вычисления результата.

NB:Та же проблема не возникает с sapply:

sapply(toydat$thing1, toyfun)
# [1] 5 4 3 2 2 3

Есть какие-нибудь идеи по поводу этого в структуре типа dplyr, чтобы я мог поддерживать последовательность рабочего процесса?

1 Ответ

0 голосов
/ 07 декабря 2018

Проблема в том, что mutate отправляет весь столбец в функцию.

Давайте отладим функцию

toyfun <- function(thing1){
   browser()
   thing2 <- data.frame(a = 0, b = 0, c = 0, d = 0)
   thing2[,thing1] <- 1
   thing3 <- thing1 + 1
  return(thing3)
}

Теперь мы запускаем команду mutate

toydat %>% 
  mutate(thing4 = toyfun(thing1 = thing1))
#Called from: toyfun(thing1 = thing1)
#Browse[1]> thing1
#[1] 4 3 2 1 1 2

Поскольку в столбце 1 есть повторяющиеся записи, выдается ошибка.

Это то же самое, что и

df <- mtcars
df[, c(5, 5)] <- 1

Ошибка в [<-.data.frame (*tmp*,, c (1, 1), значение = 1): повторяющиеся индексы для столбцов

Теперь давайте посмотрим на sapply вызов

sapply(toydat$thing1, toyfun)
#Called from: FUN(X[[i]], ...)
#Browse[1]> thing1
#[1] 4

sapply передает значение одно за другим, следовательно, ошибки нет.

Это то же самое, что и

df <- mtcars
df[, 5] <- 1
df[, 5] <- 1

, который не дает никакой ошибки.

Чтобы устранить ошибку, мы можем использовать unique, чтобы получить только unique записейиз thing1

toyfun <- function(thing1){
  thing2 <- data.frame(a = 0, b = 0, c = 0, d = 0)
  thing2[,unique(thing1)] <- 1
  thing3 <- thing1 + 1
  return(thing3)
}


toydat %>% 
    mutate(thing4 = toyfun(thing1 = thing1))

# A tibble: 6 x 2
#  thing1 thing4
#   <dbl>  <dbl>
#1      4      5
#2      3      4
#3      2      3
#4      1      2
#5      1      2
#6      2      3

, и это также будет продолжать работать с sapply

sapply(toydat$thing1, toyfun)
#[1] 5 4 3 2 2 3

Если вы не хотите изменять функцию, другой вариант - использовать rowwise который работает так же, как sapply и отправляет каждое отдельное значение по одному в функцию

toydat %>% 
   rowwise() %>%
   mutate(thing4 = toyfun(thing1 = thing1))

#Called from: toyfun(thing1 = thing1)
#Browse[1]> thing1
#[1] 4

toydat %>% 
  rowwise() %>%
  mutate(thing4 = toyfun(thing1 = thing1))

#  thing1 thing4
#   <dbl>  <dbl>
#1      4      5
#2      3      4
#3      2      3
#4      1      2
#5      1      2
#6      2      3

Надеюсь, это было понятно и полезно.

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