2017-02-10 12 views
0

С приведенными ниже данными я хочу расширить строки или каждый уровень фактора IndID, чтобы было столько строк, сколько существует между CptrDt и MortDt, включая начиная и с конца года. Для физических лиц без MortDt я надеюсь заполнить года последовательные в 2017.Развернуть строки кадра данных по диапазону дат с значениями NA

dat <- data.frame(IndID = c("AAA","BBB","CCC"), 
       CptrDt = as.Date(c("01-01-2013" ,"01-01-2013", "01-01-2014"),"%m-%d-%Y"), 
       MortDt = as.Date(c("01-01-2015" ,"01-01-2016", NA),"%m-%d-%Y")) 

> dat 
    IndID  CptrDt  MortDt 
1 AAA 2013-01-01 2015-01-01 
2 BBB 2013-01-01 2016-01-01 
3 CCC 2014-01-01  <NA> 

Упрощенный результат будет возвращать только год, как показано ниже, но я могу работать с другими форматами дата.

Result <- data.frame(IndID = c(rep("AAA",3), rep("BBB",4), rep("CCC",4)), 
       Year = c(2013,2014,2015,2013,2014,2015,2016,2014,2015,2016,2017)) 

    IndID Year 
1 AAA 2013 
2 AAA 2014 
3 AAA 2015 
4 BBB 2013 
5 BBB 2014 
6 BBB 2015 
7 BBB 2016 
8 CCC 2014 
9 CCC 2015 
10 CCC 2016 
11 CCC 2017 

Я понимаю, этот вопрос очень похож на previous post, но учитывая наличие значений NA и несколько иной структуры данных, я не был способен производить желаемый результат с предыдущим ответом, и оценил бы все предложения , Более того, как видно из опубликованных ответов, есть дополнительные решения.

+2

Вы можете использовать колонку списка или 'do':' библиотека (tidyverse); dat%>% group_by (INDID)%>% mutate (MortDt = coalesce (MortDt, Sys.Date()), Year = seq (CptrDt, MortDt, by = 'year')%>% lubridate :: year()% >% list())%>% unnest() ' – alistaire

+0

или с' purrr :: by_slice': 'dat%>% group_by (INDID)%>% mutate_if (lubridate :: is.Date, coalesce, Sys.Date ())%>% by_slice (~ seq (.x $ CptrDt, .x $ MortDt, by = 'year')%>% lubridate :: year(), .collate = 'rows', .to = 'year') ' – alistaire

ответ

2

1- Используя gsub, получите год из каждой строки и сформируйте его последовательность. Затем используйте expand.grid, чтобы развернуть значение IndID с указанной выше последовательностью. Наконец rbind список кадров данных в один фрейм данных.

dat[is.na(dat$CptrDt), "CptrDt"] <- as.Date("01-01-2017", "%m-%d-%Y") 
dat[is.na(dat$MortDt), "MortDt"] <- as.Date("01-01-2017", "%m-%d-%Y") 

do.call('rbind', apply(dat, 1, function(x) { 
              pattern <- '([0-9]{4})-[0-9]{2}-[0-9]{2}'; 
              y <- as.numeric(gsub(pattern, '\\1', x[2:3])); 
              expand.grid(IndID = x[1], 
                  Year = seq(y[1], y[2], by = 1)) 
              })) 

# IndID Year 
# 1 AAA 2013 
# 2 AAA 2014 
# 3 AAA 2015 
# 4 BBB 2013 
# 5 BBB 2014 
# 6 BBB 2015 
# 7 BBB 2016 
# 8 CCC 2014 
# 9 CCC 2015 
# 10 CCC 2016 
# 11 CCC 2017 

2- Использование format на основе предложения в комментарии ниже.

dat[is.na(dat$CptrDt), "CptrDt"] <- as.Date("01-01-2017", "%m-%d-%Y") 
dat[is.na(dat$MortDt), "MortDt"] <- as.Date("01-01-2017", "%m-%d-%Y") 

dat$CptrDt <- format(dat$CptrDt, "%Y") 
dat$MortDt <- format(dat$MortDt, "%Y") 

do.call('rbind', apply(dat, 1, function(x) { expand.grid(IndID = x[1], 
                  Year = seq(as.numeric(x[2]), as.numeric(x[3]), by = 1)) })) 

данных:

dat <- data.frame(IndID = c("AAA","BBB","CCC"), 
        CptrDt = as.Date(c("01-01-2013" ,"01-01-2013", "01-01-2014"),"%m-%d-%Y"), 
        MortDt = as.Date(c("01-01-2015" ,"01-01-2016", NA),"%m-%d-%Y")) 
+2

Не используйте регулярное выражение для анализа даты; просто используйте 'format' с'% Y'. – alistaire

+0

@alistaire благодарит за комментарий. Я добавил его в ответ – Sathish

 Смежные вопросы

  • Нет связанных вопросов^_^