Извлечение строк и подстрок из одного файла в зависимости от информации из другого файла

У меня есть файл 1.blast с такой информацией о координатах

1       gnl|BL_ORD_ID|0 100.00  33      0       0       1        3
27620   gnl|BL_ORD_ID|0 95.65   46      2       0       1       46
35296   gnl|BL_ORD_ID|0 90.91   44      4       0       3       46
35973   gnl|BL_ORD_ID|0 100.00  45      0       0       1       45
41219   gnl|BL_ORD_ID|0 100.00  27      0       0       1       27
46914   gnl|BL_ORD_ID|0 100.00  45      0       0       1       45 

и файл 1.fasta с такой информацией о последовательности

>1
TCGACTAGCTACGACTCGGACTGACGAGCTACGACTACGG
>2
GCATCTGGGCTACGGGATCAGCTAGGCGATGCGAC
...
>100000
TTTGCGAGCGCGAAGCGACGACGAGCAGCAGCGACTCTAGCTACTG

Сейчас я ищу сценарий, который берет из 1.blast первый столбец и извлекает эти идентификаторы последовательности (= первый столбец $1) плюс последовательность, а затем из самой последовательности все, кроме тех позиций между $7 и $8 из файла 1.fasta, то есть из первых двух соответствует результату будет

>1
ACTAGCTACGACTCGGACTGACGAGCTACGACTACGG
>27620
GTAGATAGAGATAGAGAGAGAGAGGGGGGAGA
...

(обратите внимание, что первые три записи из >1 не входят в эту последовательность)

Идентификаторы идут последовательно, что означает, что я могу извлечь необходимую информацию следующим образом:

awk '{print 2*$1-1, 2*$1, $7, $8}' 1.blast

Это дает мне матрицу, которая содержит в первом столбце правую строку идентификатора последовательности, во втором столбце правильную строку последовательности (= одну после строки идентификатора), а затем две координаты, которые следует исключить. Таким образом, в основном матрица, содержащая всю необходимую информацию, какие элементы из 1.fasta должны быть извлечены.

К сожалению, у меня нет слишком большого опыта работы со сценариями, поэтому я немного потерялся, как мне передать значения, например. в подходящей команде sed? Я могу получить определенные строки следующим образом:

sed -n 3,4p 1.fasta

и строка, которую я хочу удалить, например. с помощью

sed -n 5p 1.fasta | awk '{print substr($0,2,5)}'

Но теперь моя проблема заключается в том, как я могу направить информацию из первого вызова awk в другие команды, чтобы они извлекали правильные строки и удаляли из строк последовательности затем заданные координаты. Итак, substr - неправильная команда, мне нужна команда remstr(string,start,stop), которая удаляет все между этими двумя позициями из заданной строки, но я думаю, что я мог бы сделать это в собственном скрипте. Особенно правильная трубка здесь для меня проблема.


person Daniel Fischer    schedule 30.05.2013    source источник


Ответы (4)


Как указали thunk и msw, для такого рода задач доступны более подходящие инструменты, но здесь у вас есть сценарий, который может научить вас тому, как справляться с этим с помощью awk:

Содержимое script.awk:

## Process first file from arguments.
FNR == NR {
        ## Save ID and the range of characters to remove from sequence.
        blast[ $1 ] = $(NF-1) " " $NF
        next
}

## Process second file. For each FASTA id...
$1 ~ /^>/ {
        ## Get number.
        id = substr( $1, 2 )

        ## Read next line (the sequence).
        getline sequence

        ## if the ID is one found in the other file, get ranges and
        ## extract those characters from sequence.
        if ( id in blast ) {
                split( blast[id], ranges )
                sequence = substr( sequence, 1, ranges[1] - 1 ) substr( sequence, ranges[2] + 1 )
                ## Print both lines with the shortened sequence.
                printf "%s\n%s\n", $0, sequence
        }

}

Предполагая, что ваш 1.blasta вопроса и настроенный 1.fasta для его проверки:

>1
TCGACTAGCTACGACTCGGACTGACGAGCTACGACTACGG
>2
GCATCTGGGCTACGGGATCAGCTAGGCGATGCGAC
>27620
TTTGCGAGCGCGAAGCGACGACGAGCAGCAGCGACTCTAGCTACTGTTTGCGA 

Запустите скрипт следующим образом:

awk -f script.awk 1.blast 1.fasta

Это дает:

>1
ACTAGCTACGACTCGGACTGACGAGCTACGACTACGG
>27620
TTTGCGA

Конечно, я предполагаю некоторые вещи, самое главное, что последовательности fasta не длиннее одной строки.

person Birei    schedule 30.05.2013
comment
Это ваше последнее предположение ОПАСНО, так как формат файла быстрого доступа (использование которого часто далекий от стандартизированного) обычно имеет обычную новую строку после определенного количества символов. Одна из причин выбрать Bioperl или что-то подобное, поскольку соответствующие методы будут учитывать (большую часть) вариаций формата файла. - person dlaehnemann; 30.05.2013
comment
Большое спасибо! Я все еще пытаюсь пройти код и понять, что там происходит, и настроить его (например, вывод скрипта не должен содержать последовательность 2, поскольку она не упоминается в файле blast). Но я надеюсь, что с этого момента мне удастся справиться с этим. - person Daniel Fischer; 30.05.2013
comment
@thunk, хороший момент с опасными предположениями, но я не упомянул здесь одну вещь - все эти упражнения предназначены только для запуска определенных поисковых запросов, и я не использую никаких других инструментов, и я просто называю это здесь fasta, но я не загрузить файлы в любую другую программу, мне просто нужны последовательности для повторного поиска частей, которые не были найдены в предыдущем запуске. - person Daniel Fischer; 30.05.2013
comment
@DanielFischer: Хорошо. Не знал этого. Просто печатайте только тогда, когда идентификатор найден, внутри de if, а не после него. - person Birei; 30.05.2013
comment
@thunk: Да. Ты прав. Я уже видел некоторые файлы FASTA раньше и знал это. Возможно, ОП выполнил некоторую предварительную обработку ввода или что-то в этом роде. Я не знаю. В противном случае это только начало, и нет проблем с изменением сценария, чтобы адаптировать его к его потребностям. - person Birei; 30.05.2013
comment
Спасибо, скрипт действительно помог лучше понять awk и его использование (тем более, что примеры файлов, приведенные здесь, были немного упрощены, и поэтому мне пришлось еще немного подкорректировать скрипт). - person Daniel Fischer; 03.06.2013

Если вы занимаетесь биоинформатикой и работаете с последовательностями ДНК (или даже более сложными вещами, такими как аннотации последовательностей), я бы порекомендовал взглянуть на Биоперл. Это, очевидно, требует знания Perl, но имеет довольно много функций.

В вашем случае вы хотели бы сгенерировать Bio::Seq объекты из вашего fasta-файла, используя Bio::SeqIOмодуль.

Затем вам нужно будет прочитать номера fasta-entry и желаемые позиции в хэш. С fasta-name в качестве ключа и значением, представляющим собой массив из двух значений для каждой подпоследовательности, которую вы хотите извлечь. Если может быть более одной такой подпоследовательности на запись fasta, вам придется создать массив массивов в качестве записи значения для каждого ключа.

С помощью этой структуры данных вы можете извлечь последовательности, используя метод subseq из Bio::Seq< /а>.

Я надеюсь, что это способ для вас, хотя я уверен, что это также возможно с чистым bash.

person dlaehnemann    schedule 30.05.2013
comment
+1: не изобретайте велосипед, особенно если кто-то раздает колеса бесплатно - person msw; 30.05.2013
comment
Спасибо за подсказку, посмотрю. Мой опыт связан с программированием на R, так что в настоящее время мне немного сложно изменить способ мышления... Но я думаю, что стоит также познакомиться с Bioperl. - person Daniel Fischer; 30.05.2013

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

foreach row in blast:
    get the proper (blast[$1]) sequence from fasta
    drop bases (blast[$7..$8]) from sequence
    print blast[$1], shortened_sequence 

Если я правильно понял вашу задачу, вам мешает ваш язык программирования (bash) и особый формат ваших данных (запись, разделенная на строки). Perl или Python были бы гораздо более подходящими для этой задачи; на самом деле Perl был написан отчасти потому, что множественный доступ к файлам в awk того времени был действительно трудным, если не невозможным.

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

person msw    schedule 30.05.2013
comment
Да, ваши разъяснения сильно ударили по голове, это то, что я планирую сделать. На самом деле я воспринял это как процесс обучения написанию сценариев bash, но, думаю, я последую вашему совету и переключусь на Perl (или Bioperl, спасибо @thunk) и постараюсь там изо всех сил. - person Daniel Fischer; 30.05.2013

Обновил ответ:

awk  '
NR==FNR && NF { 
    id=substr($1,2)
    getline seq
    a[id]=seq
    next 
} 
($1 in a) && NF { 
    x=substr(a[$1],$7,$8)
    sub(x, "", a[$1])
    print ">"$1"\n"a[$1]
} ' 1.fasta 1.blast
person jaypal singh    schedule 30.05.2013
comment
@DanielFischer снова обновил ответ. Хотел бы получить ваш отзыв. - person jaypal singh; 30.05.2013
comment
Спасибо за вашу помощь, я все еще был занят, чтобы понять ответ от @Birei, поэтому я еще не ответил, и в настоящее время у меня нет своих данных здесь, но в понедельник я запущу код на данных. - person Daniel Fischer; 01.06.2013
comment
Спасибо, это работает так же, как и решение от @Birei, поэтому я хотел бы принять оба, но, к сожалению, это не сработает. Но оба ответа помогают лучше понять awk. - person Daniel Fischer; 03.06.2013