Dplyr: эффективный способ работы с подмножеством / конкретными строками без изменения остальной части набора данных - PullRequest
0 голосов
/ 26 сентября 2019

Давайте возьмем следующий набор данных:

df <- tibble(
  id = 1:5,
  location = rep(paste0("country", 1:2), each = 3, len = 5),
  species = paste0("species", 1:3)[rep(c(1, 1, 2, 3, 3))],
  min = c(0, 100, 0, 100, 100),
  max = c(500, 600, 700, 1100, 1100)
)

# A tibble: 5 x 5
     id location species    min   max
  <int> <chr>    <chr>    <dbl> <dbl>
1     1 country1 species1     0   500
2     2 country1 species1   100   600
3     3 country1 species2     0   700
4     4 country2 species3   100  1100
5     5 country2 species3   100  1100

Я хотел бы объединить строки с одинаковыми названиями видов для определенного местоположения, скажем, country1, но сохранив самые низкие min и самые высокие max значения дубликатов названий видов.

В этом примере желаемый результат будет:

# A tibble: 4 x 5
     id location species    min   max
  <int> <chr>    <chr>    <dbl> <dbl>
1     1 country1 species1     0   600
2     3 country1 species2     0   700
3     4 country2 species3   100  1100
4     5 country2 species3   100  1100

То, как я обычно это делаю, будет примерно таким:

country1 <- df %>% 
  filter(location == "country1") %>% 
  group_by(location, species) %>% 
  mutate(
    min = min(min),
    max = max(max)
  ) %>% 
  distinct(species, .keep_all = TRUE) %>% 
  ungroup

df %<>% 
  filter(location != "country1") %>% 
  bind_rows(country1)

> df
# A tibble: 4 x 5
     id location species    min   max
  <int> <chr>    <chr>    <dbl> <dbl>
1     4 country2 species3   100  1100
2     5 country2 species3   100  1100
3     1 country1 species1     0   600
4     3 country1 species2     0   700

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

Я пытался filter(location == "country1", .preserve = TRUE) сохранить все строки в наборе данных, но я не работал.Я также думал об использовании оператора if_else в mutate(), чтобы получить значения min и max для каждого вида в country1.Но тогда мне нужно было бы использовать distinct() только в строках с местоположением country1, что я не знаю, как это сделать.

В идеале я хотел бы работать с временным подмножеством из df, где я могу выполнять все необходимые операции, не затрагивая весь набор данных.

Любая идея сделать то, что я хочу, более простым способом?

1 Ответ

0 голосов
/ 26 сентября 2019

Это работает с вашими примерами данных и приводит к выводу в конце:

library(dplyr)
df %>%
  group_by(location,species) %>%
  summarise(min = min(min), max = max(max))

Редактировать после обновления:

Чтобы сократить рабочий процесс, я могу придумать два варианта:

  1. Преобразование данных на месте:

Вместо внешнего сохранения данных вы можете просто изменить их на месте следующим образом:

df %>%
filter(location !="country1") %>%
bind_rows((df %>% filter(location ==...)), by = "location") # replace ... with full transformation from above
Использование функции

Эта стратегия становится еще более эффективной, если ее объединить с функцией, например:

merge_rows <- function(df,target){
df %>%
filter(location == target) %>% 
  group_by(location, species) %>% 
  mutate(
    min = min(min),
    max = max(max)
  ) %>% 
  distinct(species, .keep_all = TRUE) %>% 
  ungroup
}

df %>%
filter(location !="country1") %>%
bind_rows((merge_rows(df), by = "location") 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...