Математические операции между группами с dplyr и tidyr - PullRequest
0 голосов
/ 04 марта 2020

Когда у меня есть аккуратные данные, подобные этому фиктивному примеру:

    structure(list(year = c(2017L, 2018L, 2019L, 2020L, 2017L, 2018L, 
2019L, 2020L), figure = c("income", "income", "income", "income", 
"expenses", "expenses", "expenses", "expenses"), value = c(10, 
11, 10, 13, 5, 4, 4, 4)), row.names = c(NA, -8L), .Names = c("year", 
"figure", "value"), class = "data.frame")

, то есть:

  year   figure value
1 2017   income    10
2 2018   income    11
3 2019   income    10
4 2020   income    13
5 2017 expenses     5
6 2018 expenses     4
7 2019 expenses     4
8 2020 expenses     4

, и я хочу рассчитать прибыль за каждый год (доходы - расходы), Я использую следующий подход:

temp %>% 
spread(figure, value) %>% 
mutate(profit = income - expenses) %>% 
gather(figure, value, -year)

и вывод:

   year   figure value
1  2017 expenses     5
2  2018 expenses     4
3  2019 expenses     4
4  2020 expenses     4
5  2017   income    10
6  2018   income    11
7  2019   income    10
8  2020   income    13
9  2017   profit     5
10 2018   profit     7
11 2019   profit     6
12 2020   profit     9

Я изменяю таблицу на широкую, я делаю операцию между столбцами, а затем я изменяю данные на длинные снова форматировать.

Есть ли способ с group_by() сделать то же самое, но без перехода к широкоформатному, а затем к длинному формату?

РЕДАКТИРОВАТЬ:

II имеют следующие data.frame:

temp <- structure(list(year = c(2017L, 2018L, 2019L, 2020L, 2017L, 2018L, 
2019L, 2020L, 2017L, 2018L, 2019L, 2020L, 2017L, 2018L, 2019L, 
2020L), figure = c("income", "income", "income", "income", "expenses", 
"expenses", "expenses", "expenses", "income", "income", "income", 
"income", "expenses", "expenses", "expenses", "expenses"), value = c(10, 
11, 10, 13, 5, 4, 4, 4, 10, 11, 10, 13, 5, 4, 4, 4), company = c("A", 
"A", "A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", 
"B", "B")), .Names = c("year", "figure", "value", "company"), row.names = c(NA, 
-16L), class = "data.frame")

и я:

temp %>% 
  filter(company == "A") %>% 
  group_by(year, company) %>% 
  summarise(value = value[figure == 'income'] - value[figure == 'expenses'], 
           figure = 'profit') %>%
  bind_rows(temp, .)

Окончательный вывод содержит компанию " А »и компания« Б », а на выходе должно быть только« Б ». Пример показывает, что связывание с исходным data.frame не является хорошей идеей, если мы изменим данные, прежде чем делать сводку.

1 Ответ

1 голос
/ 04 марта 2020

Для каждого year вы можете вычесть "income" value со значением "expenses" и связать результат с исходным кадром данных.

library(dplyr)

df %>%
  group_by(year) %>%
  summarise(value = value[figure == 'income'] - value[figure == 'expenses'], 
            figure = 'profit') %>%
  bind_rows(df, .)

#   year   figure value
#1  2017   income    10
#2  2018   income    11
#3  2019   income    10
#4  2020   income    13
#5  2017 expenses     5
#6  2018 expenses     4
#7  2019 expenses     4
#8  2020 expenses     4
#9  2017   profit     5
#10 2018   profit     7
#11 2019   profit     6
#12 2020   profit     9

Мы также можем использовать diff чтобы вычесть значения после упорядочивания данных на year и figure.

df %>%
  arrange(year, figure) %>%
  group_by(year) %>%
  summarise(value = diff(value),
            figure = 'profit') %>%
  bind_rows(df, .)
...