dplyr сворачивает «хвостовые» ряды в большие группы - PullRequest
0 голосов
/ 10 ноября 2018
library(tidyverse)
df <- tibble(a = as.factor(1:20), b = c(50, 20, 13, rep(2, 10), rep(1, 7)))

Как мне заставить dplyr посмотреть на этот фрейм данных df и свести все эти вхождения 2 в одну суммированную группу, а все вхождения 1 в одну суммированную группу? А также сохраните оставшуюся часть фрейма данных.

Включите это:

# A tibble: 20 x 2
   a         b
   <fct> <dbl>
 1 1        50
 2 2        20
 3 3        13
 4 4         2
 5 5         2
 6 6         2
 7 7         2
 8 8         2
 9 9         2
10 10        2
11 11        2
12 12        2
13 13        2
14 14        1
15 15        1
16 16        1
17 17        1
18 18        1
19 19        1
20 20        1

в это:

# A tibble: 5 x 2
   a         b
   <fct> <dbl>
 1 1        50
 2 2        20
 3 3        13
 4 grp2     20
 5 grp1      7

[Edit] - я исправил пример данных. Извините за это.

Ответы [ 3 ]

0 голосов
/ 10 ноября 2018

Это подход, который дает вам желаемые имена для групп, и вам не нужно заранее думать, сколько таких случаев вам понадобится (например, это создаст grp3, grp4, ... в зависимости от числа в b).

library(dplyr)

df %>%
  mutate(
    grp = as.numeric(lag(df$b) != df$b),
    grp = cumsum(ifelse(is.na(grp), 0, grp))
  ) %>% group_by(grp) %>%
  mutate(
    a = ifelse(n() > 1, paste0("grp", b), a),
    b = sum(b)
  ) %>% ungroup() %>% distinct(a, b)

Выход:

  a         b
  <chr> <dbl>
1 1        50
2 2        20
3 3        13
4 grp2     20
5 grp1      7

Обратите внимание, что код также может быть сжатым, но это, по моему мнению, приводит к некоторой недостаточной читаемости:

df %>%
  group_by(grp = cumsum(ifelse(is.na(as.numeric(lag(df$b) != df$b)), 0, as.numeric(lag(df$b) != df$b)))) %>%
  mutate(
    a = ifelse(n() > 1, paste0("grp", b), a),
    b = sum(b)
  ) %>% ungroup() %>% distinct(a, b)
0 голосов
/ 10 ноября 2018

Мы группируем по произведенному sortkey для поддержания порядка сортировки. Мы использовали тот факт, что b находится в порядке убывания во входных данных, но если это не так в ваших фактических данных, то замените sortkey = -b на более общий sortkey = data.table::rleid(b) или более длинный sortkey = cumsum(coalesce(b != lag(b), FALSE)).

Мы также конвертируем b в имена групп, получая новые a. Не было ясно, какие группы должны быть преобразованы в grp ... форму. Жестко закодированы 1 и 2? Любая группа с более чем одной строкой? Группы в конце с более чем одной строкой? Во всяком случае, было бы достаточно легко изменить условие в if_else, как только оно будет прояснено.

Наконец, выполните суммирование и затем удалите sortkey.

df %>% 
  group_by(sortkey = -b, a = paste0(if_else(b %in% 1:2, "grp", ""), b)) %>%
  summarize(b = sum(b)) %>%
  ungroup %>%
  select(-sortkey)

дает:

# A tibble: 5 x 2
  a         b
  <chr> <int>
1 50       50
2 20       20
3 13       13
4 grp2     20
5 grp1      7
0 голосов
/ 10 ноября 2018

Вот способ. Я преобразовал a из фактора в персонажа, чтобы все было проще. Вы можете преобразовать его обратно в коэффициент, если хотите. Также ваши тестовые данные были немного неправильными.

df <- tibble(a = as.character(1:20), b = c(50, 20, 13, rep(2, 10), rep(1, 7)))

df %>% 
  mutate(
    a = case_when(
      b == 1 ~ "grp1",
      b == 2 ~ "grp2",
      TRUE ~ a
    )
  ) %>% 
  group_by(a) %>% 
  summarise(b = sum(b))

# A tibble: 5 x 2
  a         b
  <chr> <dbl>
1 1        50
2 2        20
3 3        13
4 grp1      7
5 grp2     20
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...