2017-09-09 1 views
5

시계열 및 1 개 또는 3 개의 그룹화 필드가 포함 된 data.frame이 제공됩니다. 그래서 우리는 여러 개의 시계열을 가지고 있습니다 - 각 그룹화 조합마다 하나씩. 그러나 일부 날짜가 누락되었습니다. 올바른 그룹 값으로이 날짜를 추가하는 것이 가장 쉬운 방법입니다 (가장 "깔끔한 방식"이라는 측면에서).그룹화 된 시계열에서 누락 날짜를 채우는 - 깔끔한 방법?

일반적으로 나는 모든 날짜와 함께 data.frame을 생성하고 내 시간 계열과 함께 full_join을 수행한다고 말할 수 있습니다. 그러나 이제는 그룹화 값의 각 조합에 대해이를 수행해야하며 그룹화 값을 채워야합니다.

library(dplyr) 
library(lubridate) 

set.seed(1234) 
# Time series should run vom 2017-01-01 til 2017-01-10 
date <- data.frame(date = seq.Date(from=ymd("2017-01-01"), to=ymd("2017-01-10"), by="days"), v = 1) 
# Two grouping dimensions 
d1 <- data.frame(d1 = c("A", "B", "C", "D"), v = 1) 
d2 <- data.frame(d2 = c(1, 2, 3, 4, 5), v = 1) 

# Generate the data.frame 
df <- full_join(date, full_join(d1, d2)) %>% 
    select(date, d1, d2) 
# and ad to value columns 
df$v1 <- runif(200) 
df$v2 <- runif(200) 

# group by the dimension columns 
df <- df %>% 
    group_by(d1, d2) 

# create missing dates 
df.missing <- df %>% 
    filter(v1 <= 0.8) 

# So now 2017-01-01 and 2017-01-10, A, 5 are missing now 
df.missing %>% 
    filter(d1 == "A" & d2 == 5) 

# A tibble: 8 x 5 
# Groups: d1, d2 [1] 
     date  d1 d2   v1  v2 
     <date> <fctr> <dbl>  <dbl>  <dbl> 
1 2017-01-02  A  5 0.21879954 0.1335497 
2 2017-01-03  A  5 0.32977018 0.9802127 
3 2017-01-04  A  5 0.23902573 0.1206089 
4 2017-01-05  A  5 0.19617465 0.7378315 
5 2017-01-06  A  5 0.13373890 0.9493668 
6 2017-01-07  A  5 0.48613541 0.3392834 
7 2017-01-08  A  5 0.35698708 0.3696965 
8 2017-01-09  A  5 0.08498474 0.8354756 

그래서 모든 날짜와 data.frame을 생성 누락 된 날짜를 추가 :

먼저 내가 누락 된 값으로 data.frame을 만듭니다

의 예를 살펴 보자 (: df.missing는 GROUP_BY는 (D1, D2입니다) 기억)

start <- min(df.missing$date) 
end <- max(df.missing$date) 

all.dates <- data.frame(date=seq.Date(start, end, by="day")) 

아니 내가 그런 짓을 할

그럼) (my_join를 정의 할 수 있습니다 :

my_join <- function(data) { 
    # get value of both dimensions 
    d1.set <- data$d1[[1]] 
    d2.set <- data$d2[[1]] 

    tmp <- full_join(data, all.dates) %>% 
    # First we need to ungroup. Otherwise we can't change d1 and d2 because they are grouping variables 
    ungroup() %>% 
    mutate(
     d1 = d1.set, 
     d2 = d2.set 
    ) %>% 
    group_by(d1, d2) 

    return(tmp) 
} 

이제 우리는 각 조합 my_join()를 호출하고 한 번 봐 "A/5"

df.missing %>% 
    do(my_join(.)) %>% 
    filter(d1 == "A" & d2 == 5) 

# A tibble: 10 x 5 
# Groups: d1, d2 [1] 
     date  d1 d2   v1  v2 
     <date> <fctr> <dbl>  <dbl>  <dbl> 
1 2017-01-02  A  5 0.21879954 0.1335497 
2 2017-01-03  A  5 0.32977018 0.9802127 
3 2017-01-04  A  5 0.23902573 0.1206089 
4 2017-01-05  A  5 0.19617465 0.7378315 
5 2017-01-06  A  5 0.13373890 0.9493668 
6 2017-01-07  A  5 0.48613541 0.3392834 
7 2017-01-08  A  5 0.35698708 0.3696965 
8 2017-01-09  A  5 0.08498474 0.8354756 
9 2017-01-01  A  5   NA  NA 
10 2017-01-10  A  5   NA  NA 

우수함 수 있습니다! 그것이 우리가 찾고 있었던 것입니다. 그러나 우리는 my_join에 d1과 d2를 정의해야하며 조금 어색함을 느낍니다.

그래서이 솔루션에는 어떤 방식 으로든 방해가 있습니까?

PS : 나는 요지에 코드를 삽입 한 다음은

+0


. 도움이 되었다면 대답으로 받아 들여야합니다 (왼쪽의 체크 표시). 그것은 당신의 사건에 대한 해답을 지역 사회가 알 수있게 해줍니다. 원할 경우 수락 한 대답을 나중에 변경할 수 있습니다. – CPak

답변

6

tidyr에는 이러한 종류의 문제에 대한 몇 가지 훌륭한 도구가 있습니다. complete을보세요. 아래 좋은 답변을받은 JerryWho

library(dplyr) 
library(tidyr) 
library(lubridate) 

want <- df.missing %>% 
    ungroup() %>% 
    complete(nesting(d1, d2), date = seq(min(date), max(date), by = "day")) 

want %>% filter(d1 == "A" & d2 == 5) 

#> # A tibble: 10 x 5 
#> # Groups: d1 [1] 
#>  d1 d2  date   v1  v2 
#> <fctr> <dbl>  <date>  <dbl>  <dbl> 
#> 1  A  5 2017-01-01   NA  NA 
#> 2  A  5 2017-01-02 0.21879954 0.1335497 
#> 3  A  5 2017-01-03 0.32977018 0.9802127 
#> 4  A  5 2017-01-04 0.23902573 0.1206089 
#> 5  A  5 2017-01-05 0.19617465 0.7378315 
#> 6  A  5 2017-01-06 0.13373890 0.9493668 
#> 7  A  5 2017-01-07 0.48613541 0.3392834 
#> 8  A  5 2017-01-08 0.35698708 0.3696965 
#> 9  A  5 2017-01-09 0.08498474 0.8354756 
#> 10  A  5 2017-01-10   NA  NA 
+1

이것은 나를 위해 작동하지 않습니다. 일부 행이 추가됩니다. 그러나 esp. A/5에 2017-01-01 및 2017-01-10이 누락되었습니다. 내 생각에 min (date) 및 max (date)가 그룹마다 있기 때문입니다. 사전에 그룹을 해제하고 나중에 group_by를 해제해야 할 수도 있습니다. – JerryWho

+0

오, 미안 해요. 왜냐하면 먼저 'df.missing'을 해제했기 때문입니다. – austensen

+0

'complete'는 여기에 완벽합니다. – CPak

0

https://gist.github.com/JerryWho/1bf919ef73792569eb38f6462c6d7a8edf.missing

library(tidyverse) 
ans <- df.missing %>% 
      nest(date) %>% 
      mutate(data = map(data, ~seq.Date(start, end, by="day"))) %>% 
      unnest(data) %>% 
      rename(date = data) %>% 
      left_join(., df.missing, by=c("date","d1","d2")) 

ans %>% filter(d1 == "A" & d2 == 5) 

출력

 d1 d2  date   v1  v2 
    <fctr> <dbl>  <date>  <dbl>  <dbl> 
1  A  5 2017-01-01   NA  NA 
2  A  5 2017-01-02 0.21879954 0.1335497 
3  A  5 2017-01-03 0.32977018 0.9802127 
4  A  5 2017-01-04 0.23902573 0.1206089 
5  A  5 2017-01-05 0.19617465 0.7378315 
6  A  5 2017-01-06 0.13373890 0.9493668 
7  A  5 2017-01-07 0.48613541 0.3392834 
8  A  5 2017-01-08 0.35698708 0.3696965 
9  A  5 2017-01-09 0.08498474 0.8354756 
10  A  5 2017-01-10   NA  NA 

로 시작하는 tidyverse 방법 ------ -------------------------------------------------- -----------------------------------------
,여기서 다양한 형태 동물원 객체를 생성 expand.griddplyr 동사

with(df.missing, expand.grid(unique(date), unique(d1), unique(d2))) %>% 
    setNames(c("date", "d1", "d2")) %>% 
    left_join(., df.missing, by=c("date","d1","d2")) 

출력 (헤드) 여기서 read.zoo

  date d1 d2   v1   v2 
1 2017-01-01 A 1 0.113703411 0.660754634 
2 2017-01-02 A 1 0.316612455 0.422330675 
3 2017-01-03 A 1 0.553333591 0.424109178 
4 2017-01-04 A 1   NA   NA 
5 2017-01-05 A 1   NA   NA 
6 2017-01-06 A 1 0.035456727 0.352998502 
0

을 사용하는 대안적인 접근법과 그것에 우리는 날짜를 병합. 그런 다음 fortify.zoo을 사용하여 긴 데이터 프레임으로 변환하고 spread을 사용하여 v1v2을 펼칩니다.

하는 것으로 우리가 각 날짜는 분할 변수 중 하나 개 이상 조합에 표시한다고 가정 할 경우

  • 는, 즉 sort(unique(df.missing$date)) 모든 날짜를 포함, 다음 것이다 우리는 merge 라인을 생략 할 수없이 조인 전혀 끝내야 해. 테스트 데이터 df.missing 질문에 표시된이 속성을 가지고 않습니다

    all(all.dates$date %in% df.missing$date) 
    ## [1] TRUE 
    
  • 우리가 merge 후 막을 수 (또는 이후 read.zoo 각 날짜 이전 시점에서 적어도 한 번있는 경우) 다양한 형태의 동물원 개체 경우 이미 모든 날짜가있는 것으로 사용할 수 있습니다. 행 아래 코드

은 ###은 동물원의 개발 버전 (1.8.1)를 생략 할 수 표시된 :

library(dplyr) 
library(tidyr) 
library(zoo) 

split.vars <- c("d1", "d2") 
df.missing %>% 
    as.data.frame %>%  ### 
    read.zoo(split = split.vars) %>% 
    merge(zoo(, seq(start(.), end(.), "day"))) %>% 
    fortify.zoo(melt = TRUE) %>% 
    separate(Series, c("v", split.vars)) %>% 
    spread(v, Value) 

업데이트 : 1.8.1 동물원에서 참고 간소화 .

관련 문제