[WGS 분석] SAM 파일 구조 이해하기

2026. 7. 1. 02:00·Bio Data Analysis/WGS(Whole Genome Seq)

앞의 글에서 실습 과정동안 인덱스 생성 및 정렬을 하며 생성한 SRR062634.sam 파일을 사용하여 SAM 파일의 구조를 확인해보고자 함.


일반적인 SAM 파일 구조

SAM 파일은 크게 두 섹션.

1. 헤더 (@로 시작)

태그 의미
@HD SAM 파일 버전 정보
@SQ Reference 서열 정보 (이름, 길이)
@RG Read group 정보 (샘플, 장비 등)
@PG 사용한 프로그램 정보

2. 정렬 레코드 (11개 필수 필드, 탭 구분)

번호  필드명 의미
1 QNAME Read 이름
2 FLAG 정렬 상태 (비트 플래그)
3 RNAME 정렬된 reference 이름
4 POS 정렬 시작 위치
5 MAPQ 매핑 품질
6 CIGAR 정렬 방식
7 RNEXT mate read reference
8 PNEXT mate read 위치
9 TLEN insert size
10 SEQ 염기서열
11 QUAL Quality score

내 컴퓨터의 SAM 파일 열기

head -20 ~/bioinfo/bi_study/wgs_practice/aligned/SRR062634.sam

 

# 출력 결과
@SQ	SN:chr20	LN:64444167
@PG	ID:bwa-mem2	PN:bwa-mem2	VN:2.2.1	CL:bwa-mem2 mem -t 4 /Users/kofe/bioinfo/bi_study/wgs_practice/ref/chr20.fa /Users/kofe/bioinfo/bi_study/wgs_practice/trimmed/SRR062634_1_paired.fastq /Users/kofe/bioinfo/bi_study/wgs_practice/trimmed/SRR062634_2_paired.fastq
SRR062634.1	77	*	0	0	*	*	0	0	GGGTTTTCCTGAAAAAGGGATTCAAGAAAGAAAACTTACATGAGGTGATTGT	@C'@9:BB:?DCCB5CC?5C=?5@CADC?BDB)B@?-A@=:=:@CC'C>5AA	AS:i:0	XS:i:0
SRR062634.1	141	*	0	0	*	*	0	0	CAGAAGAATGTAAACTCCAGGGGGACAGGAGTGCGTG	A>--?=C;C:=C=CC=D5D?C-:CAC:-5=;>?'6>@	AS:i:0	XS:i:0
SRR062634.2	69	chr20	2284335	0	*	=	2284335	0	ACCGTGAGCAATCAGCTGCCATCAACGTGGAGGTAAGACTCTCCACCTGCAAAAACATTACAACTTGCTGAAGGCTGAGATA	FDEFF?DFEFE?BEEEEED=DB:DCEAEEB,CC=@B=5?B?CC5C?B+A??=>:CC<9-B2=@>-?:-<A@@A?9>*0<:'0	MC:Z:7S67M26S	AS:i:0	XS:i:0
SRR062634.2	137	chr20	2284335	12	7S67M26S	=	2284335	0	CTGTCTCATAAAATAAAATAAAATAAAATAAATAAAATAAAATAAAATAAAATAAAATAAAATAAAATAAAATACCTTATTGCTAAAAAGGTGCTAACAA	DEEDAEEEEE:EB>E<>CCEEEBEEE<EDEAEE;EC<CEACAE;A>EEE@EE@E8>CEDA?C8DA68>D3B:@EE=-AAC-CA5CDBDBE?:C@?BC?,?	NM:i:0	MD:Z:67	AS:i:67	XS:i:62	XA:Z:chr20,+9852728,7S22M1D47M24S,1;chr20,+44349131,13S59M28S,0;chr20,+19923416,19S55M26S,0;chr20,-35946652,38S55M7S,0;
SRR062634.3	77	*	0	0	*	*	0	0	TAGATATTTTTGTTTTAACTGCTGTAGAAAATTAAGACATAAACTAAGAAATATCCCATGAAGGAATGAGTATACTGT	-?3-C22646@-@3@@3-=-====CBB@DB-A-=-AA@C-<AA7>D=ABDA;?CDDDD5D?DD55:>:AB>5?-CCCC	AS:i:0	XS:i:0
SRR062634.3	141	*	0	0	*	*	0	0	TCAGGTGAATAAATTGAGAACAAATCTTGGAATCATGGAGAATGGATAGTCCAGAAAGAAAGA	:B5DDBDD:5DD6;:D:D5DBD6?ADD-DD=B5DAB=5@A5AC5A--=::-C:5>5A2+C-)9	AS:i:0	XS:i:0
SRR062634.4	77	*	0	0	*	*	0	0	AGATGAGTTTCACAAAGTAAGCAACTTGATATCCAAATAATCAACACCCAACTCAAGAAAAAGATCATTACCAGAAACTAATAAACCAGCACA	??EEEDB?D-?AAA-AA?>->BC:ADB:--A55ACCA:D6C:?5@CADD6=C5:CD?D4;,::?,CC-5A@C-?D5@+-BB?BC*A-A?C:C@	AS:i:0	XS:i:0
SRR062634.4	141	*	0	0	*	*	0	0	ATCATTCCACAGGGTGGATCCTGCTTCTTAGAAAGATAAGGTATGCTATAAGGAGTCTCATTTCTCGATATTATAAGATTACGAGTACTAATACA	DD:??DD:5DA-5A5=6+?CC5=C-A<CA*.@<@@(5B=@D:B:D=-5AA:=:=,5A:B??::-4(9;<;:>'B5BD:BB5:C:@5:->?B5C:?	AS:i:0	XS:i:0
SRR062634.5	77	*	0	0	*	*	0	0	CTGTATCTAGGTTTTGTCCTTACATGTATATAACCTACACCCAC	CC?-?BAAB?E:B@@A7A?5CCBBBB@B?ABB?B@BB=B-BB=AS:i:0	XS:i:0
SRR062634.5	141	*	0	0	*	*	0	0	GGCAAGAACTGGGAAGGAACAAATTCAAGTGGGCTTTTAGCATAGTAAGAGAACACTGTCCTTCAGTCTGATCATTTCAGGGAGG	B?D:C=5DDDDDDBBCC:DCCC3=DB55DDBBDBCD:A?D=-@==-8.@74):266;=<<:BAB,??B@@->==-??B5==>'@@	AS:i:0	XS:i:0
SRR062634.6	77	*	0	0	*	*	0	0	TTAGGTTTTAATGTTTGGGAAACTAAATCTCTCCTCTATCCAAGTGTACATGCTTTCGTTTTATCCCTTTGTCTC	C??=-C=ACCD?BD56DDD?DD5CD.=*;BC5-C:ACA??D=-A?C@:??5AC:==CC=C:A?>4:186?58C5C	AS:i:0	XS:i:0
SRR062634.6	141	*	0	0	*	*	0	0	ATCAGAGGTTTACAAACTCTAAGTCACAAAATCAGCTCACAGGCCACTATAAAATAGTCA	:-D5=C=C=::AA>ABDD?=A-A?BC?55CDA?=?5BB?@-@C5CB=?B?:BC=AB?4AA	AS:i:0	XS:i:0
SRR062634.7	99	chr20	30524085	15	3S57M1S	=	30524220	171	GATGTGCAGGTTTGTTACACAGGTAAATGTGTGCCATGGTGGTTTGCTGCACCTATCAACC	C?C6/AABAAFFDE=?>D@DA>5<?AC?C-C?BDBC-CA=C?A:AB@A5D??B?C5E?BBB	NM:i:4	MD:Z:6A9T7C26G5	MC:Z:7M2D27M16S	AS:i:37	XS:i:51
SRR062634.7	147	chr20	30524220	15	7M2D27M16S	=	30524085	-171	AGGCCCCTGTATGTTGTTCCCCTTCCTGTGTCCACCATGTTTTTTTTTAA	A5=::?=5?EE5;EEDD-:AF=5:FDDD:D6EADDEB@B>=86C5-C?AA	NM:i:3	MD:Z:7^AA3G23	MC:Z:3S57M1S	AS:i:23	XS:i:23	XA:Z:chr20,+54021690,16S27M2D7M,3;chr20,-24211133,14S21M15S,0;chr20,-56066716,14S21M15S,0;chr20,+25883553,15S21M14S,0;
SRR062634.8	77	*	0	0	*	*	0	0	TATAATTTACGAAAATTCTTTAATGCTGAAAAAAAGATGAAAATTCATTAATCTGAATGTCAATTCGGTCTTGTTCCAAACAGTTTTTTTTTGTTTGT	DCA5DCD5:DB-DD=C5AC-;AAA5C@@->AAA;)=(;A>-C:CCCB:B=:>A;A+==?;,@>@,BDCBDB5=B:@-5@'=@A>-C,A06;<>8<+3B	AS:i:0	XS:i:0
SRR062634.8	141	*	0	0	*	*	0	0	TTGAGAGAATAAACTTGCCTTTAGCCTCCTTTAATTTTTACCTTTTATCTTTGGCTGAGG	?BADDDDD5BDDD>DD:-DD:DB=C.@4>0>-;>>DDDDDCB-A:;44=@:CC?-;;>6@	AS:i:0	XS:i:0
SRR062634.9	77	*	0	0	*	*	0	0	GTGAAAGCTTAATGATACCATATGTGCTAAATTGTAAATTAATCTATCTCACCCGTTTCAGGAATTTCT	=FDFEDEDBCD@?BCCDECA6,;@<DAB=5@5?D?:5?DCBB5?:E:CEC?EE=4A>:=>C-A?A==CC	AS:i:0	XS:i:0
SRR062634.9	141	*	0	0	*	*	0	0	TCCTTTCCCTCAATTATATTAGTCAGGATTTATTCTTGGACCTATTAATACTGAAAAGACATTCCTGAAACGGGTGAGATAGATTAATTTACAATTTAGC	EED-EC55ACC=:-DD:==?DD:D5?>@-?5?C;CBEED-CC=C-@@;.B==D?::-AA-4;C@=E5E??D7:D:DC?A5->-<ACB?=BBB-BB<--AC	AS:i:0	XS:i:0

 

 

내 SAM 파일 헤더 섹션 (@로 시작하는 줄)

@SQ  SN:chr20  LN:64444167
@PG  ID:bwa-mem2 ~
  • @SQ — reference 서열 정보. chr20 길이가 64,444,167bp 라고 하는 것.
  • @PG — 어떤 툴로 만들었는지. bwa-mem2 명령어까지 기록됨.

정렬 레코드 (나머지 줄들)

한 줄이 read 하나.

탭으로 구분된 필드들인데, 

밑이 실제로 chr20에 정렬된 read:

SRR062634.7  99  chr20  30524085  15  3S57M1S  =  30524220  171  GATGTGCAG...

내 컴퓨터의 SAM 파일 구조 분석

SRR062634.7  99  chr20  30524085  15  3S57M1S  =  30524220  171  GATGTGCAG...  C?C6/AAB...

 

20번 염색체로 정렬된 SRR062634.7 read 를 두고 구조를 확인하려고 함.

필드 현재 필드값 의미
QNAME SRR062634.7 read 이름(SRR062634번 read 그룹의 7번째 DNA 조각)
FLAG 99 정렬 상태(밑에서 자세히 설명)
RNAME chr20 chr20에 정렬됨
POS 30524085 chr20의 30,524,085번째 위치부터 시작
MAPQ 15 매핑 신뢰도 (0~60, 높을수록 좋음)
CIGAR 3S57M1S 정렬 방식 (밑에서 설명)
RNEXT = mate(짝)도 같은 chr20에 있음
PNEXT 30524220 mate의 시작 위치
TLEN 171 이 read 쌍의 전체 DNA 조각 길이
SEQ GATGTGCAG... 정렬된 염기서열
QUAL C?C6/AAB... 염기별 품질

 

여기서 FLAG 99가 핵심.


FLAG 필드의 의미

FLAG는 2진수로 변환해서 각 자리가 다른 의미를 가짐.

99를 2진수로 바꾸면

99 = 64 + 32 + 2 + 1 = 1100011

 

비트값 의미 99에 해당히기 위한 비트값 여부
1 read가 paired-end ✅
2 정확하게 매핑된 쌍 (proper pair) ✅
4 read 자체가 매핑 안 됨 ❌
8 mate가 매핑 안 됨 ❌
16 read가 역방향(REVERSE) ❌
32 mate가 역방향(MREVERSE) ✅
64 이 read가 쌍 중 첫 번째(_1) ✅
128 이 read가 쌍 중 두 번째(_2) ❌

 

즉 FLAG 99는 "paired-end고, 정확히 매핑됐고, 이 read는 정방향(forward)이고, 짝(mate)은 역방향이고, 이 read가 _1(첫 번째)이다" 라는 뜻.

FLAG 비트값은 매번 손으로 계산 안 해도 되고, samtools flags 명령어로 바로 해석할 수 있음.

samtools flags 99

# 출력
# 0x63	99	PAIRED,PROPER_PAIR,MREVERSE,READ1

 

 

여기서

PAIRED : paired-end read
PROPER_PAIR : 정확하게 매핑된 쌍
MREVERSE : mate(짝)가 역방향
READ1 : 이 read가 _1


CIGAR 필드의 의미

CIGAR는 read가 reference에 어떻게 매칭됐는지 패턴으로 보여줌.

3S57M1S

 

이걸 쪼개면 3S + 57M + 1S.

 

코드 의미
M Match/Mismatch — reference랑 매칭됨 (일치하든 불일치하든)
S Soft clip — 정렬 안 되고 잘려나간 부분
I Insertion — read에는 있는데 reference엔 없는 염기
D Deletion — reference엔 있는데 read에는 없는 염기

 

3S57M1S 해석하면:

앞쪽 3bp  → 정렬 안 됨 (soft clip)
중간 57bp → reference랑 매칭됨
뒤쪽 1bp  → 정렬 안 됨 (soft clip)

 

총 61bp(3+57+1) read 중에 57bp만 실제로 chr20에 붙었다는 뜻.

앞뒤 끝부분은 매칭이 안 돼서 잘려나감.

read 길이가 100bp가 아니라 61bp인 것은 Trimming 때문이다.


SRR062634.7의 짝(mate) read 구조 분석

위에서 확인했으니 반대의 read도 해석.

SRR062634.7  147  chr20  30524220  15  7M2D27M16S  ...

 

samtools flags 147 명령어를 통해 PAIRED,PROPER_PAIR,REVERSE,READ2 출력값을 받음.

해석하면 "paired-end고, 정확히 매핑됐고, 이 read는 역방향이고, 짝(mate)은 정방향이고, 이 read가 _2(두 번째)이다".

 

CIGAR는 7M2D27M16S인데, D(Deletion)가 새로 등장함.

read에는 없는데 reference에는 있는 염기 2개가 있다는 뜻.

즉 이 위치에 indel(결실)이 있을 가능성을 보여주며, 나중에 GATK가 이런 정보들을 모아서 변이를 호출함.


RNAME이 * 인 경우

SRR062634.1	77	*	0	0	*	*	0	0	GGGTTTTCCTGAAA...
SRR062634.3	77	*	0	0	*	*	0	0	TAGATATTTTTGTT...

 

위에서 볼 수 있듯이 SAM 파일에서 3번째 필드(RNAME)가 *로 되어있는 것을 확인 가능.

일부 read들은 chr20이라고 적혀있는데 다른 read는 * 인 이유를 알아보기 위해 FLAG 77을 확인해보면

samtools flags 77

# 0x4d	77	PAIRED,UNMAP,MUNMAP,READ1

 

PAIRED,UNMAP,MUNMAP,READ1 라는 출력을 확인할 수 있고, 여기서 UNMAP이 핵심.

 

이 read들은 chr20 어디에도 정렬이 안 됐다는 뜻.

그래서 RNAME, POS 같은 위치 정보가 다 *나 0으로 비어있는 것.

 

MUNMAP은 짝(mate)도 같이 정렬 안 됐다는 뜻.

즉 이 read 쌍 전체가 chr20에 못 붙은 것.

 

이런 경우가 발생하는 이유는, chr20 subset만 reference로 썼기 때문.

그런데 실제 DNA 조각은 다른 염색체에서 왔을 수도 있고, repeat 영역이라 매칭이 너무 애매하거나, 품질이 낮아서 정렬 실패했을 수도 있음.

지금은 100만 read를 전체 게놈이 아니라 chr20에만 정렬했으니까 이런 매핑 실패 read가 많이 나오는 게 정상.


SAM 파일 전체 정렬 통계

samtools flagstat ~/bioinfo/bi_study/wgs_practice/aligned/SRR062634.bam

 

전체 정렬 통계 출력값을 확인해보면,

1940268 + 0 primary

 

총 read 수. trimmed 후 970,134쌍 × 2 = 1,940,268개.

570849 + 0 mapped (29.17% : N/A)

 

chr20에 매핑된 read는 29.17%.

나머지 70%는 매핑 안 됨.

매핑된 read 비율이 낮은 이유는 reference로 chr20만 썼기 때문.

그런데 100만 read는 전체 게놈(WGS) 중 일부니까, 실제로는 chr1, chr2... 다른 염색체에서 나온 read들도 섞여있는 것.

chr20에만 정렬을 시도했으니 chr20 출신 read만 붙고 나머지는 다 매핑 실패로 떨어지기 때문에 비율이 낮음.

318870 + 0 properly paired (16.43% : N/A)

 

양쪽 read가 둘 다 정확하게 매핑된 비율.

이것도 위와 같은 이유로 낮음.

 

정리하면, 매핑률 29%는 데이터 품질 문제가 아니라 reference를 chr20만 써서 생기는 당연한 결과.

실제로 chr20 전체 게놈(hg38) 기준으로 정렬했다면 매핑률이 95% 이상 나왔을 것이라고 예상.

 


추가) mapped 비율 직접 검증

flagstat 안 쓰고 SAM에서 직접 세어볼 수 있음.

samtools view ~/bioinfo/bi_study/wgs_practice/aligned/SRR062634.bam | awk '$3 != "*"' | wc -l

#출력
#  638540

 

이 결과는 위의 flagstat에서 본 570,849 mapped랑 숫자가 다른데 이유는 직접 검증하는 코드가 secondary(0개)랑 supplementary(16,944개)까지 포함해서 세어서임.

 

570,849 (primary mapped) + 16,944 (supplementary) + 일부 secondary 처리 차이 = 638,540

 

MAPQ 분포 확인

samtools view ~/bioinfo/bi_study/wgs_practice/aligned/SRR062634.bam | awk '{print $5}' | sort -n | uniq -c

 

출력값

더보기
1589483 0
14031 1
9831 2
13388 3
11304 4
10343 5
13589 6
11741 7
7734 8
10205 9
7418 10
6230 11
8748 12
7228 13
4144 14
7605 15
5791 16
5734 17
8624 18
7791 19
5096 20
7262 21
5772 22
4465 23
7251 24
6053 25
2328 26
6181 27
2530 28
2473 29
5036 30
3386 31
1451 32
4073 33
1953 34
1940 35
4109 36
2890 37
 849 38
3417 39
33856 40
1543 41
2154 42
1933 43
1729 44
2304 45
1682 46
1524 47
2355 48
1661 49
1084 50
1141 51
 806 52
 642 53
1572 54
1003 55
 711 56
 975 57
 751 58
 991 59
57318 60

MAPQ 0이 158만 개나 되는 게 핵심.

이건 바로 매핑 안 된 read들(* 표시된 것들)이 전부 MAPQ 0으로 기록되기 때문.

그래서 chr20 못 붙은 read들이 여기 다 몰려있음.

 

반대로 MAPQ 60(최고 품질)이 57,318개, MAPQ 40도 33,856개로 꽤 많음.

이건 chr20에 확실하게, 다른 위치랑 헷갈리지 않고 정확히 붙은 read들임.

'Bio Data Analysis > WGS(Whole Genome Seq)' 카테고리의 다른 글

[WGS 분석] 변이 호출 (GATK HaplotypeCaller: Variant Calling)  (0) 2026.07.01
[WGS 분석] BAM 파일 구조 이해하기  (0) 2026.07.01
[WGS 분석] 인덱스 생성 및 정렬 (SAM/BAM)  (0) 2026.06.30
[WGS 분석] QC & Trimming  (0) 2026.06.30
WGS 분석 실습을 위한 FASTQ 파일 구조 이해하기  (0) 2026.06.29
'Bio Data Analysis/WGS(Whole Genome Seq)' 카테고리의 다른 글
  • [WGS 분석] 변이 호출 (GATK HaplotypeCaller: Variant Calling)
  • [WGS 분석] BAM 파일 구조 이해하기
  • [WGS 분석] 인덱스 생성 및 정렬 (SAM/BAM)
  • [WGS 분석] QC & Trimming
데이터로 읽는 생명
데이터로 읽는 생명
is-note 님의 블로그 입니다.
  • 데이터로 읽는 생명
    In Silico Note
    데이터로 읽는 생명
  • 전체
    오늘
    어제
    • 분류 전체보기 (190)
      • Bio-Knowledge (16)
        • 분자생물학 & 유전학 기초 (0)
        • 전사체학 & 유전자 발현 (0)
        • 구조생물학 & 단백질 (0)
        • 싱글셀 & 다중오믹스 (0)
        • 임상유전학 & 질환 데이터 (0)
      • Programming (4)
        • API (4)
      • BI&Programming-Tools (111)
        • File Formats (14)
        • Linux & Bash Script (38)
        • Python (35)
        • R (11)
        • 통계 (8)
        • Pipeline Manager (0)
        • Etc (5)
      • Bio Data Analysis (28)
        • 서열분석개론 (6)
        • WGS(Whole Genome Seq) (11)
        • WES(Whole Exome Seq) (2)
        • RNA-Seq (4)
        • Metagenome (2)
        • Non-human Resequencing (1)
        • 임상유전체 분석 (1)
        • Multi-Omics (1)
      • Bio-Trends & Tech (1)
      • 코딩테스트 연습 (30)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    R
    유전체분석
    리눅스기초
    파이썬연습
    리눅스
    wgs
    통계
    GATK
    생물정보학
    파이썬
    코딩테스트
    R기초
    fasta
    분자생물학
    bioinformatics
    FASTQ
    파이썬기초
    데이터분석
    ngs
    파일포맷
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
데이터로 읽는 생명
[WGS 분석] SAM 파일 구조 이해하기
상단으로

티스토리툴바