Column/Row를 구성하는 벡터가 전부 준비된 상태에서 데이터프레임을 만드는 것은 비교적 쉽다. 기존에 존재하는 데이터프레임을 cbind() 함수로 합치는 것도 마찬가지이다. 그런데 합쳐야 할 벡터가 수십 개 이상 된다고 하자. 이를 일일이 타이핑하기는 곤란하다. 반복문을 쓰지 않고서는 매우 어렵다.
EMBOSS의 msbar 명령을 이용하여 박테리아 유전체 서열에 염기치환돌연변이를 일정하게 도입하였다. 그 각각이 원본 유전체 서열('ancestor'에 해당)에 대하여 얼마나 멀어졌는지를 Mash로 측정해 보았다. 목표로 하는 돌연변이 수에 대하여 msbar는 총 30회를 실시하였고, 돌연변이의 수는 10, 20, 30..200으로 하였다. 결과물은 전부 하나의 파일(dist.tab)에 저장하였다.
$ head -n 5 dist.tab
GCF_000008445.1.010.00.c.fnm GCF_000008445.1.fna 1.61302e-06 0 9999/10000
GCF_000008445.1.010.01.c.fnm GCF_000008445.1.fna 4.8398e-06 0 9997/10000
GCF_000008445.1.010.02.c.fnm GCF_000008445.1.fna 0 0 10000/10000
GCF_000008445.1.010.03.c.fnm GCF_000008445.1.fna 1.61302e-06 0 9999/10000
GCF_000008445.1.010.04.c.fnm GCF_000008445.1.fna 9.68178e-06 0 9994/10000
첫번째 컬럼이 돌연변이 유전체 FASTA 파일의 이름이다. fna라는 흔한 확장자를 fnm('m' for mutation)으로 고쳤다. 파일명 중간쯤에 '010'이라는 숫자가 바로 돌연변이 수에 해당한다. 만약 10, 20...으로 표기를 했다면, 100을 넘어가는 결과와 함께 다룰 때 sort에 주의해야 한다. 그래서 약간 귀찮지만 이런 파일명을 쓴 것이다.
하나의 돌연변이 숫자에는 총 30개의 Mash distance(위 자료에서 세번째 컬럼)가 있다. 이것을 뽑아내어 각기 다른 컬럼으로 만들고자 하는 것이 오늘의 목표이다. 돌연변이의 수는 총 10에서 200까지 10 단위로 증가하므로 20개가 되고, 이것이 목표로 하는 데이터프레임의 전체 컬럼 수가 된다. Row의 수는 30개가 된다.
일반적인 슬라이싱을 통해서 원본 데이터프레임의 일부를 잘라낸 뒤 새 데이터프레임에 한 컬럼씩 붙여 넣는 방법이 있을 것이라 생각했는데 잘 되지 않았다. 검색을 거듭한 결과 리스트를 써야 함을 알게 되었다. 참조했던 웹사이트가 어디였는지는 기억을 하지 못하겠다. do.call() 함수를 쓰는 방법을 잘 알아야 될 것이다.
> header = sprintf(seq(10,200,10), fmt='%03d')
> header
[1] "010" "020" "030" "040" "050" "060" "070" "080" "090" "100" "110" "120"
[13] "130" "140" "150" "160" "170" "180" "190" "200"
> df = read.table("dist.tab", sep="\t", row.names=1)
> datalist = list()
> for(i in header) {
+ pattern = paste(".", i, ".", sep="")
+ datalist[[i]] = df[grepl(pattern, row.names(df)), 2]
+ }
> df.2 = do.call(cbind, datalist)
> View(df.2)
최적화된 R code라고 확신을 할 수는 없다. '.010.' 형태의 패턴을 추출할 때, 앞뒤의 점은 정규표현식에서 임의의 문자 하나에 대응하는 점이 아니라 문자 그대로의 '.'임이 중요한데, 이것이 grepl() 함수에서 정확히 인식되고 있는 것인지를 잘 모르겠다. grep()은 인덱스를 반환하지만 grepl()은 TRUE 또는 FALSE를 반환한다고 한다. 어쨌거나 View(df.2)로 확인을 하면 다음과 같이 내가 의도한 데이터 변환이 이루어졌음을 알 수 있다.
나의 '데이터 주무르기'는 그야말로 마음 내키는 대로이다. 모든 조작을 Perl에서 하던 시절도 있었고, 요즘은 bash script와 awk/sed 등을 적절히 섞어서 쓰는 빈도가 늘어났다. 그러다가도 예외 사항이 별로 없이 매트릭스 형태로 잘 짜여진 데이터 파일을 보면 R에서 작업을 하고 싶어진다. 사용했던 코드를 노트 파일과 컴퓨터 작업 공간에 잘 저장해 두는 것도 좋은 버릇이라고 자평한다.