2016-08-31 3 views
2

Ниже приведены входные и выходные данные. Я хочу преобразовать фрейм данных из формата ввода в формат вывода.Создание дат между двумя датами в dataframe

На данный момент я написал код. он выполняет свою работу. но я думаю, что это очень неэффективно. есть ли лучшие пакеты или функции, которые могут справиться с этим?

mycode:

#create a output data frame to be apended later 
output = data.frame(id1 = character(0), id2 = character(0), dates = character(0)) 

# for loop to get all possible combiation of dates 

for (i in c(1:nrow(input))) { 
    end = as.Date('2016-07-18') 
    len = as.numeric(end-input$min_date[i]) 
    output = rbind(output, as.data.frame(cbind(
    pid = rep(input$id1[i],len), 
    cid = rep(input$id2[i],len), 
    dates = as.character(seq(input$min_date[i], end, by='day')) 
) 
) 
) 

}

Входной сигнал:

+------+--------+------------+------------+ 
| id1 | id2 | min_date | max_date | 
+------+--------+------------+------------+ 
| 3575 | 155443 | 2012-06-18 | 2016-07-18 | 
| 3575 | 155450 | 2012-06-12 | 2016-07-18 | 
+------+--------+------------+------------+ 

выход:

+------+--------+------------+ 
| id1 | id2 | dates | 
+------+--------+------------+ 
| 3575 | 155443 | 2012-06-18 | 
| 3575 | 155443 | 2012-06-19 | 
| 3575 | 155443 | 2012-06-20 | 
| 3575 | 155443 | ..   | 
| 3575 | 155443 | …   | 
| 3575 | 155443 | 2016-07-18 | 
|  |  |   | 
| 3575 | 155450 | 2012-06-12 | 
| 3575 | 155450 | 2012-06-13 | 
| 3575 | 155450 | 2012-06-14 | 
| 3575 | 155450 | …   | 
| 3575 | 155450 | …   | 
| 3575 | 155450 | 2016-07-18 | 
+------+--------+------------+ 

ответ

2

Предполагая, что 'min_date/max_date' столбцы Date сл ass, мы используем Map, чтобы получить последовательность каждого «min_date» с соответствующим «max_date» в list, реплицировать последовательность строк «df1» на количество строк элементов list, создать data.frame путем расширения набора данных на основе «i1» и получить «даты» создания, объединяя «lst» элементы.

lst <- Map(function(x, y) seq(x,y, by = "1 day"), df1$min_date, df1$max_date) 
i1 <- rep(1:nrow(df1), lengths(lst)) 
data.frame(df1[i1,-3], dates = do.call("c", lst)) 

Или, если мы используем dplyr

library(dplyr) 
df1 %>% 
    rowwise() %>% 
    do(data.frame(.[1:2], date = seq(.$min_date, .$max_date, by = "1 day"))) 

или с помощью data.table, мы можем сделать это в одной строке кода

library(data.table) 
setDT(df1)[,.(date = seq(min_date, max_date, by = "1 day")) ,.(id1, id2)] 
1

Вы можете использовать dplyr и splitstackshape,

library(dplyr) 
library(splitstackshape) 
df %>% 
    group_by(id1, id2) %>% 
    mutate(dates = paste(seq(as.Date(min_date),as.Date(max_date),by = 1), collapse = ',')) %>% 
    select(-c(min_date, max_date)) %>% 
    cSplit('dates', ',', 'long') 
Смежные вопросы