Свертывание data.frame по координатам группы и интервала

#r #dataframe #datatable #dplyr #aggregate

#r #фрейм данных #данные, подлежащие обработке #dplyr #агрегировать

Вопрос:

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

 df <- data.frame(chr = c(rep("1",5),rep("2",4),rep("3",5)),
                 start = c(seq(1,50,10),seq(1,40,10),seq(1,50,10)),
                 end = c(seq(10,50,10),seq(10,40,10),seq(10,50,10)),
                 group = c(c("g1.1","g1.1","g1.2","g1.3","g1.1"),c("g2.1","g2.2","g2.3","g2.2"),c("g3.1","g3.2","g3.2","g3.2","g3.3")),
                 stringsAsFactors = F)
  

Я ищу быстрый способ свертывания df по chr и by group таким образом, чтобы последовательные интервалы вдоль a, chr которые назначены одному и тому же group , объединялись и их start и end координаты изменялись соответствующим образом.

Вот желаемый результат для этого примера:

 res.df <- data.frame(chr = c(rep("1",4),rep("2",4),rep("3",3)),
                     start = c(c(1,21,31,41),c(1,11,21,31),c(1,11,41)),
                     end = c(c(20,30,40,50),c(10,20,30,40),c(10,40,50)),
                     group = c("g1.1","g1.2","g1.3","g1.1","g2.1","g2.2","g2.3","g2.2","g3.1","g3.2","g3.3"),
                     stringsAsFactors = F)
  

Ответ №1:

Редактировать: Для учета требования последовательности вы можете использовать тот же подход, что и ранее, но добавить дополнительную группирующую переменную на основе последовательных значений.

 library(dplyr)

df  %>%
  group_by(chr, group, temp.grp = with(rle(group), rep(seq_along(lengths), lengths))) %>%
  summarise(start = min(start),
            end = max(end)) %>%
  arrange(chr, start) %>%
  select(chr, start, end, group)

# A tibble: 11 x 4
# Groups:   chr, group [9]
   chr   start   end group
   <chr> <dbl> <dbl> <chr>
 1 1         1    20 g1.1 
 2 1        21    30 g1.2 
 3 1        31    40 g1.3 
 4 1        41    50 g1.1 
 5 2         1    10 g2.1 
 6 2        11    20 g2.2 
 7 2        21    30 g2.3 
 8 2        31    40 g2.2 
 9 3         1    10 g3.1 
10 3        11    40 g3.2 
11 3        41    50 g3.3 
  

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

1. Спасибо @H 1. Я думаю, что мой предыдущий пример был недостаточно ясен, и, к сожалению, ваш ответ не решает проблему.

Ответ №2:

Другой tidyverse подход мог бы быть:

 df %>%
 gather(var, val, -c(chr, group)) %>%
 group_by(chr, group) %>%
 filter(val == min(val) | val == max(val)) %>%
 spread(var, val)

  chr   group   end start
  <chr> <chr> <dbl> <dbl>
1 1     g1.1     20     1
2 1     g1.2     30    21
3 1     g1.3     50    31
4 2     g2.1     10     1
5 2     g2.2     20    11
6 2     g2.3     40    21
7 3     g3.1     10     1
8 3     g3.2     40    11
9 3     g3.3     50    41
  

Или:

 df %>%
 group_by(chr, group) %>%
 summarise_all(funs(min, max)) %>%
 select(-end_min, -start_max)

  chr   group start_min end_max
  <chr> <chr>     <dbl>   <dbl>
1 1     g1.1          1      20
2 1     g1.2         21      30
3 1     g1.3         31      50
4 2     g2.1          1      10
5 2     g2.2         11      20
6 2     g2.3         21      40
7 3     g3.1          1      10
8 3     g3.2         11      40
9 3     g3.3         41      50
  

Решением, использующим также rleid() from data.table , к обновленному сообщению могло бы быть:

 df %>%
 group_by(chr, group, group2 = rleid(group)) %>%
 summarise_all(funs(min, max)) %>%
 select(-end_min, -start_max)

   chr   group group2 start_min end_max
   <chr> <chr>  <int>     <dbl>   <dbl>
 1 1     g1.1       1         1      20
 2 1     g1.1       4        41      50
 3 1     g1.2       2        21      30
 4 1     g1.3       3        31      40
 5 2     g2.1       5         1      10
 6 2     g2.2       6        11      20
 7 2     g2.2       8        31      40
 8 2     g2.3       7        21      30
 9 3     g3.1       9         1      10
10 3     g3.2      10        11      40
11 3     g3.3      11        41      50
  

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

1. Спасибо @tmfmnk. Я думаю, что мой предыдущий пример был недостаточно ясен, и, к сожалению, ваш ответ не решает проблему.