Функция распределения по списку сгруппированных идентификаторов - PullRequest
0 голосов
/ 09 декабря 2018

У меня есть фрейм данных с идентификатором, датой начала, даты окончания и значениями дохода и стоимости.

table <- data.frame(id = c(1, 2, 3),
               start = c("2018-01-01", "2018-02-05", "2018-05-30"),
               end = c("2018-01-31", "2018-03-26", "2018-08-31"),
               income = c(100, 225, 399),
               costs = c(37, 98, 113))

table$start <- as.Date(table$start)
table$end <- as.Date(table$end)

Что приводит к:

  id      start        end income costs
  1 2018-01-01 2018-01-31    100    37
  2 2018-02-05 2018-03-26    225    98
  3 2018-05-30 2018-08-31    399   113

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

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

Я ожидаю получить следующую таблицу:

  id   date      income      costs
  1   2018-01    100         37
  2   2018-02    108         47.04
  2   2018-03    117         50.96
  3   2018-05    8.489362    2.404255
  3   2018-06    127.340426  36.063830
  3   2018-07    131.585106  37.265957
  3   2018-08    131.585106  37.265957

Я попытался использовать rbindlist над списком фреймов данных, созданных идентификатором, и следующей функцией:

explode <- function(start, end, income) {
              dates <- seq(start, end, "day")
              n <- length(dates)
              rowsum(rep(income, n) / n, format(dates, "%Y-%m"))                  
}

  Map(explode, table$start, table$end, table$income)

Но, конечно, он возвращает только значения строки и внутри безымянного списка.

ЛюбойПомощь будет очень ценится.Спасибо!

Ответы [ 2 ]

0 голосов
/ 09 декабря 2018

Ваше решение могло бы сработать.Просто добавьте новый параметр к Map и расширьте свою функцию с помощью cbind, чтобы объединить доход и расходы , затем rbind список, сгенерированный из Map:

explode <- function(start, end, income, costs) {
  dates <- seq(start, end, "day")
  n <- length(dates)
  cbind.data.frame(
    date = format(start, "%Y-%m"),
    income = rowsum(rep(income, n) / n, format(dates, "%Y-%m")),
    costs = rowsum(rep(costs, n) / n, format(dates, "%Y-%m")) 
  )
}

data_list <- Map(explode, table$start, table$end, table$income, table$costs)
final_df <- do.call(rbind, data_list)

final_df    
#    date     income     costs
# 2018-01 100.000000 37.000000
# 2018-02 108.000000 47.040000
# 2018-03 117.000000 50.960000
# 2018-05   8.489362  2.404255
# 2018-06 127.340426 36.063830
# 2018-07 131.585106 37.265957
# 2018-08 131.585106 37.265957
0 голосов
/ 09 декабря 2018

Я бы пошел на data.table:

library(data.table)

table_aggregated <- setDT(table)[
  , .(id = id, income = income, costs = costs, day_var = seq(start, end, "day")), by = 1:nrow(table)][
    , `:=` (income_day = income / .N, 
            costs_day = costs / .N,
            date = format(day_var, "%Y-%m")), by = id][
              , .(income = sum(income_day),
                  costs = sum(costs_day)), by = .(id, date)]

Вывод:

   id    date     income     costs
1:  1 2018-01 100.000000 37.000000
2:  2 2018-02 108.000000 47.040000
3:  2 2018-03 117.000000 50.960000
4:  3 2018-05   8.489362  2.404255
5:  3 2018-06 127.340426 36.063830
6:  3 2018-07 131.585106 37.265957
7:  3 2018-08 131.585106 37.265957
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...