2014-12-08 2 views
2

좀 더 일반적인 문제의 특정 변형이 생겼습니다. 내가 data.table과 함께 사용하고있는 패널 데이터가 있고 data.table의 기능별 그룹을 사용하여 누락 된 값을 채우고 싶습니다. 불행히도 그들은 숫자가 아니므로 단순히 보간 할 수는 없지만 조건에 따라 채워 져야합니다. data.tables에 일종의 조건부 na.locf를 수행 할 수 있습니까?조건부 NA로 채우기 data.table

본질적으로 NAs 후에 조건부로 NAs를 채우는 방법이 있지만 다음 관찰이 이전 것 인 경우에만 NAs를 채우기를 원합니다.

예를 들어, 다음 데이터에서 각 id 그룹에 의해 associatedid 변수를 채우고 싶습니다. 그래서 id == 1, year == 2003은 ABC123으로 채울 것입니다. 왜냐하면 NA 앞뒤의 값이 같기 때문입니다. 그러나 동일한 ID의 경우 2000이 아니기 때문입니다. Id == 2는 다음 값이 NA 이전의 값과 같지 않기 때문에 변경되지 않습니다. Id == 3은 2003 년과 2004 년을 채울 것입니다.

df = read.table(header=T, text = "id year associatedid 
      1 2000 NA 
      1 2001 ABC123 
      1 2002 ABC123 
      1 2003 NA 
      1 2004 ABC123 
      1 2005 ABC123 
      2 2000 NA 
      2 2001 ABC123 
      2 2002 ABC123 
      2 2003 NA 
      2 2004 DEF456 
      2 2005 DEF456 
      3 2000 NA 
      3 2001 ABC123 
      3 2002 ABC123 
      3 2003 NA 
      3 2004 NA 
      3 2005 ABC123 
      ") 

dt = data.table(df,key = c("id")) 

모든 제안이나 조언을 부탁드립니다. 감사!

답변

2

이 모든 수정 na.locf 기능을 작성하는 방법에 대한 것입니다. 그런 다음 다른 함수처럼 data.table에 연결할 수 있습니다. 우리가 그 기능을 일단

new.locf <- function(x){ 
    # might want to think about the end of this loop 
    # this works here but you might need to add another case 
    # if there are NA's as the last value. 
    # 
    # anyway, loop through observations in a vector, x. 
    for(i in 2:(length(x)-1)){ 
    nextval = i 
    # find the next, non-NA value 
    # again, not tested but might break if there isn't one? 
    while(nextval <= length(x)-1 & is.na(x[nextval])){ 
     nextval = nextval + 1 
    } 
    # if the current value is not NA, great! 
    if(!is.na(x[i])){ 
     x[i] <- x[i] 
    }else{ 
     # if the current value is NA, and the last value is a value 
     # (should given the nature of this loop), and 
     # the next value, as calculated above, is the same as the last 
     # value, then give us that value. 
     if(is.na(x[i]) & !is.na(x[i-1]) & x[i-1] == x[nextval]){ 
     x[i] <- x[nextval] 
     }else{ 
     # finally, return NA if neither of these conditions hold 
     x[i] <- NA 
     } 
    } 
    } 
    # return the new vector 
    return(x) 
} 

, 우리는 평소처럼 data.table 사용할 수 있습니다

dt2 <- dt[,list(year = year, 
       # when I read your data in, associatedid read as factor 
       associatedid = new.locf(as.character(associatedid)) 
       ), 
      by = "id" 
      ] 

을이 반환

> dt2 
    id year associatedid 
1: 1 2000   NA 
2: 1 2001  ABC123 
3: 1 2002  ABC123 
4: 1 2003  ABC123 
5: 1 2004  ABC123 
6: 1 2005  ABC123 
7: 2 2000   NA 
8: 2 2001  ABC123 
9: 2 2002  ABC123 
10: 2 2003   NA 
11: 2 2004  DEF456 
12: 2 2005  DEF456 
13: 3 2000   NA 
14: 3 2001  ABC123 
15: 3 2002  ABC123 
16: 3 2003  ABC123 
17: 3 2004  ABC123 
18: 3 2005  ABC123 

당신이 최선을 이해 찾고있는 것을하는 그것.

new.locf 정의에 일부 헷지를 제공 했으므로 약간의 생각을 할 수도 있지만 시작해야합니다.

+0

게시 한 경우에는 분명히 마찬가지입니다. 제안한대로 더 큰 데이터 세트에 적용하려고하면 NAs가 행을 채울 때 중단된다는 것을 알게되었으므로이 경우를 처리하기 위해 마지막 조건을 추가했습니다. – DaedalusBloom

0

저는 첫 번째 패스에서 시작 값 (ID 내)의 fron에 "p_"를 붙여 넣을 NA를 변경 한 후 두 번째 패스 검사에서 마지막 시퀀스는 다음 실제 값과 일치합니다. 나는 지금까지 나의 코드를 제공하고있다. 그것은 정말로 대답이 아니기 때문에, 어떤 상향 회선도 기대하지 않는다. (아마 그 associatedidasid로 이름을 바꾸려면 더 쉬웠을 것입니다.)

lapply(split(df, df$id), 
    function(d){ d$associatedid <- as.character(d$associatedid) 
    missloc <- with(d, tapply(is.na(associatedid), id, which)) 
    for (n in missloc) if( 
      d$associatedid[n+1] %in% c(d$associatedid[n-1], 
            paste0("p_" , d$associatedid[n-1])& 
    grepl(gsub("p\\_", "", d$associatedid[n-1]), d$associatedid[n+1]) 
         { d$associatedid[n] <- d$associatedid[n-1] 
        } else{ 
       #tentative NA replacement 
     d$associatedid[n] <- paste0("p_" , d$associatedid[n-1])} 
}) 
+0

입력 해 주셔서 감사합니다. "two pass"방식은 내가 정말로 생각하지 못했던 방식이므로,이를 사용하는 방법을 찾을 수 있습니다. A'so, 다음에는 간단한 변수 이름을 사용합니다. 그러나이 시점에서 이것은 추측 일뿐입니다. 일반적으로 data.table에서 이러한 종류의 split-manipulate-recombine 프로세스는 변수 이름을 한 번만 참조하면됩니다. – DaedalusBloom