基于dataframe中的列重塑数据

基于dataframe中的列重塑数据,r,reshape,plyr,R,Reshape,Plyr,我需要采用以下格式的data.frame: id1 id2 mean start end 1 A D 4 12 15 2 B E 5 14 15 3 C F 6 8 10 并根据开始-结束中的差异生成重复行。例如,第一行需要3行,第二行需要1行,第三行需要2行。在最终data.frame中,开始和结束字段应按顺序排列。此data.frame的最终结果应为: id1 id2 mean start end 1 A

我需要采用以下格式的data.frame:

  id1 id2 mean start end
1   A   D    4    12  15
2   B   E    5    14  15
3   C   F    6     8  10
并根据
开始-结束
中的差异生成重复行。例如,第一行需要3行,第二行需要1行,第三行需要2行。在最终data.frame中,开始和结束字段应按顺序排列。此data.frame的最终结果应为:

   id1 id2 mean start end
1    A   D    4    12  13
2    A   D    4    13  14
3    A   D    4    14  15
21   B   E    5    14  15
31   C   F    6     8   9
32   C   F    6     9  10
我已经编写了这个函数,它可以工作,但不是用非常R’风格的代码编写的:

dupData <- function(df){
    diff <- abs(df$start - df$end)
    ret <- {}

    #Expand our dataframe into the appropriate number of rows.
    for (i in 1:nrow(df)){
        for (j in 1:diff[i]){
            ret <- rbind(ret, df[i,])
        } 
    }

    #If matching ID1 and ID2, generate a sequential ordering of start & end dates
    for (k in 2:nrow(ret) - 1) {
        if ( ret[k,1] == ret[k + 1, 1] & ret[k, 2] == ret[k, 2]  ){ 
            ret[k, 5] <- ret[k, 4] + 1
            ret[k + 1, 4] <- ret[k, 5]  
        }
    }
    return(ret)
}

survival
软件包的
survSplit
函数可以按照这些思路进行操作,不过它有更多的选项(例如指定切割时间)。您可以使用它,或者查看它的代码,看看是否可以更好地实现简化版本。

可能有一种更通用的方法来实现这一点,但下面使用的是
rbind.fill

cbind(df[rep(1:nrow(df), times = apply(df[,4:5], 1, diff)), 1:3],
      rbind.fill(apply(df[,4:5], 1, function(x)
                       data.frame(start = x[1]:(x[2]-1), end = (x[1]+1):x[2]))))


##     id1 id2 mean start end
## 1     A   D    4    12  13
## 1.1   A   D    4    13  14
## 1.2   A   D    4    14  15
## 2     B   E    5    14  15
## 3     C   F    6     8   9
## 3.1   C   F    6     9  10

毫无疑问,这不是一个迟到总比不迟到好的时代,但我也有一个类似的问题,我想到了这个

library(plyr)
ddply(df, c("id1", "id2", "mean", "start", "end"), summarise,
                    sq=seq(1:(end-start)))
许多年后,有两种替代方案使用当今流行的
数据提供替代方案。表
tidyverse
软件包:

备选案文1:

library(data.table)
setDT(mydf)[, list(mean, start = start:(end-1)), .(id1, id2)][, end := start + 1][]
   id1 id2 mean start end
1:   A   D    4    12  13
2:   A   D    4    13  14
3:   A   D    4    14  15
4:   B   E    5    14  15
5:   C   F    6     8   9
6:   C   F    6     9  10
备选案文2:

library(tidyverse)
mydf %>% 
  group_by(id1, id2, mean) %>% 
  summarise(start = list(start:(end-1))) %>% 
  unnest(start) %>% 
  mutate(end = start+1)

那是一件相当奇特的工作,我很感激。使用100k行数据帧以适当的格式输出数据大约需要1.5分钟。谢谢
library(tidyverse)
mydf %>% 
  group_by(id1, id2, mean) %>% 
  summarise(start = list(start:(end-1))) %>% 
  unnest(start) %>% 
  mutate(end = start+1)