Разделить все числовые столбцы на общий коэффициент; разный коэффициент для разных групп строк

#r #dictionary #dplyr #purrr

#r #словарь #dplyr #мурлыканье

Вопрос:

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

Репрезентативный пример — с iris набором данных, если бы я хотел разделить все числовые столбцы для каждого Species на другой коэффициент, например

  1. Установить значение на 1
  2. Разноцветный на 10
  3. Virginica на 100

Пробовал разделить, затем объединить — предоставить список факторов; разделить iris список наборов данных фреймов данных по группам, сопоставить по обоим входам, затем рекомбинировать — но я не могу правильно отобразить карту

 map_dfr(list(1,10,100), ~
              iris %>% 
              group_split(Species) %>% 
              mutate(across(where(is.numeric), ~x / .x)))

Error in UseMethod("mutate_") : 
  no applicable method for 'mutate_' applied to an object of class "c('vctrs_list_of', 'vctrs_vctr', 'list')"
  

Или использовать map2 для двух входных данных списка:

 map2(x = iris %>% group_split(Species),
     y = list(1,10,100), 
     function(x,y)
       mutate(across(where(is.numeric), .x / .y)))

Error: unexpected ')' in "       mutate(across(where(is.numeric), .x / .y)))"

  

Ответ №1:

Вот рабочая версия с map2 :

 map2(.x = iris %>% group_split(Species),
     .y = list(1,10,100), 
     function(x, div) {
       mutate(x, across(where(is.numeric), ~ .x / div))
      })
  

Основное изменение заключается в том, что mutate() требуется, чтобы фрейм данных был его первым аргументом, следовательно mutate(x, ...) . Я также переименовал y в div , чтобы избежать путаницы. У нас есть 2 анонимные функции… function(x, div) означает, что у нас есть аргумент x , который является фреймом данных, и div который является каждым делителем. Мы передаем x в mutate , а затем вторая анонимная функция (использующая ~ обозначение) нуждается в использовании .x по умолчанию (для числовых столбцов), но должна использовать div , поскольку она находится внутри (x, div) функции.

Мне не очень нравится приведенный выше код, потому что он полагается на то, что .y список находится в том же порядке, что и group_split группы. Если бы это был мой код, я бы, вероятно, сделал это с помощью справочной таблицы и вместо этого объединил, что безопаснее, потому что связь между видами и делителем теперь понятна и проверяема.

 div = tribble(
  ~Species, ~factor,
  "setosa", 1,
  "versicolor", 10,
  "virginica", 100
)

iris %>% 
  left_join(div) %>%
  mutate(across(where(is.numeric), ~.x / factor)) %>%
  select(-factor)
  

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

1. Спасибо @gregor-thomas, это превосходно — согласитесь, что простой left_join / mutate — это более чистый код, меньше шансов на ошибку при сопоставлении неправильного коэффициента с неправильным подмножеством данных и метод, который я буду использовать. Я был слишком ориентирован на карту — свежий взгляд всегда полезен 🙂 И спасибо за объяснение map2 вызова, сортировки x из .x анонимных функций, на случай, если я использую его или подобное в будущем.