Свернуть кадр данных BLAST по значениям в двух столбцах

У меня есть кадр данных BLAST HSP (отображаются не все столбцы):

      query.id subject.id alignment.length
196 1032519524 1032519523              212
197 1032519524 1032519523              182
198 1032519524 1032519522              212
199 1032519524 1032519522              182
200 1032519524 1032518642              212

и хотел бы свернуть данные, чтобы получить уникальные пары query.id и subject.id. Если есть несколько строк с одинаковыми query.id и subject.id, следует добавить значения дляalignment.length:

    query.id subject.id alignment.length
1 1032519524 1032518642              212
2 1032519524 1032519522              394
3 1032519524 1032519523              394

Я делаю это аккуратным однострочником, используя plyr:

ddply(blast.results, c("query.id", "subject.id"), function(x)colSums(x['alignment.length']))

К сожалению, это становится невозможным при обработке нескольких сотен тысяч результатов BLAST. Есть ли более быстрый и масштабируемый подход?

Микробенчмарк для решений @PoGibas data.table:

Unit: milliseconds
                                                                                                                            expr
                               setDT(blast.results)[, .(alignment.length = sum(alignment.length)),      .(query.id, subject.id)]
 setkey(setDT(blast.results), query.id, subject.id)[, .(alignment.length = sum(alignment.length)),      .(query.id, subject.id)]
                                                                                                                             100
       min        lq        mean     median        uq        max neval cld
 11.514016 18.010048 31.61341262 22.0045935 32.104018 222.943783   100   b
 15.308905 22.620595 36.32531007 28.2132725 43.527390 156.109477   100   b
  0.000012  0.000185  0.00033057  0.0003635  0.000443   0.000772   100  a

person user1981275    schedule 19.09.2017    source источник


Ответы (1)


Решение с использованием dplyr (от @hadley):

library(dplyr)
blast.results %>%
    group_by(query.id, subject.id) %>%
    summarise(alignment.length = sum(alignment.length))

Решение с использованием data.table (от @Мэтт Доул):

library(data.table)
setkey(setDT(blast.results), query.id, subject.id)[, .(alignment.length = sum(alignment.length)), .(query.id, subject.id)]

Как вы упомянули, что скорость важна, вы, вероятно, захотите использовать data.table (data.table vs dplyr).

person pogibas    schedule 19.09.2017
comment
согласен, что скорость в целом верна, но я бы предложил ОП проверить скорость на обоих из них и посмотреть, достаточно ли мала разница в этом случае, чтобы они могли выбирать на основе комфорта/знакомства/скорости, а не грубого вычисления эффективность (несколько сотен тысяч могут быть небольшими для целей дифференциации dplyr и data.table) - person Ben Bolker; 20.09.2017
comment
Ого, data.table выглядит очень быстро! Сравнивая его на данный момент с большим набором данных, мы не можем протестировать решение dplyr в данный момент, так как оно не может быть установлено... - person user1981275; 20.09.2017
comment
@user1981275 user1981275 Я обновил свой ответ на setkey в data.table, попробуйте. - person pogibas; 20.09.2017
comment
@PoGibas В моем тесте (вопрос отредактирован) вариант с setkey немного медленнее в средних и минимальных значениях. Я не включаю свое решение ddply, так как оно занимает вечность - person user1981275; 20.09.2017