Leaderboard Algoritam

Leaderboard algoritam [2] je optimizovani pristup za sekvenciranje peptida. Za razliku od sekvenciranja grubom silom koje zahteva tačno poklapanje između teorijskog spektra kandidata i eksperimentalnog spektra, ovaj algoritam je dizajniran da radi sa nedostajućim i lažnim masama tako što prati samo najbolje kandidate peptida umesto svih mogućnosti.

U realnim eksperimentalnim podacima masene spektrometrije, izmereni eksperimentalni spektar je često zašumljen i nepotpun. Neki očekivani fragmenti peptida mogu nedostajati, a lažni pikovi se mogu pojaviti zbog pozadinskog šuma. Savršeno poklapanje između teorijskog spektra peptida i eksperimentalnog spektra je malo verovatno.

Prednosti Algoritma

Efikasnost

Fokusira se samo na najperspektivnije kandidate, značajno smanjujući vreme izvršavanja

Skalabilnost

Efikasno radi sa peptidima različitih dužina bez eksponencijalnog rasta vremena

Preciznost

Održava visoku tačnost uprkos šumu u eksperimentalnim podacima

Primene

Eksperimentalni Podaci

Idealan za analizu realnih podataka masene spektrometrije sa šumom

Nepotpuni Podaci

Kada tačno poklapanje nije moguće zbog nepotpunih ili netačnih podataka u spektru

Vremenski Kritične Analize

Kada je potrebna brza identifikacija peptida iz velikih skupova podataka

Kod za Leaderboard algoritam

Algoritam održava listu najboljih kandidata (leaderboard) i u svakoj iteraciji proširuje samo najperspektivnije peptide. Ovo značajno smanjuje prostor pretrage u poređenju sa pristupom grube sile. Za svaki od peptida koji se generiše određujemo koji je njegov score, odnosno broj masa linearnog spektra peptida koji je jednak masama u eksperimentalnom spektru.

def leaderboard_sequencing(target_spectrum):
    # Krećemo od praznog peptida
    peptides = ['']

    # Peptid koji je trenutno najbolji kandidat i njegov score
    leader_peptide = ''
    leader_peptide_score = 0

    target_peptide_mass = target_spectrum[-1]

    while len(peptides) > 0:
        extended_peptides = extend(peptides, amino_acid_candidates)

        consistent_peptides = []

        for peptide in extended_peptides:
            peptide_mass = calculate_peptide_mass(peptide)
            if peptide_mass == target_peptide_mass:
                # Računamo koji je broj poklapanja cikličnog peptida sa eksperimentalnim spektrom
                peptide_score = cyclic_score(peptide, target_spectrum)
                # Ako je score bolji, ažuriramo vrednost najboljeg kandidata
                if peptide_score > leader_peptide_score:
                    leader_peptide = peptide
                    leader_peptide_score = peptide_score
            elif peptide_mass < target_peptide_mass:
                consistent_peptides.append(peptide)

        # Funkcija u kojoj se pravi lista kandidata i vraćaju samo najbolji kandidati
        peptides = trim(consistent_peptides, target_spectrum, MAX_NUMBER_OF_CANDIDATES)

    return leader_peptide

Jedna od glavnih funkcija je trim. Ulaz u funkciju predstavljaju peptidi koji su kandidati za rešenje, eksperimentalni spektar kao i broj peptida koji ćemo vratiti iz funkcije odnosno najbolji kandidati za potencijalno rešenje. Bitno je izabrati dobro broj kandidata koji prolazi u dalju rundu. U slučaju da je taj broj previše mali rizujemo da previše agresivno odsečemo neke kandidate i da potencijalno izgubimo rešenje. U slučaju da je borj previše veliki čuvaćemo previše kandidata i samim tim povećati vreme izvršavanja algoritma. Generalno, dobra je praksa ako se traže peptidi sa manjom masom da se koristi manji broj kandidata koji nastavlja u sledeću rundu a ako se masa poveća da se samim tim poveća i broj kandidata koji nastavlja u sledeću rundu.

def trim(peptides, target_spectrum, max_number_of_candidates):
    # Ako je broj peptida manji od broja kandidata koji može da prođe
    # u sledeću rundu, vraćamo sve peptide
    if len(peptides) <= max_number_of_candidates:
        return peptides

    leaderboard = []

    # Za svaki od peptida računamo njegov score
    for peptide in peptides:
        # Bitno je koristiti linear_score funkciju jer ovo nije finalni izgled peptida
        # samim tim, ako se koristi cyclic_score možemo da dobijemo mase koje možda neće
        # postojati kada se peptid proširi
        peptide_score = linear_score(peptide, target_spectrum)
        leaderboard.append((peptide_score, peptide))

    # Sortiramo listu peptida u opadajućem redosledu po njihovom score-u
    leaderboard.sort(reverse=True)

    # Ako u listi kandidata ima još neka sekvenca peptida čiji je 
    # score jednak poslednjoj sekvenci koja prolazi u sledeću rundu,
    # dodajemo i tu sekvencu da potencijalno ne bismo izgubili dobro
    # rešenje 
    for i in range(max_number_of_candidates, len(leaderboard)):
        if leaderboard[i][0] < leaderboard[max_number_of_candidates - 1][0]:
            break

    # Lista kandidata koja je prošla u sledeću rundu
    trimmed_leaderboard = leaderboard[:i]
    # Pošto smo u listi čuvali peptide sa njihovim rezultatima,
    # vraćamo samo listu peptida odnosno njihove sekvence
    return [el[1] for el in trimmed_leaderboard]

Funkcija cyclic_score računa broj poklapanja teorijskog spektra cikličnog peptida sa eksperimentalnim spektrom. Ova funkcija se koristi u slučaju da je masa peptida jednaka najvećoj teoorijskoj masi jer je u tom slučaju formiran ceo peptid i mogu da se nađu svi potpeptidi.

def cyclic_score(peptide, target_spectrum):
    # Formira se ciklični spektar i na osnovu njega se računa score
    peptide_cyclic_spectrum = cyclic_spectrum(peptide)
    return score(peptide_cyclic_spectrum, target_spectrum)

Funkcija linear_score računa broj poklapanja teorijskog spektra peptida sa eksperimentalnim spektrom. Ova funkcija se koristi kada se ceo peptid još ne zna i samim tim ne mogu da se kreiraju sve ciklične varijacije jer bi se dobile mase koje se možda ne bi dobile kada se peptid proširi aminokiselinama.

def linear_score(peptide, target_spectrum):
    # Formira se linearni spektar i na osnovu njega se računa score
    peptide_linear_spectrum = linear_spectrum(peptide)
    return score(peptide_linear_spectrum, target_spectrum)

Funkcija score računa broj poklapanja teorijskog spektra peptida sa eksperimentalnim spektrom.

def score(peptide_spectrum, target_spectrum):
    total_score = 0

    i = 0
    j = 0
    n = len(peptide_spectrum)
    m = len(target_spectrum)

    # Prolazi se kroz spektre i upoređuju mase
    while i < n and j < m:
        # Ako su mase jednake prelazimo na sledeće mase u oba spektra i uvećavamo broj poklapanja
        if peptide_spectrum[i] == target_spectrum[j]:
            i += 1
            j += 1
            total_score += 1
        # U slučaju da je masa teorijskog spektra veća, prelazimo na sledeću masu u eksperimentalnom spektru
        elif peptide_spectrum[i] > target_spectrum[j]:
            j += 1
        # U slučaju da je masa teorijskog spektra manja, prelazimo na sledeću masu u teorijskom spektru
        else:
            i += 1

    return total_score

U vizuelizaciji ispod, možete videti kako algoritam kroz runde bira N kandidata koji prolaze u sledeću rundu. Takođe, možete da vidite teorijske spektre kandidata kao i broj elemenata spektra koji su isti kao i u zadatom teorijskom spektru. Teorijski spektri kandidata mogu da se zumiraju da bi se lakše videli potpeptidi sa njihovim masama.
U poslednjoj rundi će biti prikazani peptidi koji predstavljaju najbolje kandidate za rešenje. Može imati više različitih kandidata s obzirom da različite aminokiseline mogu da imaju istu masu.
Dodatno, ako ne želite da vidite runde koje su se desile potrebno je da označite opciju da se prikažu samo rešenja.

Primeri peptida i njihovih teorijskih spektara:

  • NQE: [0, 114, 128, 129, 242, 243, 257, 371]
  • NQEL: [0, 113, 114, 128, 129, 227, 240, 242, 257, 355, 356, 370, 370, 484]
Unesi eksperimentalni spektar i klikni Analiziraj da vidiš vizualizaciju