Python으로 DNA 서열 분석하기
이 토픽을 마치면
Python으로 DNA 서열의 GC content를 계산하고, FASTA 파일을 파싱하고, 코돈을 아미노산으로 변환할 수 있습니다.
변수: 데이터를 담는 그릇
실험 노트에 "시료 농도: 2.5 mg/mL"이라고 적듯, Python에서는 변수에 값을 저장합니다.
gene_name = "BRCA1"sequence = "ATGCGATCGATCGATCG"gc_ratio = 0.529
print(f"유전자: {gene_name}")print(f"서열 길이: {len(sequence)}bp")print(f"GC 비율: {gc_ratio:.1%}")
assert gene_name == "BRCA1"assert len(sequence) == 17문자열: DNA 서열 다루기
DNA 서열은 A, T, G, C 네 글자로 이루어진 문자열(string)입니다. Python의 문자열 메서드로 서열을 분석할 수 있습니다.
sequence = "ATGCGATCGATCGATCG"
# 특정 염기 개수 세기g_count = sequence.count("G")c_count = sequence.count("C")print(f"G: {g_count}개, C: {c_count}개")
# 상보 서열 만들기 (A↔T, G↔C)complement_table = str.maketrans("ATGC", "TACG")complement = sequence.translate(complement_table)print(f"원본: {sequence}")print(f"상보: {complement}")print(f"역상보: {complement[::-1]}")
assert complement == "TACGCTAGCTAGCTAGC"assert complement[::-1] == "CGATCGATCGATCGCAT"함수: GC Content 계산기
함수(function)는 실험 프로토콜의 한 단계를 재사용 가능하게 포장한 것입니다. 한 번 만들면 어떤 서열에든 적용할 수 있습니다.
def calculate_gc_content(sequence: str) -> float: sequence = sequence.upper() gc_count = sequence.count("G") + sequence.count("C") return (gc_count / len(sequence)) * 100
# 테스트seq1 = "ATGCGATCGATCGATCG"seq2 = "AAAAAAAAAA"seq3 = "GGGGGGGGGG"
print(f"seq1 GC: {calculate_gc_content(seq1):.1f}%")print(f"seq2 GC: {calculate_gc_content(seq2):.1f}%")print(f"seq3 GC: {calculate_gc_content(seq3):.1f}%")
assert abs(calculate_gc_content(seq1) - 52.9) < 0.1assert calculate_gc_content(seq2) == 0.0assert calculate_gc_content(seq3) == 100.0리스트와 반복문: 여러 서열 한 번에 처리
96-well plate의 모든 well에 같은 처리를 하듯, 반복문(for loop)은 여러 데이터에 같은 작업을 반복합니다.
def calculate_gc_content(sequence: str) -> float: sequence = sequence.upper() gc_count = sequence.count("G") + sequence.count("C") return (gc_count / len(sequence)) * 100
genes = { "BRCA1": "ATGGATTTATCTGCTCTTCGCGTTGAAGAAGTACAAAATGTC", "TP53": "ATGGAGGAGCCGCAGTCAGATCCTAGCGTGAGTTTGCTGTGA", "EGFR": "ATGCGACCCTCCGGGACGGCCGGGGCAGCGCTCCTGGCGCTG",}
results = []for name, seq in genes.items(): gc = calculate_gc_content(seq) results.append(gc) print(f"{name}: GC={gc:.1f}%, 길이={len(seq)}bp")
assert len(results) == 3assert all(0 <= gc <= 100 for gc in results)딕셔너리: FASTA 파일 파싱
딕셔너리(dictionary)는 실험 시료에 라벨을 붙이는 것과 같습니다. 유전자 이름(키)으로 서열(값)을 바로 찾을 수 있습니다.
def parse_fasta(fasta_text: str) -> dict[str, str]: sequences: dict[str, str] = {} current_header = "" for line in fasta_text.strip().split("\n"): if line.startswith(">"): current_header = line[1:].strip() sequences[current_header] = "" else: sequences[current_header] += line.strip() return sequences
sample_fasta = """>BRCA1_humanATGGATTTATCTGCTCTTCGCGTTGAAGAAGTACAAAATGTC>TP53_humanATGGAGGAGCCGCAGTCAGATCCTAGCGTGAGTTTGCTGTGA"""
result = parse_fasta(sample_fasta)print(f"파싱된 서열 수: {len(result)}")for name, seq in result.items(): print(f" {name}: {len(seq)}bp")
assert len(result) == 2assert result["BRCA1_human"] == "ATGGATTTATCTGCTCTTCGCGTTGAAGAAGTACAAAATGTC"assert result["TP53_human"] == "ATGGAGGAGCCGCAGTCAGATCCTAGCGTGAGTTTGCTGTGA"코돈 → 아미노산 변환
DNA 서열 3글자(코돈)가 하나의 아미노산을 지정합니다. 이 변환 테이블을 딕셔너리로 만들 수 있습니다.
CODON_TABLE = { "ATG": "M", # Methionine (시작코돈) "TTT": "F", "TTC": "F", # Phenylalanine "TTA": "L", "TTG": "L", "CTT": "L", "CTC": "L", # Leucine "GAT": "D", "GAC": "D", # Aspartic acid "GAA": "E", "GAG": "E", # Glutamic acid "GCT": "A", "GCC": "A", # Alanine "TAA": "*", "TAG": "*", "TGA": "*", # 종결코돈}
def translate_sequence(dna: str) -> str: protein = [] for i in range(0, len(dna) - 2, 3): codon = dna[i:i+3] amino_acid = CODON_TABLE.get(codon, "?") if amino_acid == "*": break protein.append(amino_acid) return "".join(protein)
test_seq = "ATGGATTTTGAA"protein = translate_sequence(test_seq)print(f"DNA: {test_seq}")print(f"Protein: {protein}")
assert protein == "MDFE"직접 해보기 (Faded Example)
아래 빈칸을 채워 GC content 계산 함수를 완성하세요.
def gc_content(seq):seq = seq.upper()gc = seq.count('G') + seq.count('')return / len(seq) * 100
흔한 에러 & 해결법
Q: IndentationError: expected an indented block
Python은 들여쓰기(indentation)로 코드 블록을 구분합니다. def, for, if 다음 줄은 반드시 스페이스 4칸 들여쓰기가 필요합니다.
Q: KeyError: 'BRCA1'
딕셔너리에 해당 키가 없을 때 발생합니다. dict.get("BRCA1", "없음")을 사용하면 키가 없어도 에러 없이 기본값을 반환합니다.
Q: 서열에 소문자가 섞여 있어서 count가 안 맞습니다
.upper()로 먼저 대문자 통일 후 처리하세요. 실제 FASTA 파일에서 소문자는 반복 서열(repeat-masked region)을 의미하기도 합니다.
다음 글에서는 Git으로 이 분석 코드를 버전 관리하는 법을 배웁니다.