Комплексная фильтрация строк с python - PullRequest
1 голос
/ 27 апреля 2020

У меня есть длинная строка, которая является деревом phylogeneti c, и я хочу сделать очень специфическую c фильтрацию.

(Esy@ESY15_g64743_DN3_SP7_c0:0.0726396855636,Aar@AA_maker7399_1:0.137507902808,((Spa@Tp2g18720:0.0318934795022,Cpl@CP2_g48793_DN3_SP8_c:0.0273465005242):9.05326020871e-05,(((Bst@Bostr_13083s0053_1:0.0332592496158,((Aly@AL8G21130_t1:0.0328569260951,Ath@AT5G48370_1:0.0391706378372):0.0205924636564,(Chi@CARHR183840_1:0.0954469923893,Cru@Carubv10026342m:0.0570981548016):0.00998579652059):0.0150356382287):0.0340484449097,(((Hco@scaff1034_g23864_DN3_SP8_c_TE35_CDS100:0.00823215335663,Hlo@DN13684_c0_g1_i1_p1:0.0085462978729):0.0144626717872,Hla@DN22821_c0_g1_i1_p1:0.0225079453622):0.0206478928557,Hse@DN23412_c0_g1_i3_p1:0.048590776459):0.0372829371381):0.00859075940423,(Esa@Thhalv10004228m:0.0378509854703,Aal@Aa_G102140_t1:0.0712272454125):1.00000050003e-06):0.00328120860999):0.0129090235079):0.0129090235079;

В основном каждый x@y является species@gene_id информацией. То, что я пытаюсь сделать, это обрезать это так, чтобы у меня было только x вместо x@y.

(Esy, Aar,(Spa,Cpl))...

Сначала я попытался разделить строку, но проблема в том, что строка имеет разные «точки разделения» для того, чего я хочу достичь, т.е. некоторые части x@y заканчиваются ,, а другие - ). Я искал решение и видел операции с регулярными выражениями, но я новичок в Python, и я не был уверен, стоит ли сосредоточиться на этом. Я также подумал о strip(), но мне кажется, что мне нужно указать символы, которые будут удалены для этого.

Основная проблема в том, что для меня нет «шаблона», по которому Python нужно следовать. Единственное, что идентификаторы всех видов состоят из 3 букв, и перед ними стоит @ символ.

Есть ли метод, который может делать то, что я хочу? Я буду очень рад, если вы поможете мне с моей проблемой. Заранее спасибо.

Ответы [ 6 ]

1 голос
/ 27 апреля 2020

Попробуйте:

import re:

pat = re.compile(r'(\w{3})@')
txt = "(Esy@ESY15_g64743_DN3_SP7_c0:0.0726396855636,Aar@AA_maker7399_1:0.137507902808,((Spa@Tp2g18720:0.0318934795022,Cpl@CP2_g48793_DN3_SP8_c:0.0273465005242):9.05326020871e-05,(((Bst@Bostr_13083s0053_1:0.0332592496158,((Aly@AL8G21130_t1:0.0328569260951,Ath@AT5G48370_1:0.0391706378372):0.0205924636564,(Chi@CARHR183840_1:0.0954469923893,Cru@Carubv10026342m:0.0570981548016):0.00998579652059):0.0150356382287):0.0340484449097,(((Hco@scaff1034_g23864_DN3_SP8_c_TE35_CDS100:0.00823215335663,Hlo@DN13684_c0_g1_i1_p1:0.0085462978729):0.0144626717872,Hla@DN22821_c0_g1_i1_p1:0.0225079453622):0.0206478928557,Hse@DN23412_c0_g1_i3_p1:0.048590776459):0.0372829371381):0.00859075940423,(Esa@Thhalv10004228m:0.0378509854703,Aal@Aa_G102140_t1:0.0712272454125):1.00000050003e-06):0.00328120860999):0.0129090235079):0.0129090235079;"
pat.findall(t)

Результат:

['Esy', 'Aar', 'Spa', 'Cpl', 'Bst', 'Aly', 'Ath', 'Chi', 'Cru', 'Hco', 'Hlo', 'Hla', 'Hse', 'Esa', 'Aal']

Если вам нужна неповрежденная конструкция, мы можем вместо этого попытаться удалить ненужные детали:

pat = re.compile(r'(@|:)[^/),]*')
pat.sub('',t).replace(',', ', ')

Результат:

'(Esy, Aar, ((Spa, Cpl), (((Bst, ((Aly, Ath), (Chi, Cru))), (((Hco, Hlo), Hla), Hse)), (Esa, Aal))))'

Regex demo

0 голосов
/ 27 апреля 2020

Код синтаксического анализа может быть трудно следовать. Tatsu позволяет писать читаемый код синтаксического анализа, комбинируя грамматики и python:

text = "(Esy@ESY15_g64743_DN3_SP7_c0:0.0726396855636,Aar@AA_maker7399_1:0.137507902808,((Spa@Tp2g18720:0.0318934795022,Cpl@CP2_g48793_DN3_SP8_c:0.0273465005242):9.05326020871e-05,(((Bst@Bostr_13083s0053_1:0.0332592496158,((Aly@AL8G21130_t1:0.0328569260951,Ath@AT5G48370_1:0.0391706378372):0.0205924636564,(Chi@CARHR183840_1:0.0954469923893,Cru@Carubv10026342m:0.0570981548016):0.00998579652059):0.0150356382287):0.0340484449097,(((Hco@scaff1034_g23864_DN3_SP8_c_TE35_CDS100:0.00823215335663,Hlo@DN13684_c0_g1_i1_p1:0.0085462978729):0.0144626717872,Hla@DN22821_c0_g1_i1_p1:0.0225079453622):0.0206478928557,Hse@DN23412_c0_g1_i3_p1:0.048590776459):0.0372829371381):0.00859075940423,(Esa@Thhalv10004228m:0.0378509854703,Aal@Aa_G102140_t1:0.0712272454125):1.00000050003e-06):0.00328120860999):0.0129090235079):0.0129090235079;"

import sys
import tatsu

grammar = """
start = things ';'
    ;

things = thing [ ',' things ]
    ;

thing = x '@' y ':' number
    | '(' things ')' ':' number
    ;

x = /\w+/
    ;

y = /\w+/
    ;

number = /[+-]?\d+\.?\d*(e?[+-]?\d*)/
    ;
"""

class Semantics:
    def x(self, ast):
        # the method name matches the rule name
        print('X =', ast)

parser = tatsu.compile(grammar, semantics=Semantics())
parser.parse(text)
0 голосов
/ 27 апреля 2020

вы можете использовать регулярное выражение:

import re 
s = "(Esy@ESY15_g64743_DN3_SP7_c0:0.0726396855636,Aar@AA_maker7399_1:0.137507902808,((Spa@Tp2g18720:0.0318934795022,Cpl@CP2_g48793_DN3_SP8_c:0.0273465005242):9.05326020871e-05,(((Bst@Bostr_13083s0053_1:0.0332592496158,((Aly@AL8G21130_t1:0.0328569260951,Ath@AT5G48370_1:0.0391706378372):0.0205924636564,(Chi@CARHR183840_1:0.0954469923893,Cru@Carubv10026342m:0.0570981548016):0.00998579652059):0.0150356382287):0.0340484449097,(((Hco@scaff1034_g23864_DN3_SP8_c_TE35_CDS100:0.00823215335663,Hlo@DN13684_c0_g1_i1_p1:0.0085462978729):0.0144626717872,Hla@DN22821_c0_g1_i1_p1:0.0225079453622):0.0206478928557,Hse@DN23412_c0_g1_i3_p1:0.048590776459):0.0372829371381):0.00859075940423,(Esa@Thhalv10004228m:0.0378509854703,Aal@Aa_G102140_t1:0.0712272454125):1.00000050003e-06):0.00328120860999):0.0129090235079):0.0129090235079;"
p = "...?(?=@)|\(|\)"

result = re.findall(p, s)

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

для объяснения того, что происходит:
p - это шаблон регулярного выражения
, поэтому в этом шаблоне:
. означает совпадение с любым словом
...?(?=@) означает сопоставление с любым словом, пока я не получу слово ? с ? это @, так что весь этот шаблон означает, что вы получаете любые три слова перед @
| выражением or, я использовал его здесь, чтобы найти другой шаблон
, а остальное - найти ) и (

0 голосов
/ 27 апреля 2020

Попробуйте это регулярное выражение, если вам нужны скобки в выводе:

import re
regex = r"@[A-Za-z0-9_\.:]+|[0-9:\.;e-]+"
phylogenetic_tree = "(Esy@ESY15_g64743_DN3_SP7_c0:0.0726396855636,Aar@AA_maker7399_1:0.137507902808,((Spa@Tp2g18720:0.0318934795022,Cpl@CP2_g48793_DN3_SP8_c:0.0273465005242):9.05326020871e-05,(((Bst@Bostr_13083s0053_1:0.0332592496158,((Aly@AL8G21130_t1:0.0328569260951,Ath@AT5G48370_1:0.0391706378372):0.0205924636564,(Chi@CARHR183840_1:0.0954469923893,Cru@Carubv10026342m:0.0570981548016):0.00998579652059):0.0150356382287):0.0340484449097,(((Hco@scaff1034_g23864_DN3_SP8_c_TE35_CDS100:0.00823215335663,Hlo@DN13684_c0_g1_i1_p1:0.0085462978729):0.0144626717872,Hla@DN22821_c0_g1_i1_p1:0.0225079453622):0.0206478928557,Hse@DN23412_c0_g1_i3_p1:0.048590776459):0.0372829371381):0.00859075940423,(Esa@Thhalv10004228m:0.0378509854703,Aal@Aa_G102140_t1:0.0712272454125):1.00000050003e-06):0.00328120860999):0.0129090235079):0.0129090235079;"

print(re.sub(regex,"",phylogenetic_tree))

Вывод:

(Esy,Aar,((Spa,Cpl),(((Bst,((Aly,Ath),(Chi,Cru))),(((Hco,Hlo),Hla),Hs)),(Esa,Aal))))
0 голосов
/ 27 апреля 2020

Поскольку вы пытаетесь разобрать дерево филогенетического c, я настоятельно рекомендую, чтобы Bio Python сделал за вас тяжелую работу.

Вы можете легко проанализировать и отобразить филогенетический c с Bio.Phylo . Затем он просто перебирает все элементы дерева и разделяет имена по знаку «at».

Поскольку Phylo ожидает, что ввод находится в файле, мы создаем файл-подобный объект в памяти с помощью io.StringIO. Получить полное дерево так же просто, как

Phylo.read(io.StringIO(s), 'newick')

Чтобы проверить, выглядит ли проанализированное дерево в здравом уме, я печатаю его один раз с помощью print(tree).

Теперь мы хотим изменить все имена узлов, которые содержат '@'. С tree.find_elements мы получаем доступ ко всем узлам. Некоторые узлы не имеют имени, а некоторые могут не содержать '@'. Поэтому, чтобы быть особенно осторожным, мы сначала проверяем if n.name and '@' in n.name. Только тогда мы разделяем имя каждого узла на '@' и берем только первую его часть (индекс 0): n.name = n.name.split('@')[0]

Чтобы воссоздать начальное строковое представление, мы используем Phylo.write:

out = io.StringIO()
Phylo.write(tree, out, "newick")
print(out.getvalue())

Опять же, write хочет получить аргумент файла - если мы просто хотим получить строку, мы можем снова использовать объект StringIO.

Full код:

import io

from Bio import Phylo

if __name__ == '__main__':
    s = '(Esy@ESY15_g64743_DN3_SP7_c0:0.0726396855636,Aar@AA_maker7399_1:0.137507902808,((Spa@Tp2g18720:0.0318934795022,Cpl@CP2_g48793_DN3_SP8_c:0.0273465005242):9.05326020871e-05,(((Bst@Bostr_13083s0053_1:0.0332592496158,((Aly@AL8G21130_t1:0.0328569260951,Ath@AT5G48370_1:0.0391706378372):0.0205924636564,(Chi@CARHR183840_1:0.0954469923893,Cru@Carubv10026342m:0.0570981548016):0.00998579652059):0.0150356382287):0.0340484449097,(((Hco@scaff1034_g23864_DN3_SP8_c_TE35_CDS100:0.00823215335663,Hlo@DN13684_c0_g1_i1_p1:0.0085462978729):0.0144626717872,Hla@DN22821_c0_g1_i1_p1:0.0225079453622):0.0206478928557,Hse@DN23412_c0_g1_i3_p1:0.048590776459):0.0372829371381):0.00859075940423,(Esa@Thhalv10004228m:0.0378509854703,Aal@Aa_G102140_t1:0.0712272454125):1.00000050003e-06):0.00328120860999):0.0129090235079):0.0129090235079;'

    tree = Phylo.read(io.StringIO(s), 'newick')
    print(' before '.center(20, '='))
    print(tree)

    for n in tree.find_elements():
        if n.name and '@' in n.name:
            n.name = n.name.split('@')[0]

    print(' result '.center(20, '='))
    out = io.StringIO()
    Phylo.write(tree, out, "newick")
    print(out.getvalue())

Вывод:

====== before ======
Tree(rooted=False, weight=1.0)
    Clade(branch_length=0.0129090235079)
        Clade(branch_length=0.0726396855636, name='Esy@ESY15_g64743_DN3_SP7_c0')
        Clade(branch_length=0.137507902808, name='Aar@AA_maker7399_1')
        Clade(branch_length=0.0129090235079)
            Clade(branch_length=9.05326020871e-05)
                Clade(branch_length=0.0318934795022, name='Spa@Tp2g18720')
                Clade(branch_length=0.0273465005242, name='Cpl@CP2_g48793_DN3_SP8_c')
            Clade(branch_length=0.00328120860999)
                Clade(branch_length=0.00859075940423)
                    Clade(branch_length=0.0340484449097)
                        Clade(branch_length=0.0332592496158, name='Bst@Bostr_13083s0053_1')
                        Clade(branch_length=0.0150356382287)
                            Clade(branch_length=0.0205924636564)
                                Clade(branch_length=0.0328569260951, name='Aly@AL8G21130_t1')
                                Clade(branch_length=0.0391706378372, name='Ath@AT5G48370_1')
                            Clade(branch_length=0.00998579652059)
                                Clade(branch_length=0.0954469923893, name='Chi@CARHR183840_1')
                                Clade(branch_length=0.0570981548016, name='Cru@Carubv10026342m')
                    Clade(branch_length=0.0372829371381)
                        Clade(branch_length=0.0206478928557)
                            Clade(branch_length=0.0144626717872)
                                Clade(branch_length=0.00823215335663, name='Hco@scaff1034_g23864_DN3_SP8_c_TE35_CDS100')
                                Clade(branch_length=0.0085462978729, name='Hlo@DN13684_c0_g1_i1_p1')
                            Clade(branch_length=0.0225079453622, name='Hla@DN22821_c0_g1_i1_p1')
                        Clade(branch_length=0.048590776459, name='Hse@DN23412_c0_g1_i3_p1')
                Clade(branch_length=1.00000050003e-06)
                    Clade(branch_length=0.0378509854703, name='Esa@Thhalv10004228m')
                    Clade(branch_length=0.0712272454125, name='Aal@Aa_G102140_t1')

==== result =====
(Esy:0.07264,Aar:0.13751,((Spa:0.03189,Cpl:0.02735):0.00009,(((Bst:0.03326,((Aly:0.03286,Ath:0.03917):0.02059,(Chi:0.09545,Cru:0.05710):0.00999):0.01504):0.03405,(((Hco:0.00823,Hlo:0.00855):0.01446,Hla:0.02251):0.02065,Hse:0.04859):0.03728):0.00859,(Esa:0.03785,Aal:0.07123):0.00000):0.00328):0.01291):0.01291;

Формат Phylo по умолчанию использует меньше цифр, чем в исходном дереве. Чтобы сохранить числа без изменений, просто переопределите строку формата длины ветви с помощью «% s»:

Phylo.write(tree, out, "newick", format_branch_length="%s")
0 голосов
/ 27 апреля 2020

Как насчет такого рода функции:

def parse_string(string):
    new_string = ''
    skip = False
    for char in string:
        if char == '@':
            skip = True
        if char == ',':
            skip = False
        if not skip or char in ['(', ')']:
            new_string += char
    return new_string

Вызов ее в вашей строке:

string = '(Esy@ESY15_g64743_DN3_SP7_c0:0.0726396855636,Aar@AA_maker7399_1:0.137507902808,((Spa@Tp2g18720:0.0318934795022,Cpl@CP2_g48793_DN3_SP8_c:0.0273465005242):9.05326020871e-05,(((Bst@Bostr_13083s0053_1:0.0332592496158,((Aly@AL8G21130_t1:0.0328569260951,Ath@AT5G48370_1:0.0391706378372):0.0205924636564,(Chi@CARHR183840_1:0.0954469923893,Cru@Carubv10026342m:0.0570981548016):0.00998579652059):0.0150356382287):0.0340484449097,(((Hco@scaff1034_g23864_DN3_SP8_c_TE35_CDS100:0.00823215335663,Hlo@DN13684_c0_g1_i1_p1:0.0085462978729):0.0144626717872,Hla@DN22821_c0_g1_i1_p1:0.0225079453622):0.0206478928557,Hse@DN23412_c0_g1_i3_p1:0.048590776459):0.0372829371381):0.00859075940423,(Esa@Thhalv10004228m:0.0378509854703,Aal@Aa_G102140_t1:0.0712272454125):1.00000050003e-06):0.00328120860999):0.0129090235079):0.0129090235079;'
parse_string(string)
> '(Esy,Aar,((Spa,Cpl),(((Bst,((Aly,Ath),(Chi,Cru))),(((Hco,Hlo),Hla),Hse)),(Esa,Aal))))'
...