Объединение строк в data.frame

#r #dataframe #collapse

#r #фрейм данных #агрегировать

Вопрос:

У меня есть data.frame , который выглядит как этот пример data.frame :

 df = data.frame(id = c("a","b","c","d","e","f","g"), start = c(10,20,30,40,50,60,70), end = c(15,25,35,45,55,65,75), flag = c(0,1,1,0,1,0,1))
> df
  id start end flag
1  a    10  15    0
2  b    20  25    1
3  c    30  35    1
4  d    40  45    0
5  e    50  55    1
6  f    60  65    0
7  g    70  75    1
  

Он сортируется в порядке возрастания по df$start и затем df$end .
Я ищу функцию, которая объединит все строки, в df$flag == 1 которые не вмешиваются строки df$flag == 0 . Объединенные строки должны быть df$id объединены с разделителем комы, они df$start должны быть из строки с min df$start , и они df$end должны быть из строки с max df$end . И, наконец, df$flag для них должно быть 1.

Итак, для этого примера возврат data.frame должен быть:

 res.df = data.frame(id = c("a","b,c","d","e","f","g"), start = c(10,20,40,50,60,70), end = c(15,35,45,55,65,75), flag = c(0,1,0,1,0,1))
> res.df
   id start end flag
1   a    10  15    0
2 b,c    20  35    1
3   d    40  45    0
4   e    50  55    1
5   f    60  65    0
6   g    70  75    1
  

Комментарии:

1. Не могли бы вы уточнить end значение? Из вашего объяснения кажется, что оно должно быть 35, но ваше res.df показывает 25.

2. Извините за это. Теперь это исправлено.

3. Еще один вопрос: будет ли когда-либо объединяться более двух строк?

Ответ №1:

Это сложно сделать, aggregate поскольку одна и та же функция применяется к каждому столбцу по очереди. Несколько вызовов aggregate могут выполнить это по частям, которые затем объединяются. Однако data.table позволяет использовать разные функции агрегирования в одном вызове:

 library(data.table)
d <- data.table(df)

d[,list(id=paste(id, collapse=','), start=min(start), end=max(end)), 
  by=list(flag, cumsum(flag==0))
]
   flag cumsum  id start end
1:    0      1   a    10  15
2:    1      1 b,c    20  35
3:    0      2   d    40  45
4:    1      2   e    50  55
5:    0      3   f    60  65
6:    1      3   g    70  75
  

В итоге вы получаете новый столбец, который при желании можно удалить. Условие on cumsum(flag==0) предотвращает flag==0 объединение любых строк с в агрегате и сохраняет непоследовательные flag==1 значения отдельными в результате.

Ответ №2:

Вот решение в base использовании aggregate и merge :

 merge(merge(aggregate(start ~ flag   cumsum(flag==0), data=df, FUN=min), 
           aggregate(end ~ flag   cumsum(flag==0), data=df, FUN=max)
      ), 
     aggregate(id ~ flag   cumsum(flag==0), data=df, FUN=paste, sep=',')
)
  flag cumsum(flag == 0) start end   id
1    0                 1    10  15    a
2    0                 2    40  45    d
3    0                 3    60  65    f
4    1                 1    20  35 b, c
5    1                 2    50  55    e
6    1                 3    70  75    g
  

Код становится немного более читаемым, если вы используете Reduce и список фреймов данных для выполнения слияния:

 Reduce(merge, list(aggregate(start ~ flag   cumsum(flag==0), data=df, FUN=min), 
                   aggregate(end   ~ flag   cumsum(flag==0), data=df, FUN=max),
                   aggregate(id    ~ flag   cumsum(flag==0), data=df, FUN=paste, sep=',')
              )
)