2016-08-19 4 views
6

"시작"및 "종료"열에 설명 된 범위에 원래 데이터 집합의 모든 값이 포함되도록 데이터 프레임의 행을 결합하고 싶습니다. 겹침, 반복 및 중첩 된 범위가있을 수 있습니다. 일부 범위가 누락되었을 수 있습니다.날짜 범위를 기준으로 행 통합

data = data.frame(rbind(
    c("Roger", 1, 10), 
    c("Roger", 10, 15), 
    c("Roger", 16, 17), 
    c("Roger", 3, 6), 
    c("Roger", 20, 25), 
    c("Roger", NA, NA), 
    c("Susan", 2, 8))) 
names(data) = c("name", "start", "end") 
data$start = as.numeric(as.character(data$start)) 
data$end = as.numeric(as.character(data$end)) 

원하는 결과는 다음과 같습니다 : 여기

내가 붕괴하고 싶은 데이터의 종류의 예

name start end 
Roger 1  17 
Roger 20 25 
Susan 2  8 

내 시도는 모든 항목을 확장하고있다 각 행의 범위. 이 방법은 효과가 있지만 그 후에 다시 축소하는 방법을 모르겠습니다. 또한, 내가 작업하고있는 전체 데이터 세트에는 3 천만 개의 행과 매우 큰 범위가 있으므로이 방법은 매우 느립니다.

pb <- txtProgressBar(min = 0, max = length(data$name), style = 3) 
mylist = list() 
for(i in 1:length(data$name)){ 
    subdata = data[i,] 
    if(is.na(subdata$start)){ 
    mylist[[i]] = subdata 
    mylist[[i]]$each = NA 
    } 
    if(!is.na(subdata$start)){ 
    sequence = seq(subdata$start, subdata$end) 
    mylist[[i]] = subdata[rep(1, each = length(sequence)),] 
    mylist[[i]]$daily = sequence 
    } 
    setTxtProgressBar(pb, i) 
} 

rbindlist(mylist) 
+0

아마도 분명하지만 Roger가 두 번 나타나는 이유는 무엇입니까? start = 1 및 end = 25로 한 행에 없습니까? – snoram

+0

@snoram 좋은 질문입니다. Roger는 18 세 또는 19 세가 아니기 때문에 두 기록은 자신의 범위에서 갭을 반영합니다. – Nancy

+2

관련 항목 : [R의 교차 영역 축소] (http://stackoverflow.com/questions/16957293/collapse-intersecting-regions-in-r) 및 [고유 그룹으로의 중첩 범위] (http://stackoverflow.com)/questions/15235821/merge-overlapping-ranges-to-unique-groups) – Henrik

답변

10

나는 훨씬 더 효율적이에 대한 IRanges를 추측하고,하지만 ...

library(data.table) 

# remove missing values 
DT = na.omit(setDT(data)) 

# sort 
setorder(DT, name, start) 

# mark threshold for a new group 
DT[, high_so_far := shift(cummax(end), fill=end[1L]), by=name] 

# group and summarise 
DT[, .(start[1L], end[.N]), by=.(name, g = cumsum(start > high_so_far + 1L))] 

#  name g V1 V2 
# 1: Roger 0 1 17 
# 2: Roger 1 20 25 
# 3: Susan 1 2 8 

를 어떻게 작동 해요 :

  • cummax 누적 최대이므로, 현재 행을 포함하여 지금까지 가장 높은 값.
  • 현재 행을 제외한 값을 사용하려면 shift (이전 행에서 가져옴)을 사용하십시오.
  • cumsum(some_condition)은 그룹화 변수를 만드는 표준 방법입니다.
  • .Nby=으로 결정되는 그룹의 마지막 행입니다.

원하는 경우 열은 .(s = start[1L], e = end[.N])과 같은 마지막 단계에서 명명 될 수 있습니다. 날짜 간격와


. 날짜로 작업하는 경우 IDate 클래스를 제안합니다. Date을 변환하기 위해 as.IDate을 사용하면됩니다.

우리 날짜에 +1 수 있지만, 불행히도 cummax 할 수있는, 그래서 ...

cummax_idate = function(x) (setattr(cummax(unclass(x)), "class", c("Date", "IDate"))) 

set.seed(1) 
d = sample(as.IDate("2011-11-11") + 1:10) 
cummax_idate(d) 
# [1] "2011-11-14" "2011-11-15" "2011-11-16" "2011-11-18" "2011-11-18" 
# [6] "2011-11-19" "2011-11-20" "2011-11-20" "2011-11-21" "2011-11-21" 

나는이 기능을 cummax 대신에 사용될 수 있다고 생각합니다.

setattr은 출력을 인쇄하지 않기 때문에 함수에있는 여분의 ()이 있습니다.

+0

'na.omit'을'setDT' 다음에 적용하여 결국 더 빠른'na.omit.data.table' 메소드를 사용합니다. – jangorecki

+0

좋습니다.고마워, @ 장고 레크 – Frank

+0

@ This is great. 나는 실제로 이것을 날짜 범위에 사용하고 있지만 날짜를 숫자로 변환 한 다음 날짜로 다시 변환하면이 메서드로 작업하고 날짜를 유지합니다. – Nancy

관련 문제