2015-02-12 3 views
3

У меня есть dataframe, который выглядит следующим образом:Как расширить данные, прежде чем изменить в R

as.is <- data.frame(Project = c('Proj A', 'Proj B', 'Proj C', 'Proj D'), 
       Start.Date = c('16.02.2015', '02.03.2015', '16.02.2015', '09.03.2015'), 
       Duration = c(3, 2, 2, 4), 
       No.Of.Resources = c(3, 5, 2, 6)) 

Мне нужно изменить формат, так это выглядит следующим образом:

to.be <- data.frame(Project = c('Proj A', 'Proj B', 'Proj C', 'Proj D'), 
       '16.02.2015' = c(3, NA, 2, NA), 
       '23.02.2015' = c(3, NA, 2, NA), 
       '02.03.2015' = c(3, 5, NA, NA), 
       '09.03.2015' = c(NA, 5, NA, 6), 
       '16.03.2015' = c(NA, NA, NA, 6), 
       '23.03.2015' = c(NA, NA, NA, 6), 
       '30.03.2015' = c(NA, NA, NA, 6)) 

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

Каков правильный способ для решения этой проблемы?

редактировать: Для того, чтобы уточнить, Продолжительность количество недель, так что мне нужно генерировать столбцы с названиями х, х + 7, х + 14 ...

+0

Как бы вы хотели, чтобы рассматривать записи с повторяющимися датами (например, строки 1,3 в 'as.is') ? –

+0

@ Марат Талыпов В одном столбце. Я предположил, что я буду делать какой-то расплав, чтобы получить данные в длинном формате и броском, чтобы распространить его, что приведет к объединению нескольких ссылок. – Pyrosopher

ответ

5

Вот такой подход, который, кажется, работает. Он использует expandRows и getanID из моего пакета «splitstackshape», а затем dcast.data.table от «data.table» для распространения значений в широком виде:

as.is$Start.Date <- as.Date(as.character(as.is$Start.Date), "%d.%m.%Y") 

library(splitstackshape) 
dcast.data.table(
    getanID(
    expandRows(as.is, "Duration"), 
    c("Project", "Start.Date"))[ 
     , Start.Date := Start.Date + (.id-1) * 7], 
    Project ~ Start.Date, value.var = "No.Of.Resources") 
# Project 2015-02-16 2015-02-23 2015-03-02 2015-03-09 2015-03-16 2015-03-23 2015-03-30 
# 1: Proj A   3   3   3   NA   NA   NA   NA 
# 2: Proj B   NA   NA   5   5   NA   NA   NA 
# 3: Proj C   2   2   NA   NA   NA   NA   NA 
# 4: Proj D   NA   NA   NA   6   6   6   6 

Это тот случай, когда «dplyr» делает для более хорошего чтения решения:

library(splitstackshape) 
library(dplyr) 
library(tidyr) 

as.is$Start.Date <- as.Date(as.character(as.is$Start.Date), "%d.%m.%Y") 
expandRows(as.is, "Duration") %>%     # expand the data 
    getanID(c("Project", "Start.Date")) %>%   # add an "id" column 
    mutate(Start.Date = Start.Date + (.id-1) * 7) %>% # recalculate start dates 
    select(-.id) %>%         # drop the "id" column 
    spread(Start.Date, No.Of.Resources)    # reshape long to wide 
1

Я рекомендую использовать tidyr пакет вместо reshape2 , Хотя tidyr импортирует reshape2 для выполнения некоторых операций, я считаю, что это следует считать его преемником.

# Convert to Date class to sort the columns correctly 
as.is$Start.Date <- as.Date(as.character(as.is$Start.Date), "%d.%m.%Y") 

intermediate <- with(as.is, data.frame(
    Project = rep(Project, Duration), 
    Date = rep(Start.Date, Duration) + 
      7*(unlist(lapply(Duration, seq_len))-1), 
    No.Of.Resources = rep(No.Of.Resources, Duration) 
)) 

require(tidyr) 
result <- spread(intermediate, Date, No.Of.Resources) 

Глядя на результат вы получите

Project 2015-02-16 2015-02-23 2015-03-02 2015-03-09 2015-03-16 2015-03-23 
1 Proj A   3   3   3   NA   NA   NA 
2 Proj B   NA   NA   5   5   NA   NA 
3 Proj C   2   2   NA   NA   NA   NA 
4 Proj D   NA   NA   NA   6   6   6 
    2015-03-30 
1   NA 
2   NA 
3   NA 
4   6 

Вызов dput(result) на него производит то, что вы просите

structure(list(
    Project = structure(1:4, .Label = c("Proj A", "Proj B", "Proj C", "Proj D"), class = "factor"), 
    `2015-02-16` = c(3, NA, 2, NA), 
    `2015-02-23` = c(3, NA, 2, NA), 
    `2015-03-02` = c(3, 5, NA, NA), 
    `2015-03-09` = c(NA, 5, NA, 6), 
    `2015-03-16` = c(NA, NA, NA, 6), 
    `2015-03-23` = c(NA, NA, NA, 6), 
    `2015-03-30` = c(NA, NA, NA, 6)), 
    .Names = c("Project", "2015-02-16", "2015-02-23", "2015-03-02", "2015-03-09", "2015-03-16", "2015-03-23", "2015-03-30"), 
    class = "data.frame", row.names = c(NA, 4L)) 
+0

@Backlin Да. Моя проблема заключается в том, что продолжительность означает, что проект будет длиться х недель с даты начала. Если бы это была единственная дата, я был бы в порядке, но я не вижу, как я превращаю dd.mm.yyyy с продолжительностью 4 недели в 4 строки в длинном формате, которые затем могу повернуть (или сделать все это на один раз с dcast) – Pyrosopher

5

Я хотел бы сделать это по-разному в data.table. Обновлено новое решение:

library(data.table) 
dt = as.data.table(as.is) 
dt[, Start.Date := as.Date(Start.Date, '%d.%m.%Y')] 

# use dcast.data.table before version 1.9.5 
dcast(dt[, list(seq(Start.Date, length.out = Duration, by = '1 week'), No.Of.Resources) 
     , by = Project], Project ~ V1) 

Старый (и излишне сложным) решение:

# expand out Start.Date by Project 
dates.all = dt[, seq(Start.Date, length.out = Duration, by = '1 week'), by = Project] 

# set the key and do a rolling join, then dcast 
# (can use just dcast in version 1.9.5+, have to use dcast.data.table before that) 
setkey(dt, Project, Start.Date) 
dcast(dt[dates.all, roll = TRUE], Project ~ Start.Date) 
# Project 2015-02-16 2015-02-23 2015-03-02 2015-03-09 2015-03-16 2015-03-23 2015-03-30 
#1: Proj A   3   3   3   NA   NA   NA   NA 
#2: Proj B   NA   NA   5   5   NA   NA   NA 
#3: Proj C   2   2   NA   NA   NA   NA   NA 
#4: Proj D   NA   NA   NA   6   6   6   6