Разверните фрейм данных, следуя наборам правил - PullRequest
2 голосов
/ 07 января 2020

У меня довольно сложная проблема, которую я не могу решить.

У меня есть кадр данных, который я прочитал в dplyr:

trans_id date       type
9373    2019-09-29  6-months 
9945    2019-08-15  3-months 
9945    2019-11-13  3-months 
9615    2019-12-28  3-months 
11465   2019-07-13  3-months 
11465   2019-10-11  3-months 

Воспроизводимый пример:

library(tidyverse)

df <- data.frame(stringsAsFactors=FALSE,
          id = c(9373, 9945, 9945, 9615, 11465, 11465),
        date = c("2019-09-29", "2019-08-15", "2019-11-13", "2019-12-28",
                 "2019-07-13", "2019-10-11"),
        type = c("6-months", "3-months", "3-months", "3-months", "3-months",
                 "3-months")) %>%
  mutate(date = as.Date(date))

Каждый id является транзакцией, произошедшей с данным date; каждая транзакция может повторяться каждые 3 месяца или 6 месяцев - как указано в type.

Я хочу развернуть эти транзакции в своих ежемесячных аналогах до текущей даты; это означает, что первая транзакция 9373 должна повторяться 6 раз с 30-дневным циклом (type == 6 месяцев), начиная с 2019-09-29 до текущего дня (сегодня 2020-01-07), иначе будет только 4 разовых ежемесячных транзакции, так как последние две должны произойти.

То же самое для 3-месячных транзакций, всегда с учетом даты начала и текущей даты.

Пример конечного результата:

id      date        type
9373    2019-09-29  6-months # first 6-months cycle transaction
9373    2019-10-29  6-months 
9373    2019-11-28  6-months 
9373    2019-12-28  6-months 
9945    2019-08-15  3-months # 
9945    2019-09-14  3-months 
9945    2019-10-14  3-months 
9945    2019-11-13  3-months #
9945    2019-12-13  3-months 
9615    2019-12-28  3-months #

Любая помощь высоко ценится !

Ответы [ 2 ]

1 голос
/ 07 января 2020

Вы можете использовать rowwise и do примерно так:

df %>% 
  rowwise() %>% 
  do({
    p <- as.numeric(gsub('\\D+','',.$type))-1
    tibble(
      id=.$id,
      date=seq(.$date,pmin(Sys.Date(),.$date+p*30),30),
      type=.$type
    )
  }) %>% 
  ungroup()

# A tibble: 16 x 3
# id date       type    
# * <dbl> <date>     <chr>   
#   1  9373 2019-09-29 6-months
# 2  9373 2019-10-29 6-months
# 3  9373 2019-11-28 6-months
# 4  9373 2019-12-28 6-months
# 5  9945 2019-08-15 3-months
# 6  9945 2019-09-14 3-months
# 7  9945 2019-10-14 3-months
# 8  9945 2019-11-13 3-months
# 9  9945 2019-12-13 3-months
# 10  9615 2019-12-28 3-months
# 11 11465 2019-07-13 3-months
# 12 11465 2019-08-12 3-months
# 13 11465 2019-09-11 3-months
# 14 11465 2019-10-11 3-months
# 15 11465 2019-11-10 3-months
# 16 11465 2019-12-10 3-months
1 голос
/ 07 января 2020

Это один из способов использования функций dplyr и tidyr.

library(dplyr)
library(tidyr)

df %>%
  #Extract the number from type column
  mutate(num = readr::parse_number(type)) %>%
  #For each transcation
  group_by(row = row_number()) %>%
  #Create a sequence from date till number of months with a break of 30 days
  complete(id, type, date = seq(date, by = "30 days", length.out = num)) %>%
  #Remove rows which have date value greater than today
  filter(date <= Sys.Date()) %>%
  ungroup() %>%
  select(-num, -row)

# A tibble: 16 x 3
#      id type     date      
#   <dbl> <chr>    <date>    
# 1  9373 6-months 2019-09-29
# 2  9373 6-months 2019-10-29
# 3  9373 6-months 2019-11-28
# 4  9373 6-months 2019-12-28
# 5  9945 3-months 2019-08-15
# 6  9945 3-months 2019-09-14
# 7  9945 3-months 2019-10-14
# 8  9945 3-months 2019-11-13
# 9  9945 3-months 2019-12-13
#10  9615 3-months 2019-12-28
#11 11465 3-months 2019-07-13
#12 11465 3-months 2019-08-12
#13 11465 3-months 2019-09-11
#14 11465 3-months 2019-10-11
#15 11465 3-months 2019-11-10
#16 11465 3-months 2019-12-10
...