Подсчитайте новый элемент, добавленный и удаленный из предыдущей группы из фрейма данных - PullRequest
6 голосов
/ 13 июля 2020

У меня есть фрейм данных

df <- data.frame(
  "Quarter" = c("Q1 2019","Q1 2019","Q1 2019","Q2 2019","Q2 2019","Q2 2019","Q2 2019","Q3 2019","Q3 2019","Q3 2019","Q3 2019","Q4 2019","Q4 2019"),
  "Name" = c("Ram","John","Jack","Ram","Rach","Will","John","Ram","Rach","Will","John","Rach","John"),
  stringsAsFactors = FALSE
) 

Мне нужно подсчитать количество людей, которые были добавлены и оставлены в каждом квартале, сравнив его с предыдущим кварталом.

Ожидаемое вывод:

quarterYear status Count
1    Q1 2019 Added   3
2    Q1 2019 Left    0
3    Q2 2019 Added   2
4    Q2 2019 Left    1
5    Q3 2019 Added   0
6    Q3 2019 Left    0
7    Q4 2019 Added   0
8    Q4 2019 Left    2 

Я не уверен, как сравнить две группы и получить счет.

Как я могу добиться ожидаемого результата в R?

Ответы [ 4 ]

5 голосов
/ 13 июля 2020

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

tab <- table(df$Quarter, df$Name)
tab <- rbind(tab[1,,drop=FALSE], diff(tab))
out <- rbind(added = rowSums(tab == 1), left = rowSums(tab == -1))

#      Q1 2019 Q2 2019 Q3 2019 Q4 2019
#added       3       2       0       0
#left        0       1       0       2

Если вам нужен именно длинный вывод:

setNames(data.frame(as.table(out)), c("status","quarter","count"))
#  status quarter count
#1  added Q1 2019     3
#2   left Q1 2019     0
#3  added Q2 2019     2
#4   left Q2 2019     1
#5  added Q3 2019     0
#6   left Q3 2019     0
#7  added Q4 2019     0
#8   left Q4 2019     2
2 голосов
/ 13 июля 2020

Разделить, чтобы создать список и сопоставить два списка, чтобы получить длину «неравных» элементов, т.е.

l1 <- split(df$Name, df$Quarter)
do.call(rbind, Map(function(x, y) { i1 <- length(setdiff(x, y)); 
                                    i2 <- length(setdiff(y, x)); 
                                    data.frame(Added = i1, Left = i2)},
          l1[-1], l1[-length(l1)]))

#        Added Left
#Q2 2019     2    1
#Q3 2019     0    0
#Q4 2019     0    2

Вы можете привести в порядок вывод так, как хотите

1 голос
/ 13 июля 2020

Вот один из способов сохранить объем данных. Мы разбиваем данные на список фреймов данных на основе Quarter. Используя map2, мы сравниваем значения одного квартала и следующего квартала и подсчитываем количество людей, добавленных и оставленных в каждом квартале. Рассчитайте значения для первого квартала отдельно и привяжите их к исходному фрейму данных.

library(tidyverse)

list_df <- df %>% group_split(Quarter)

list_df %>%
   .[[1]] %>%
  summarise(quarterYear  = first(Quarter),
            status = c('Added', 'Left'), 
            Count = c(n(), 0)) %>%
    bind_rows(map2_df(list_df[-1], list_df[-length(list_df)], 
            ~tibble(quarterYear = .x$Quarter[1],
                    status = c('Added', 'Left'), 
                    Count = c(sum(!.x$Name %in% .y$Name), 
                              sum(!.y$Name %in% .x$Name)))))


# A tibble: 8 x 3
#  quarterYear status Count
#  <chr>       <chr>  <dbl>
#1 Q1 2019     Added      3
#2 Q1 2019     Left       0
#3 Q2 2019     Added      2
#4 Q2 2019     Left       1
#5 Q3 2019     Added      0
#6 Q3 2019     Left       0
#7 Q4 2019     Added      0
#8 Q4 2019     Left       2

Использование того же logi c в базе R:

list_df <- split(df, df$Quarter)
temp <- list_df[[1]]

rbind(data.frame(quarterYear = temp$Quarter[1], 
                 status =  c('Added', 'Left'), 
                 Count = c(nrow(temp), 0)),
   do.call(rbind, Map(function(x, y) 
      data.frame(quarterYear = x$Quarter[1],
                 status = c('Added', 'Left'), 
                 Count = c(sum(!x$Name %in% y$Name), sum(!y$Name %in% x$Name))), 
list_df[-1],list_df[-length(list_df)])))
1 голос
/ 13 июля 2020

Следующее работает: сначала столбец Name превращается в список имен с помощью Quarter, а затем сравнивается каждый квартал с предыдущим кварталом с использованием purrr::map2_int. Наконец, два добавленных столбца, Added и Left, преобразовываются в длинную форму с использованием tidyr::pivot_longer.

library(tidyverse)

df %>%
  group_by(Quarter) %>%
  summarise(names = list(Name)) %>%
  mutate(Added = map2_int(names, lag(names, default = list(list())), ~ length(setdiff(.x, .y))),
         Left = map2_int(names, lag(names, default = list(list())), ~ length(setdiff(.y, .x)))) %>%
  pivot_longer(Added:Left, names_to = "status", values_to = "Count") %>%
  select(-names)

Результат:

# A tibble: 8 x 3
  Quarter status Count
  <chr>   <chr>  <int>
1 Q1 2019 Added      3
2 Q1 2019 Left       0
3 Q2 2019 Added      2
4 Q2 2019 Left       1
5 Q3 2019 Added      0
6 Q3 2019 Left       0
7 Q4 2019 Added      0
8 Q4 2019 Left       2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...