str = "AGCCCTCCAGGACAGGCTGCATCAGAAGAGGCCATCAAGCAGGTCTGTTCCAAGGGCCTTTGCGTCAGATCACTGTCCTTCTGCCATGGCCCTGTGGATGCGCCTCCTGCCCCTGCTGGCGCTGCTGGCCCTCTGGGGACCTGACCCAGCCGCAGCCTTTGTGAACCAACACCTGTGCGGCTCACACCTGGTGGAAGCTCTCTACCTAGTGTGCGGGGAACGAGGCTTCTTCTACACACCCAAGACCCGCCGGGAGGCAGAGGACCTGCAGGTGGGGCAGGTGGAGCTGGGCGGGGGCCCTGGTGCAGGCAGCCTGCAGCCCTTGGCCCTGGAGGGGTCCCTGCAGAAGCGTGGCATTGTGGAACAATGCTGTACCAGCATCTGCTCCCTCTACCAGCTGGAGAACTACTGCAACTAGACGCAGCCCGCAGGCAGCCCCACACCCGCCGCCTCCTGCACCGAGAGAGATGGAATAAAGCCCTTGAACCAGC" DNAString:
Aku bukanlah orang dalam bidang biologi, tapi aku rasa elok kalau aku kongsikan apa yang aku sudah belajar. Pada pertengahan tahun lepas, aku ada ajar seorang kawan aku pengaturcaraan Python. Memandangkan dia adalah orang dari bidang biologi, kita sama-sama belajar menterjemah DNA menjadi protein berdasarkan siri tutorial yang telah disediakan oleh saluran YouTube RebelCoder.
Dogma Pusat Biologi Molekul
Dogma pusat ialah satu set penjelasan aliran maklumat genetik dalam sistem biologi. Salah satunya ialah aliran bagaimana DNA boleh menghasilkan rantaian protein yang membentuk kehidupan. Secara ringkasnya, DNA menghasilkan RNA melalui proses transkripsi kemudian RNA akan menghasilkan protein melalui proses penterjemahan.
Walaupun dogma pusat mengatakan protein dihasilkan daripada RNA, kita boleh langkau langkah ini kerana bentuk RNA sama sahaja seperti DNA kecuali bes timina (T) DNA diganti dengan bes urasil (U) RNA. Oleh itu, pengabaian langkah ini tidak akan menjejaskan hasil akhir protein bagi tujuan kita.
Rumusan dogma pusat boleh didapati dalam video ini oleh Coretan Biologi:
Sifar: Sediakan Data
Kita akan gunakan data dari National Center for Biotechnology Information sebagai contoh untuk tulisan ini. Khususnya, data insulin homo sapiens NM_001185097.2
(Pergi ke pautan FASTA untuk dapatkan jujukan DNAnya) Kita namakannya DNAString
.
Pertama: Sediakan Pasangan Pemadanan
Setiap asid amino dalam protein merupakah hasil bacaan satu set tiga bes serangkai yang dinamakan kodon. Oleh itu, kita perlu beritahu kod kita kodon apa akan hasilkan asid apa. Kita sediakan satu dict
dengan nilai berikut:
dict = {
DNA_Codons_Mapping: "GCT": "A", "GCC": "A", "GCA": "A", "GCG": "A",
"TGT": "C", "TGC": "C",
"GAT": "D", "GAC": "D",
"GAA": "E", "GAG": "E",
"TTT": "F", "TTC": "F",
"GGT": "G", "GGC": "G", "GGA": "G", "GGG": "G",
"CAT": "H", "CAC": "H",
"ATA": "I", "ATT": "I", "ATC": "I",
"AAA": "K", "AAG": "K",
"TTA": "L", "TTG": "L", "CTT": "L", "CTC": "L", "CTA": "L", "CTG": "L",
"ATG": "M", # Kodon pemula
"AAT": "N", "AAC": "N",
"CCT": "P", "CCC": "P", "CCA": "P", "CCG": "P",
"CAA": "Q", "CAG": "Q",
"CGT": "R", "CGC": "R", "CGA": "R", "CGG": "R", "AGA": "R", "AGG": "R",
"TCT": "S", "TCC": "S", "TCA": "S", "TCG": "S", "AGT": "S", "AGC": "S",
"ACT": "T", "ACC": "T", "ACA": "T", "ACG": "T",
"GTT": "V", "GTC": "V", "GTA": "V", "GTG": "V",
"TGG": "W",
"TAT": "Y", "TAC": "Y",
"TAA": "_", "TAG": "_", "TGA": "_" # Kodon berhenti
}
Pemetaan ini memberitahu kita bahawa jujukan bes "GCT"
akan menghasilkan asid A
dan seterusnya. Setiap asid diwakili oleh satu huruf yang merujuk kepada huruf pertama nama asid tersebut. Kodon yang berbeza boleh menghasilkan asid yang sama.
Perlulah kita ketahui akan dua huruf penting yang aku beri komen dalam kod di atas. Huruf pertama ialah huruf M
yang merujuk kepada asid metionina yang dihasilkan oleh kodon "ATG"
. Kodon ini dinamakan βkodon pemulaβ kerana ia mengisytiharkan permulaan rantaian asid amino.
Huruf kedua pula ialah huruf _
yang dihasilkan oleh tiga kodon berbeza. Kodon-kodon ini pula merupakan βkodon berhentiβ: ia memberitahu agar pembinaan rantaian asid perlu berhenti. Ia tidak mewakili apa-apa asid, maka simbol _
dipilih.
Secara ringkasnya, rantaian asid amino tidak akan dihasilkan selagi mana kodon pemula tidak dijumpai. Kemudian, rantaian itu akan diputuskan ketika bertemu dengan kodon berhenti. Hasil rantaian itulah protein makhluk tersebut.
Sampingan: Pengesahan Jujukan DNA
Langkah ini bukanlah satu kewajipan, tatepi ia bantu melancarkan algoritma kita supaya kita tak masukkan input yang tak sah. Kita gunakan langkah ini untuk memastikan jujukan huruf yang dimasukkan itu adalah jujukan DNA yang sah. Bila dah melalui pengesahan ini, kita boleh yakin yang tidak ada set huruf yang pelik seperti ABC
yang akan mengeluarkan ralat kerana tiada padanan langsung.
Untuk pastikan jujukan kita hanya mempunyai huruf-huruf yang dibenarkan sahaja, kita boleh siapkan satu tuple
bes-bes DNA dan semak keahlian huruf-huruf dalam jujukan input. Kita guna tuple
dan bukan list
sebab kita nak elakkan kesilapan penambahan huruf yang tidak disengajakan. Disebabkan tuple
tidak membenarkan penambahan ahli, maka ia adalah calon yang baik.
tuple = ("A", "C", "G", "T") DNA_Bases:
Kemudian, kita sediakan fungsi validate_sequence()
yang akan memunculkan ralat sekiranya inputnya tidak sah. Perkara sedekimian boleh dicapai dengan mengambil setiap huruf dalam dna_seq
dan raise ValueError
sekiranya huruf tersebut tiada dalam tuple
yang disediakan. Sekiranya, ia bertemu dengan huruf yang tidak sah, raise ValueError
akan menghentikan program.
def validate_sequence(dna_seq: str) -> str:
"""Semak sama ada input adalah jujukan DNA adalah sah"""
= dna_seq.upper()
check_seq for nuc in check_seq:
if nuc not in DNA_Bases:
raise ValueError(f"Jujukan tidak sah. `{nuc}` bukan ahli {DNA_Bases=}")
return check_seq
Kita akan sahkan DNAString
kita.
=DNAString) validate_sequence(dna_seq
'AGCCCTCCAGGACAGGCTGCATCAGAAGAGGCCATCAAGCAGGTCTGTTCCAAGGGCCTTTGCGTCAGATCACTGTCCTTCTGCCATGGCCCTGTGGATGCGCCTCCTGCCCCTGCTGGCGCTGCTGGCCCTCTGGGGACCTGACCCAGCCGCAGCCTTTGTGAACCAACACCTGTGCGGCTCACACCTGGTGGAAGCTCTCTACCTAGTGTGCGGGGAACGAGGCTTCTTCTACACACCCAAGACCCGCCGGGAGGCAGAGGACCTGCAGGTGGGGCAGGTGGAGCTGGGCGGGGGCCCTGGTGCAGGCAGCCTGCAGCCCTTGGCCCTGGAGGGGTCCCTGCAGAAGCGTGGCATTGTGGAACAATGCTGTACCAGCATCTGCTCCCTCTACCAGCTGGAGAACTACTGCAACTAGACGCAGCCCGCAGGCAGCCCCACACCCGCCGCCTCCTGCACCGAGAGAGATGGAATAAAGCCCTTGAACCAGC'
Contoh 1 Katakan kita gunakan jujukan DNA yang tidak sah. Maka, kita dapat lihat yang ValueError
akan dikemukakan.
='GAYA') validate_sequence(dna_seq
ValueError: Jujukan tidak sah. `Y` bukan ahli DNA_Bases=('A', 'C', 'G', 'T')
Kedua: Proses Terjemahan
Sekarang ini, kita perlu beritahu komputer supaya dapatkan tiga bes serangkai, pastu padankan dengan asid menggunakan pemetaan DNA_Codons_Mapping
yang kita dah sediakan sebelum ini. Namun begitu, perlu ditegaskan bahawa pembacaan huruf tidak semestinya bermula dari huruf pertama. Misalnya, katalah kita ada jujukan ABCDEF
, pembacaan boleh mula dari A
, B
, C
, D
atau seterusnya. Oleh itu, kita sediakan satu pembolehubah kedudukan awal init_pos
dengan nilai asal 0
yang kita boleh tentukan kemudian.
def make_translation(dna_seq: str, init_pos: int = 0) -> list:
"""Menterjemahkan jujukan input menjadi senarai asid amino"""
= list()
acids # Lelaran akan melangkau setiap tiga huruf sebab itulah panjang satu kodon
for pos in range(init_pos, len(dna_seq) - 2, 3):
= dna_seq[pos:pos + 3]
codon
acids.append(DNA_Codons_Mapping[codon])return acids
Fungsi ini akan memulangkan senarai asid kerana memang itulah yang kita mahukan.
from typing import List # Membolehkan kita nyatakan jenis isi dalam `List`
str] = make_translation(dna_seq=DNAString)
senarai_asid_amino: List[','.join(senarai_asid_amino)
'S,P,P,G,Q,A,A,S,E,E,A,I,K,Q,V,C,S,K,G,L,C,V,R,S,L,S,F,C,H,G,P,V,D,A,P,P,A,P,A,G,A,A,G,P,L,G,T,_,P,S,R,S,L,C,E,P,T,P,V,R,L,T,P,G,G,S,S,L,P,S,V,R,G,T,R,L,L,L,H,T,Q,D,P,P,G,G,R,G,P,A,G,G,A,G,G,A,G,R,G,P,W,C,R,Q,P,A,A,L,G,P,G,G,V,P,A,E,A,W,H,C,G,T,M,L,Y,Q,H,L,L,P,L,P,A,G,E,L,L,Q,L,D,A,A,R,R,Q,P,H,T,R,R,L,L,H,R,E,R,W,N,K,A,L,E,P'
Ketiga: Semua Kemungkinan Senarai Asid
Untuk setiap jujukan DNA, ada enam kemungkinan senarai asid yang boleh dihasilkan. Hal ini kerana setiap kodon boleh mula dibaca dari mana-mana tiga huruf dalam jujukan tersebut. Perkara ini menghasilkan 3 kemungkinan. Tambahan pula, jujukan DNA tersebut ada pasangannya, maka pasangannya juga akan menghasilkan 3 kemungkinan senarai asidnya yang tersendiri. Maka, jumlahnya ialah 6 kemungkinan.
Nampaknya bacaan kodon yang berbeza permulaannya dipanggil βrangka bacaanβ.
Contoh 2 Katakan ada jujukan DNA GATTAGCCAGATTAC
, boleh jadi kodonnya adalah begini:
GAT
TAG
CCA
GAT
TAC
β Jujukan input- G
ATT
AGC
CAG
ATT
AC - GA
TTA
GCC
AGA
TTA
C CTA
ATC
GGT
CTA
ATG
β Jujukan pasangan- C
TAA
TCG
GTC
TAA
TG - CT
AAT
CGG
TCT
AAT
G
Apa yang kita perlu buat ialah panggil fungsi yang sama berulang kali dengan init_pos
yang berbeza. Selain itu, kita juga perlu ada satu fungsi yang akan hasilkan pasangan jujukan input.
def make_complement(dna_seq: str) -> str:
"""Menghasilkan pasangan jujukan yang melekat bersama dengan jujukan input"""
= str.maketrans('ATGC', 'TACG')
mapping return dna_seq.translate(mapping)
def make_reverse_complement(dna_seq: str) -> str:
"""Menterbalikkan pasangan jujukan (sebab pasangannya dibaca berlawanan arah)"""
return make_complement(dna_seq)[::-1]
def make_reading_frames(dna_seq: str) -> List[List[str]]:
"""Menghasilkan kesemua enam (6) rangka bacaan daripada jujukan bes DNA yang diberikan."""
= []
frames 0))
frames.append(make_translation(dna_seq, 1))
frames.append(make_translation(dna_seq, 2))
frames.append(make_translation(dna_seq, 0))
frames.append(make_translation(make_reverse_complement(dna_seq), 1))
frames.append(make_translation(make_reverse_complement(dna_seq), 2))
frames.append(make_translation(make_reverse_complement(dna_seq), return frames
Keempat: Mencari Kodon Mula dan Kodon berhenti
Kita perlu sediakan arahan supaya:
- Jika ia adalah kodon berhenti,
_
, maka hentikan rantaian jika wujud. - Jika ia adalah asid dari kodon mula,
M
, maka mulakan rantaian. - Jika ia adalah asid biasa, maka sambung rantaian jika wujud ataupun langkau jika tiada rantaian.
def make_proteins_from_one_reading_frame(amino_acid_seq: list) -> list:
"""Menghasilkan calon protein dengan mengenal pasti kodon pemula dan kodon berhenti"""
= []
current_protein = []
proteins for amino_acid in amino_acid_seq:
if amino_acid == "_":
# Hentikan rantain
if current_protein:
# Dapatkan rantaian jika wujud
for p in current_protein:
proteins.append(p)= []
current_protein else:
if amino_acid == "M":
# Mulakan rantaian
"")
current_protein.append(for i in range(len(current_protein)):
# Operasi ini tidak akan buat apa-apa kalau tiada `""` yang dihasilkan oleh syarat sebelum ini
+= amino_acid
current_protein[i] return proteins
Kemudian, kita boleh dapatkan semua protein yang mungkin dihasilkan oleh jujukan DNA serta pasangannya.
def make_proteins_from_all_reading_frames(dna_seq: str, ordered=False) -> List[str]:
"""Menghasilkan calon protein daripada semua rangka bacaan yang dihasilkan dari sejujuk DNA"""
= make_reading_frames(dna_seq)
frames
= []
potential_proteins for frame in frames:
= make_proteins_from_one_reading_frame(frame)
proteins for p in proteins:
potential_proteins.append(p)
# Susun supaya yang paling panjang berada di atas
if ordered:
= sorted(potential_proteins, key=len, reverse=True)
potential_proteins
return potential_proteins
Hasil
=DNAString) make_proteins_from_all_reading_frames(dna_seq
['MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN',
'MRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN',
'ME',
'MLVQHCSTMPRFCRDPSRAKGCRLPAPGPPPSSTCPTCRSSASRRVLGV',
'MPRFCRDPSRAKGCRLPAPGPPPSSTCPTCRSSASRRVLGV',
'MAEGQ']
Kalau dibandingkan dengan maklumat /translation
yang ada pada pautan insulin homo sapiens NCBI, ternyata ia padan dengan rantaian pertama hasil algoritma aku. Cubalah buat sendiri dan cuba padankannya dengan data lain. Kod-kod yang ditulis ada disediakan dalam repositori GitHub. Bolehlah gunakannya sebagai rujukan.