【问题标题】:Split row containing range into multiple rows by any number按任意数字将包含范围的行拆分为多行
【发布时间】:2014-01-13 09:34:50
【问题描述】:

给定一个 data.frame,其中 start 和 end 代表范围。

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

如何使用任何单个数字或一组不规则的数字来做到这一点

【问题讨论】:

    标签: r plyr


    【解决方案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,你应该已经准备好了。

    【讨论】:

    • mod 函数可以很好地获取 bin 的数量。然而,当断点小于开始时,循环会创建一个新的开始。例如,df$start &lt;- 20splitBy &lt;- 5 将给出两个新的起始编号 20 和 25,而不是一个 20。这可以通过在 if 语句中添加 newstart[length(newstart)] &lt; splitBy 来检查起始是否大于拆分编号来避免.正如您所建议的那样,在循环而不是 ddply 函数中完成所有操作可能更容易。
    • @sbebop 好点。我没有时间检查任何“极端情况”。
    【解决方案2】:

    按照@carl-whitthoft 的建议,使用for 循环,可以在一个 断点处拆分行。但是这个过程需要很长的时间,所以如果速度无关紧要的话,这是可行的。

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多