2010-08-13 3 views
2

мне нужно взять data.frame в формате:данные перекроить на основе столбца в dataframe

id1 id2 mean start end 
1 A D 4 12 15 
2 B E 5 14 15 
3 C F 6  8 10 

и генерировать повторяющиеся строки, основанные на различии в start - end. Например, мне нужно 3 строки для первой строки, 1 для второй и 2 для третьей. Начальные и конечные поля должны быть в последовательном порядке в последнем кадре данных. Конечный результат для этого 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'esque код:

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) 
} 

Кто-нибудь есть предложения по как оптимизировать этот код? Есть ли функция в plyr, которая может быть применима?

#sample daters 
df <- data.frame(id1 = c("A", "B", "C") 
     , id2 = c("D", "E", "F") 
     , mean = c(4,5,6) 
     , start = c(12,14,8) 
     , end = c(15, 15, 10) 
) 

ответ

2

Возможно, существует более общий способ сделать это, но ниже используется 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 
+0

Это весьма причудливую работы там, я ценю это. Потребовалось ~ 1,5 минуты, работая с кадром данных в 100 тыс. Строк, чтобы выводить данные в соответствующем формате. Благодаря! – Chase

1

survSplit функция survival пакета делает что-то вдоль этих линий, хотя она имеет немного больше опций (например, с указанием времени разреза). Возможно, вы сможете использовать его или просмотреть его код, чтобы узнать, сможете ли вы улучшить свою упрощенную версию.

1

Нет сомнений в том, что это не один из тех случаев, когда лучше поздно, чем никогда, но я имел подобную проблему и придумал это ...

library(plyr) 
ddply(df, c("id1", "id2", "mean", "start", "end"), summarise, 
        sq=seq(1:(end-start))) 
0

две альтернативы, многие лет спустя, предлагая альтернативы с использованием современных популярных data.table и 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) 
Смежные вопросы