Как рассчитать долю последовательности, которая соответствует данным таблицам с начальными и конечными координатами? - PullRequest
1 голос
/ 29 мая 2019

Имеются две таблицы данных с начальными и конечными координатами для последовательностей целых чисел:

df1 <- data.table(CAT = c(rep("A", 3), rep("B", 3), rep("C", 3)),
              START = c(1, 11, 21, 1, 21, 41, 1, 11, 21),
              END = c(10, 20, 30, 20, 40, 60, 10, 20, 30)
)
df2 <- data.table(CAT = c(rep("A", 3), rep("B", 3), rep("C", 3)),
              START = c(1, 11, 21, 31, 41, 51, 1, 11, 21),
              END = c(5, 17, 23, 38, 48, 54, 9, 17, 26)
)

Как подсчитать количество целых чисел в каждой последовательности в df1, которые находятся в начальной и конечной координатах любогопоследовательность в df2 с соответствием CAT?В настоящее время я использую цикл for:

seq2 <- Vectorize(seq.default, vectorize.args = c("from", "to"))
df1$MATCH <- NA
for (i in 1:nrow(df1)){
  df2_sub <- subset(df2, df2$CAT == df1$CAT[i])
  df2_int <- unlist(seq2(from = df2_sub$START, to = df2_sub$END))
  df1_int <- seq(df1$START[i], df1$END[i])
  df1$MATCH[i] <- length(na.omit(match(df1_int, df2_int)))
}

, который возвращает

df1
   CAT START END MATCH
1:   A     1  10     5
2:   A    11  20     7
3:   A    21  30     3
4:   B     1  20     0
5:   B    21  40     8
6:   B    41  60    12
7:   C     1  10     9
8:   C    11  20     7
9:   C    21  30     6

Однако таблицы данных и векторы, к которым я применяю это, оченьбольшой?Кто-нибудь может предложить способ улучшить производительность?Возможно, используя data.table?

Ответы [ 2 ]

2 голосов
/ 29 мая 2019

Нет необходимости создавать последовательности, которые впоследствии свернуты.

Как указано Коул , функция foverlaps() может использоваться для идентификации перекрывающихся последовательностей. С помощью некоторой простой арифметики можно рассчитать длины перекрытий, которые агрегируются для каждой строки df1, наконец:

library(data.table)
foverlaps(df1[, rn := .I], setkey(df2, CAT, START, END))[
  , ovl := (pmin(END, i.END) - pmax(START, i.START) + 1)][
    , .(MATCH = sum(ovl)), by = .(rn)][
      is.na(MATCH), MATCH := 0][]
   rn MATCH
1:  1     5
2:  2     7
3:  3     3
4:  4     0
5:  5     8
6:  6    12
7:  7     9
8:  8     7
9:  9     6

Версия разработки 1.12.3 data.table поставляется с новой функцией nafill():

library(data.table) # version 1.12.3
foverlaps(df1[, rn := .I], setkey(df2, CAT, START, END))[
  , ovl := (pmin(END, i.END) - pmax(START, i.START) + 1)][
    , .(MATCH = sum(ovl)), by = .(rn)][
      , MATCH := nafill(MATCH, fill = 0)][]
2 голосов
/ 29 мая 2019

Первое, что вам нужно знать, это то, что вы используете для всей своей строки в df1 свою функцию seq2, которая для исполнения очень плохая.

Это решение, которое я предлагаю, я не тестировал его с очень большим набором данных для производительности.

seq2 <- Vectorize(seq.default, vectorize.args = c("from", "to"))

df2_sub = df2[, sequence = unlist( seq2(from = START, to = END) ), by = CAT]

f = function(cat, start, end){
  df2_sub[CAT == cat, length( intersect(seq(start, end), sequence) )]
}

df1[, MATCH := f(CAT, START, END), by = 1:nrow(df1)]

Это работает, если две таблицы df1 и df2 являются data.table.

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