2014-01-13 63 views
3

給定data.frame,其中開始和結束表示範圍。將包含範圍的行拆分成多行,數目爲

id start end 
1  3 51 
2  20 28 

我試圖通過25

id start end splitGroup 
1  3 25   0 
1  25 51   25 
2  20 25   0 
2  25 28   25 

由常規功能相似的劈裂如果範圍包含另一個數字或數字序列,並且將它們分組分割行成多行,例如這裏順序使用plyr包

df <- data.frame(
    id = c(1:2), 
    start = c(3,20), 
    end = c(51,28) 
) 

splitBy <- 20 

rowSplit <- function(df, splitBy){ 

    newDf <- ddply(df, .(id), function(x){ 
    data.frame(
     id = x$id, 
     start = x$start, 
     end = x$end, 
     splitGroup = seq(
     floor(x$start/splitBy)*splitBy, 
     floor(x$end/splitBy)*splitBy, 
     by=splitBy 
    ) 
    ) 
    }) 

    newDf <- within(newDf, { 
    start <- ifelse(
     floor(start/splitBy)*splitBy == splitGroup, 
     start, 
     splitGroup 
    ) 
    end <- ifelse( 
     end < (splitGroup + splitBy), 
     end, 
     (splitGroup + splitBy) 
    ) 
    }) 

    return(newDf) 
} 

rowSplit(df, splitBy) 

id start end splitGroup 
1  3 20   0 
1  20 40   20 
1  40 51   40 
2  20 28   20 

這怎麼能使用任意數量的辛格運河或不規則組數字

來完成

回答

0

使用for循環,如@ carl-whitthoft所示,行可以拆分爲一個斷點。但是這個過程需要很長時間,所以如果速度無關緊要的話,這是有效的。

rowSplit <- function(df, splitAt, id ="id", start = "start", end = "end"){ 

    splitRow <- ifelse(df[ ,start] < splitAt & df[ ,end] > splitAt, TRUE, FALSE) 

    newDf <- data.frame(
    id = integer(), 
    start = numeric(), 
    end = numeric(), 
    group = integer() 
) 

    for (j in 1:nrow(df)){ 
    newDf <- rbind(
     newDf, 
     c(df[j,id], 
     df[j,start], 
     ifelse(splitRow[j] == TRUE, splitAt, df[j,end]), 
     ifelse(df[j,start] < splitAt, 0, splitAt) 
    ) 
    ) 
    if (splitRow[j] == TRUE) { 
     newDf <- rbind(newDf, c(df[j,id], splitAt, df[j,end], splitAt)) 
    } 
    } 

    colnames(newDf) <- c("id", "start", "end", "group") 

    return(newDf) 
} 

拆分爲25:

df <- data.frame(
    id = c(1:2), 
    start = c(3,20), 
    end = c(51,28) 
) 

rowSplit(df, 25) 

id start end group 
1  3 25  0 
1 25 51 25 
2 20 25  0 
2 25 28 25 

1

下面是在使用MOD函數開始:

smod <- df$start%/%25 # 0 0 
emod<-df$end%/%25  # 2 1 
newstart<-numeric(0) 
matchit<-25*(1:100) # or at least extend to maximum value in your dataframe 
for (j in 1:2) { newstart<-c(newstart,df$start[j]) 
    if(emod[j]>0) newstart<-c(newstart, min(matchit[matchit>df$start[j]])) } 

Rgames> newstart 
[1] 3 25 20 25 

計算newend以類似的方式,你應該設置。

+0

MOD函數能很好地得到倉的數量。然而,當斷點小於起點時,循環會創建一個新的開始。例如,'df $ start < - 20'和'splitBy < - 5'將給出兩個新的起始數字20和25,而不是一個,20。這可以通過檢查開始是否大於分割數字來避免, newstart [length(newstart)] junkka

+0

@sbebop好點。我沒有去檢查任何「角落案件」。 –