R Подсчет непрерывного номера переменной даты по id - PullRequest
0 голосов
/ 11 октября 2018

У меня есть такая база данных:

dat = data.frame(id = c(rep("Adam", 5), rep("Bob", 10)), 
                 card_id = c(rep("0001", 2), rep("0002", 3), rep("0003", 5), rep("0004", 5)), 
                 bill_date = c("2017-01", "2017-02", 
                               "2017-01", "2017-02", "2017-03", 
                               "2017-01", "2017-02", "2017-03", "2017-05", "2017-06", 
                               "2017-01", "2017-02", "2017-03", "2017-04", "2017-05"), stringsAsFactors = F)

#      id card_id bill_date
# 1  Adam    0001   2017-01
# 2  Adam    0001   2017-02
# 3  Adam    0002   2017-01
# 4  Adam    0002   2017-02
# 5  Adam    0002   2017-03
# 6   Bob    0003   2017-01
# 7   Bob    0003   2017-02
# 8   Bob    0003   2017-03
# 9   Bob    0003   2017-05
# 10  Bob    0003   2017-06
# 11  Bob    0004   2017-01
# 12  Bob    0004   2017-02
# 13  Bob    0004   2017-03
# 14  Bob    0004   2017-04
# 15  Bob    0004   2017-05

Я хочу получить максимальный номер непрерывного счета для каждого card_id для каждого id.

Ожидаемый результат:

#      id card_id max_cont_bill_num
# 1  Adam    0001                 2
# 2  Adam    0002                 3
# 3   Bob    0003                 3
# 4   Bob    0004                 5

Ответы [ 3 ]

0 голосов
/ 11 октября 2018
dat %>% mutate(numb=as.integer(gsub("^[0-9]*-","",bill_date))) %>% 
  group_by(id, card_id) %>% summarize(maxc=numb[sum(numb==numb[1]:(numb[n()]+numb[1]-1))])

Результат:

# A tibble: 4 x 3
# Groups:   id [?]
  id    card_id  maxc
  <chr> <chr>   <int>
1 Adam  0001        2
2 Adam  0002        3
3 Bob   0003        3
4 Bob   0004        5

Объяснение: mutate создает столбец только с номерами месяцев.Затем мы группируем по id и card_id и создаем сводку, которая сравнивает вектор чисел в группе с вектором равной длины, который начинается с первого месяца в группе до последнего, суммирует все случаи, когдаответ «ИСТИНА», а затем возвращает число в строке, соответствующее этой сумме (т. е. последнее число, которое было последовательным).

Примечание: это будет прервано, когда bill_date охватывает более одного года непрерывно.


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

Во-первых, новые данные, содин случай, охватывающий два года:

dat = data.frame(id = c(rep("Adam", 5), rep("Bob", 10)), 
                  card_id = c(rep("0001", 2), rep("0002", 3), rep("0003", 5), rep("0004", 5)), 
                  bill_date = c("2017-01", "2017-02", 
                                "2017-12", "2018-01", "2018-03", 
                                "2017-01", "2017-02", "2017-03", "2017-05", "2017-06", 
                                "2017-01", "2017-02", "2017-03", "2017-04", "2017-05"), stringsAsFactors = F)

Теперь мы изменим дату счета на фактические даты и используем cut.POSIXt, чтобы создать последовательность месяцев, и применим предыдущее решение к этой последовательности:

dat$monthseq<-cut.POSIXt(as.POSIXct(paste0(dat$bill_date,"-01")),breaks="month",labels=FALSE)
dat%>% 
  group_by(id, card_id) %>% 
  summarize(maxc=bill_date[sum(monthseq==monthseq[1]:(monthseq[n()]))])

Результат:

# A tibble: 4 x 3
# Groups:   id [?]
  id    card_id maxc   
  <chr> <chr>   <chr>  
1 Adam  0001    2017-02
2 Adam  0002    2018-01
3 Bob   0003    2017-03
4 Bob   0004    2017-05
0 голосов
/ 11 октября 2018

Прошу прощения, я не прочитал ответ ОП достаточно внимательно в первый раз.

library(tidyverse); library(lubridate)
dat %>%
  # new group for each gap in time series or new id / card_id
  mutate(date = ymd(bill_date,truncated = 2),
         gap = id  != lag(id, default = "") | 
           card_id != lag(card_id, default = "") |
              date != lag(date) %m+% months(1),
         group = cumsum(gap)) %>%
  # How many in each group?
  count(id, card_id, group) %>%
  # Just keep each id / card_id's longest streak
  group_by(id, card_id) %>%
  top_n(1, wt = n)
0 голосов
/ 11 октября 2018

Мы можем попробовать с difftime и rle.Создайте функцию для преобразования 'bill_date' в Date, класс, получите разницу между соседними датами, преобразуйте в целое число, затем получите идентификатор длины бега значений, выберите максимальное значение length.Примените эту функцию после группировки по 'id', 'card_id'

f1 <- function(x)  {
                x1 <- as.Date(paste0(x, "-01") )
                x2 <- as.integer(difftime(x1[-1], x1[-length(x1)], unit = "weeks"))
                  max(rle(c(x2[1], x2))$lengths) 
                  }

dat %>% 
   group_by(id, card_id) %>%
    summarise(max_count = f1(bill_date))        
# A tibble: 4 x 3
# Groups:   id [?]
#  id    card_id max_count
#  <chr> <chr>       <int>
#1 Adam  0001            2
#2 Adam  0002            3
#3 Bob   0003            3
#4 Bob   0004            5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...