Не могу воспроизвести R data.table :: foverlaps в Python - PullRequest
1 голос
/ 22 мая 2019

Я использую data.table::foverlaps в контексте проблем перекрывающихся интервалов геномики . Недавно я попытался найти эквивалент foverlaps в Python, потому что было бы гораздо приятнее использовать только один язык вместо комбинирования Python & R каждый раз, когда мне приходилось копаться в результатах анализа. Конечно, я не первый, кто задает вопрос о нахождении эквивалента R foverlaps в python, применимых в Python pandas. Это самый актуальный пост, который я нашел на SO:

2015 Объединить кадры данных панд, где одно значение находится между двумя другими

2016 R эквивалент эквивалента в Python

2017 Как объединить два кадра данных, для которых значения столбцов находятся в определенном диапазоне?

2018 Как воспроизвести такой же вывод foverlaps в R со слиянием панд в python?

Дело в том, что я вообще не специалист по Python. Поэтому я выбрал ответ, наиболее актуальный / понятный для меня, sqlite3.

Вот как я делаю это в R:

library(data.table)

interv1 <- cbind(seq(from = 3, to = 40, by = 4),seq(from = 5, to = 50, by = 5), c(rep("blue",5), rep("red", 5)), rep("+",10))
interv2 <- cbind(seq(from = 3, to = 40, by = 4),seq(from = 5, to = 50, by = 5), c(rep("blue",5), rep("red", 5)), rep("-",10))
interv  <- rbind(interv1, interv2)
interv <- data.table(interv)
colnames(interv) <- c('start', 'stop', 'color', 'strand')
interv$start <- as.integer(interv$start)
interv$stop <- as.integer(interv$stop)
interv$stop <- interv$stop -1
interv$cov <- runif(n=nrow(interv), min = 10, max = 200)

to_match <- data.table(cbind(rep(seq(from = 4, to = 43, by = 4),2), rep(c(rep("blue", 5), rep("red", 5)), 2), c(rep("-", 10), rep("+", 10))))
colnames(to_match) <- c('start', 'color', 'strand')
to_match$stop <-  to_match$start 
to_match$start <- as.integer(to_match$start)
to_match$stop <- as.integer(to_match$stop)

setkey(interv, color, strand, start, stop)
setkey(to_match, color, strand, start, stop)

overlapping_df <- foverlaps(to_match,interv)

#write.csv(x = interv, file = "Documents/script/SO/wig_foverlaps_test.txt", row.names = F)
#write.csv(x = to_match, file = "Documents/script/SO/cov_foverlaps_test.txt", row.names = F)

И вот как я пытался воспроизвести его на python:

import pandas as pd
import sqlite3

cov_table = pd.DataFrame(pd.read_csv('SO/cov_foverlaps_test.txt', skiprows = [0], header=None))
cov_table.columns = ['start', 'stop', 'chrm', 'strand', 'cov']
cov_table.stop = cov_table.stop - 1


wig_file = pd.DataFrame(pd.read_csv('SO/wig_foverlaps_test.txt', header=None, skiprows = [0]))
wig_file.columns = ['i_start', 'chrm', 'i_strand', 'i_stop']

cov_cols = ['start','stop','chrm','strand','cov']
fract_cols = ['i_start','i_stop','chrm','i_strand']

cov_table = cov_table.reindex(columns = cov_cols)
wig_file = wig_file.reindex(columns = fract_cols)

cov_table.start = pd.to_numeric(cov_table['start'])
cov_table.stop = pd.to_numeric(cov_table['stop'])

wig_file.i_start = pd.to_numeric(wig_file['i_start'])
wig_file.i_stop = pd.to_numeric(wig_file['i_stop'])



conn = sqlite3.connect(':memory:')

cov_table.to_sql('cov_table', conn, index=False)
wig_file.to_sql('wig', conn, index=False)

qry = '''
    select  
        start PresTermStart,
        stop PresTermEnd,
        cov RightCov,
        i_start pos,
        strand Strand
    from
        cov_table join wig on
        i_start between start and stop and 
        cov_table.strand = wig.i_strand
     '''

test = pd.read_sql_query(qry, conn)

Независимо от того, что я изменяю код, я всегда нахожу некоторые небольшие различия в выводе (тест), в этом примере я пропускаю две строки в итоговой таблице Python, где значение, которое должно находиться в диапазоне и равен концу диапазона:

пропущенная строка:

> 19   24  141.306318     24      +
> 
> 19   24  122.923700     24      -

Наконец, я боюсь, что если я найду правильный способ сделать это с sqlite3, разница во времени вычислений с data.table::foverlaps будет слишком большой.

Подытожить:

  • Мой первый вопрос - это где я ошибся в своем коде?
  • Есть ли подход, который был бы более подходящим и близким к фоверлапсу? с точки зрения скорости вычислений?

Спасибо, что прочитали, я надеюсь, что этот пост подходит для SO.

1 Ответ

1 голос
/ 22 мая 2019

По сути, логика слияния и интервалов отличается между R и Python.

R

В соответствии с foverlaps документами вы используете тип по умолчанию любой , который работает под условием:

Пусть [a, b] и [c, d] - интервалы по x и y с a <= b и c <= d. <br/> ...
Для type = "any", если c <= b и d> = a, они перекрываются.

Кроме того, вы присоединяетесь к другим столбцам ключей. В целом вы навязываете следующую логику (для сравнения переведенную в столбцы SQLite):

foverlaps(to_match, interv) --> foverlaps(cov_table, wig)

  1. wig.i_start <= cov_table.stop (i.e., c <= b)
  2. wig.i_stop >= cov_table.start (i.e., d >= a)
  3. wig.color == cov_table.color
  4. wig.strand == cov_table.strand

Python

Вы выполняете интервальный запрос INNER JOIN +, накладывающий следующую логику:

  1. wig.i_start >= cov_table.start (i.e., i_start between start and stop)
  2. wig.i_start <= cov_table.stop (i.e., i_start between start and stop)
  3. wig.strand == cov_table.strand

Заметные различия Python по сравнению с R: wig.i_stop никогда не используется; wig.i_chrm (или цвет) никогда не используется; и wig.i_start обусловлено дважды.

Чтобы решить эту проблему, рассмотрите следующую непроверенную настройку SQL, чтобы надеяться достичь результатов R. Кстати, в SQL лучше использовать псевдонимы ВСЕ столбцы в предложениях JOIN (даже SELECT):

select  
   cov_table.start as PresTermStart,
   cov_table.stop as PresTermEnd,
   cov_table.cov as RightCov,
   wig.i_start as pos,
   wig.strand as Strand
from
   cov_table 
join wig 
    on cov_table.color = wig.i_chrm
   and cov_table.strand = wig.i_strand
   and wig.i_start <= cov_table.stop 
   and wig.i_stop  >= cov_table.start 

Для повышения производительности рассмотрите возможность использования постоянной (не в памяти) базы данных SQLite и создания индексов в полях соединения: color , strand , начало и останов .

...