2019년 9월 20일 금요일

YouTube Preminum을 취소하고 Mendeley를 업그레이드하다

약간의 비용을 지불하고 유튜브에서 광고 없이 음악을 듣는 것은 참 즐거운 일이었다. 돈을 내면, 그만큼 얻는 즐거움과 효용이 있다. 하지만 가끔씩 선택의 순간이 오고, 더 큰 효용을 위해 작은 것을 포기하는 용기를 발휘해야 할 필요도 있다.

2018년에 5월부터 매달 8,690원을 내기 시작했을 때의 서비스 이름은 YouTube Red였다. 구글 결제 센터에 접속하면 여전히 YouTube Red라는 서비스 명목으로 돈이 빠져나감을 알 수 있다. 그런데 해지를 하였더니 YouTube Premium 멤버십을 정녕 해지하실 거냐고 이메일이 왔다. 두 서비스가 사실상 같은 것이겠지? 잘 쓰던 서비스를 해지한다고 해서 별로 아쉬울 것은 없다. 음악은 인터넷 라디오로 들으면 되니까...

그대신 유튜브에서 Mendeley의 PDF 저장 공간(Personal Space라 불림)을 기본 2GB에서 5GB로 올리는데 비용을 지불하기로 했다. 파견 근무지(회사)에서는 개인 PC에 파일을 저장하는 것이 기본적으로 금지되어 있고, PDF에 메모나 하이라이트와 같은 수정을 가하면 lock이 걸려서 사용하기에 보통 불편한 것이 아니다. 차라리 Mendeley 웹에 논문 PDF를 올린 다음 읽는 것이 더 낫다. 업로드한 논문의 성격에 맞추어서 읽을만한 최신 논문을 제안하는 기능도 꽤 괜찮다. 어차피 여기에 올리는 자료는 공개적으로 얻을 수 있는 논문이므로 회사의 기밀 유지와는 관계가 없다고 생각하여 Mendeley를 적극 사용하기로 하였다. 흠, 내가 어떤 주제의 논문을 읽는다는 것이 기밀 사항이 될 수도 있겠군.

회사에서는 Gmail 웹사이트가 열리고, Mendeley 웹사이트의 내 계정으로 PDF를 올릴 수도 있다. DropBox가 되는지는 확인해 보지 않았다. 반면 KRIBB에서는 이상의 행위를 할 수 없다. 국정원의 정책 때문인 것으로 알고 있다. 회사든 KRIBB이든 일을 하기에는 비슷한 정도로 불편한 셈이다. 다행스럽게도 KRIBB에서는 파일에 보안 잠금은 되지 않는다. SSL 인증서와 관련해서 회사 전산망에서는 너무 많은 고생을 했고 지금도 해결 가능성은 보이지 않는다.

2012년에 Solar System이라는 패키지로 총 4회 결제를 했었다. 엊그제 새로 개시한 Plus package는 여전히 매월 4.99 달러를 내면 된다. 무려 7년이 지나서 다시 유료 서비스로 전환한 셈이다.

가급적이면 모니터 화면을 통해서 자료를 읽으려 하지만, 종이에 인쇄하여 줄을 쳐 가면서 읽는 아날로그적인 습관을 아직 버리지 못했다. 내가 전자책 단말기를 사기로 결정하는 날은 언제나 올지 모르겠다. 오늘도 퇴근 후 읽으려고 논문 하나를 종이에 인쇄하여 들고 나간다.

'Quick-and-Dirty' Perl 스크립트 한 줄의 작동원리 알아보기

여러 개의 염기서열을 담고 있는 sequence.fasta에서 특정 ID에 해당하는 서열만을 뽑아내는 한줄짜리 Perl 스크립트를 설명해 보고자 한다. 추출할 서열의 ID 목록은 ids.txt에 존재한다고 가정하자.

$ perl -ne 'if(/^>(\S+)/){$c=$i{$1}}$c?print:chomp;$i{$_}=1 if @ARGV' ids.txt sequences.fasta

이 예제는 Short command lines for manupulation of FASTQ and FASTA sequence files에서 가져온 것이고, 내가 작성하여 위키 페이지에 올렸던 문서에 포함되어 있다. 솔직하게 말하자면 교육 또는 학습 목적으로는 대단히 바람직하지 않은 코드이다. 길이가 매우 짧고 어쨌든 실행은 되니까 그저 복사해서 붙여놓고 아무런 의문을 제기하지 않고 써도 된다. 물론 나는 이보다는 조금 더 긴 Perl 스크립트를 별도로 만들어서 사용한다.

마침 이 코드의 정규표현식에 관한 질문이 들어와서 블로그에 상세하게 작동 원리 전체를 설명해 보기로 하였다. 겨우 한 줄에 불과하지만 이해하기는 쉽지 않다. 한참 다른 정보를 찾아서 고민하고 테스트를 거듭하여 겨우 감을 잡을 수 있었다.

먼제 Perl 인터프리터의 명령행 옵션인 -e와 -n을 알아야 한다. -e는 잘 알려진 것으로, 스크립트를 파일로 만들지 않고 명령행에서 직접 입력하여 사용하기 위한 것이다. -n은 -e 코드를 while loop로 둘러싸는 것이다.  Perl의 명령행 옵션에 관한 상세한 설명과 예제는 Perl Command-Line Options 또는 7 of the most useful Perl command line options를 참조하기 바란다.

그러면 본격적으로 이 고약한 코드를 해부해 보자. 코드는 다음과 같이 세 개의 블록으로 나눌 수 있다. 각각을 b-I, b-II, 그리고 b-III이라 부르기로 하자. perl -n 옵션을 주었으므로 ids.txt와 sequences.fasta의 모든 줄에 대해서 다음이 순차적으로 실행되는 implicit loop를 돈다.


ids.txt에 seq1, seq2(실제로는 한 줄에 한 ID이므로 "seq1\n", "seq2\n"라고 생각해야 됨)라는 내용이 담겨있다고 가정하자. 이 두 줄에 대해서 루프를 돌 때는 b-I은 건너뛴다. 왜냐하면 첫 줄이 '>'로 시작하지 않기 때문이다. 뒤이어서 b-II에서는 무슨 일이 벌어지는가? A? : command 1 : command 2는 if..the..else와 매우 흡사하다. '?'는 conditional operator라 부른다(참고). A라는 조건을 판별하여 참이면 command 1을, 거짓이면 command 2를 실행하라는 뜻이다. $c?라고 물어보았으니 $c가 1이면 print 함수를 , 그렇지 않으면 chomp 함수를 실행하게 되는데, 함수의 인수가 없다고 걱정할 것은 없다. 자동으로 $_ 변수(현재 읽어들여 처리 중인 라인)을 인수로 사용하기 때문이다. chomp 함수는 인수를 명시적으로 나타내지 않으면 $_의 뒤에 붙은 "\n"을 털어낸다. 이어서 이 코드의 세번째 블록(b-III)으로 진행되어 $i{seq1}=1가 선언되고, 다음번 줄에 대해서 반복을 돌면서 $i{seq2}=1가 실행된다. 만약 b-II에서 chomp를 실행하지 않았다면 $i의 key는 "seq1\n"이 되고 만다. 이는 "seq1"과는 다른 문자열로 간주됨에 유의하라. 결과적으로 ids.txt를 이루는 두 줄에 대해서 코드 전체(b-I/II/III)가 반복되고, %i hash에는 추출해야 할 서열의 ID가 key로서 기록된다.

ids.txt에 대해서 loop를 돌았으니 다음으로는 sequences.fasta 파일을 이루는 각 줄에 대해서 b-I/II/III을 반복하여 실행할 차례가 되었다. sequences.fasta의 첫 줄은 '>sequece_id' 형태이므로 block-I에서 패턴 매칭문을 만난다. /^>(\S+)/의 의미는 '>'로 시작하는 라인에서 '>'의 바로 다음에 오는 공백이 아닌 문자 여러개에 해당하는 패턴을 찾아서 $1 변수에 넣으라는 뜻이다. if {} 블록 내부의 $c=$i{$1}는 그러면 무슨 의미인가? 만약 지금 읽어들인 서열 ID가 ids.txt에 존재하는 것이라면 %i hash의 key에 정의된 상태가 된다. 따라서 $c=1이 된다. 만약 지금 막 읽어들인 서열 ID가 ids.txt에 없다면 $c는 아직 미정의 상태이다.

다음으로는 b-II로 진행한다. 조건연산자 '?'가 $c의 참 혹은 거짓 여부를 묻는다. $c가 정의된 상태라면 '>sequence_id'를 표준출력으로 인쇄한다. 정확히 말하자면 라인의 끝을 나타내는 "\n"까지 $_에 포함된 상태이니 정상적으로 한 줄이 다 인쇄되고 다음 라인을 인쇄할 준비를 마친다. 다음으로 b-III을 만난다. $i{">sequence_id\n"}=1이 실행되지만 이는 이후의 동작에 영향을 미치지 않는다.

이번에는 sequences.fasta의 두번째 줄을 실행할 순서이다. '>'로 시작하는 줄이 아니므로 b-I은 통과한다. b-II에서는 어떻게 될까? $c는 여전히 1의 값을 갖고 있으므로 print 문이 실행된다. b-III을 만나게 되지만 $i{"ATCGACG..\n"}=1을 실행하게 되고 역시 결과에는 영향을 미치지 않는다. 즉, 추출하고자 선택된 sequence의 ID 및 실제 염기서열 라인만 계속 표준출력으로 인쇄가 된다.

그러다가 ids.txt에 정의되지 않은 ID의 서열을 드디어 만나게 된다. '>'로 시작하는 라인을 만났으니 일단 b-I으로는 들어가는데, 이에 맞는 $i{서열ID}는 존재하지 않는다. 따라서 $c는 정의되지 않는다. 따라서 이어서 진행되는 b-II에서는 chomp를 만나게 된다. 이는 마찬가지로 출력물에 영향을 미치지 않는다. 이 동작은 다시 '>'로 시작하는 줄을 만나게 될 때까지 반복된다.

솔직하게 말해서 나의 코드 분석이 100% 맞는다고 자신은 못하겠다. 겨우 한 줄에 불과한 코드를 이렇게 긴 글로 설명해야 한다면, Perl 스크립트 작성 학습용 샘플로는 적합하지 않다. 물론 사용하는 데에는 아무런 문제가 없다. 1996년부터 2000년까지 소위 '난해한 Perl 코드 콘테스트(Obfuscated Perl Contest)'가 있었다고 하니 500바이트 내외의 Perl 코드가 불러일으키는 난잡함, 그러나 그 속에서 풍겨나는 익살과 아름다움을 감상하고 싶다면 위키피디아 혹은 다음의 수상작 페이지를 방문해 보라.


2019년 9월 17일 화요일

독서 역주행 - <두 얼굴의 조선사(2016)>와 <공자가 죽어야 나라가 산다(1999)> 이어서 읽기

나의 성은 나주 정(丁)씨 '○○공(公)'파이다.

"저는 ○○ 김가입니다." ...(1)
"저는 ○○ 박씨입니다." ...(2)

다른 사람 앞에서 말을 할 때에는 (1)처럼 하는 것이 예의에 맞다고 한다. 하지만 이 블로그에서처럼 평어체로 쓰는 글에서는 (2)처럼 해도 큰 문제가 없을 것 같다. '○○공'파라고 표현한 것은 이 정보가 정확하지 않을 수도 있기 때문이다. 집안 어른께서 우리 정씨의 내력을 말씀해 주신 것을 제대로 기억하지 못해서 그런 것이 아니다. 우리 집안의 ○○공 파보(派譜)를 정리한 것은 돌아가신 할아버지의 노력이었다. 그런데 이것을 나주 정씨 '메인 스트림'에 해당하는 월헌공파에서 인정을 하지 않는 듯한 느낌을 받은 일이 있다. 그것도 처음 만나는 사람이 당사자인 내 앞에서 그런 이야기를 한다는 것은 매우 무례한 일이 아니겠는가?

할아버지께서는 고향(경기도 어느 지역 A라 하자)에 남아있는 우리 조상의 비문, 우리 성씨와 연결된 지명 및 유적의 이름, 그리고 최근 기록만 남은 단편적인 우리 집안의 족보를 가지고 쥬류를 이루는 정씨의 족보에 힘겹게 연결하는 작업을 하셨노라고 내게 말씀하신 적이 있다. 내가 알기로 '○○공파'가 만들어진 것도 할아버지의 노력인 것으로 안다. 그렇다면 혹시 원래 우리 집안은 정씨가 아닐 수도 있는 것 아닌가? 조선 후기가 되면서 양반이 점점 많아지고, 전부 성과 족보를 갖게 되었다. 양반이 갑자기 생식능력이 왕성해져서 그 수가 늘었나? 절대 그럴리는 없다. 대부분은 족보를 새로 만들면서 권문세가의 성을 슬쩍한 것이 다반사일 것이다. 게대가 태반은 중국에서 들어온 사람이 자기 성씨의 시조가 되었다고 하니 정말 웃기는 노릇이다. 하긴 나주 정씨도 정덕성이란 사람이 중국에서 한국 압해도에 유배를 와서 시작했다고 전하지만, 다산 정약용은 이를 믿을 수 없다고 하였다. 보다 확실한 중시조는 고려 때의 무인 직책인 검교대장군을 지낸 정윤종(정덕성의 15세손이라고도 함)이다.

우리 조상이 원래 근본이 없는 집안을 이루고 살다가 수백년 전에 A 지역에 들어와서 丁씨 행세를 한 것일까? 기왕 그럴 것이라면 몰락한 왕족이나 당시 세도를 누리던 집안의 성을 따르지 않았을까? 아니면 티를 덜 내기 위하여? 지금으로선 우리 집안이 과거에 양반이 아니었다 하더라도 상관이 없다는 생각이다.

명절을 맞이하여 우리 나라 인구를 차지하는 성씨가 너무가 다양성이 부족하고, 대부분이 왕족이나 권문세가의 후손임을 자처하는 것이 한심하다는 생각이 들었다. 그렇게 된 원인은 어디 있을까 고민을 하다가 방송 다큐멘터리 작가 조윤민이 지은 '두 얼굴의 조선사(2016)'를 구입해서 읽게 되었고, 지금으로부터 꼭 20년 전인 1999년에 상명대 김경일 교수가 지은 '공자가 죽어야 나라가 산다'를 중고책 서점에서 구해서 단숨에 읽었다.


중국땅을 거쳐간 왕조 중에는 한나라 이래로 300년을 넘긴 것이 없다. 그러나 조선은 대한제국 선포 전까지만 따져도 500년이 넘는 역사를 자랑한다. 그런데 이것이 길다고 해서 과연 자랑할마한 일일까? 그 기나긴 역사 속에서 우리는 자주적인 근대화의 싹을 틔워 왔는가? 결코 그렇지 않다는 것이 왼쪽 책의 결론이고, 나는 그것의 근본 이유가 유학에 있다고 생각하여 오른쪽 책까지 읽게 된 것이다. 

조선의 지배세력은 그야말로 '정치 공학자'라고 생각한다. 유교라는 이념화된 사상이야말로 가장 강력한 무기였다. 흔히 유교의 기본 정신 중에 仁을 가장 중요한 것으로 생각하지만, 중국 고대문자 및 문헌 전문가인 김경일 교수에 의하면 공자가 살던 시기에 仁이라는 글자는 없었다고 한다. 오래 전 중국에서 적당히 다듬어진 사상이 어쩌다가 조선의 통치 이념이 되고, 그 틀에 갖힌 기득권 세력은 우리의 창의롭고 진취적인 기운을 죄다 틀어막은 것만 같다. 과거의 기준에 맞지 않으면 사문난적으로 몰려서 사약을 한 사발 죽 들으켜야 하는 사회에서 어찌 발전으로 생각하고 미래를 대비할 수 있단 말인가?

왼쪽 책은 조선왕조실록 등 근거를 제시해 가면서 학문적으로 기술하였고, 오른쪽 책은 일종의 에세이에 해당한다. 오른쪽 책은 당시 IMF 구제금융 시대를 맞아 답답한 현실을 개탄하면서 쓰여진 책이다. 저자는 책을 내고 나서 유림들에게 고소를 당하는 등 많은 어려움을 겪었다. 하지만 원래 저자가 의도한 제목은 훨씬 강경한 '공자를 죽여야 나라가 산다'였다나? 두 책을 읽는 내내 머리에서 김이 뿜어져 나오는 것만 같았다. 

조선에 대한 비판적인 시각을 갖고 있다고 하여 이것이 식민사관이라든가 요즘 물의를 일으키는 책 '반일 종족주의'를 옹호하고 있는 것으로 오해하지는 말라. 

다음에 읽을 책은 김경일 교수의 2013년도 저작 '유교 탄생의 비밀'이 될 것이다.

2019년 9월 16일 월요일

화성으로 가는 탑승권

NASA에서 2020년 발사 예정인 화성탐사선(MARS2020)을 기념하여 탑승권을 발급하는 이벤트를 벌이고 있다. 마감은 9월 말까지이다. 탑승권을 받은 사람들의 이름은 칩에 담아 우주선에 실린다고 한다. 사람을 보낼 수는 없는 노릇이니.

나는 9,342,924번째 탑승자이다. 탑승권의 원본 사이트는 여기에 있다.


이 이벤트에 관한 소식은 대덕넷에서 접했다. 재치있고 낭만적인 이벤트가 아닌가. 여기에 접속하여 이름과 국가명, 우편번호, 그리고 이메일 주소만 넣으면 된다.

국내만 '20만명'..."이번달까지 화성에 이름 보내세요"

잠시 상상의 나래를 펼쳐보자. 인적사항을 담은 화성 탐사선이 지구를 출발하여 가는 도중에(혹은 화성에 도착하여) 외계인에게 납치가 된다. 외계인은 탐사선이 보유한 모든 정보를 해독하여 지구인 백만명의 이메일 주소를 알아내고(그렇다, 외계인에 의한 해킹이다!) 악성코드를 심은 이메일 메시지를 뿌린다. 이메일을 열어본 사람은 갑자기 정신상태가 이상해지면서 외계인들에게 조종당한다... 어, 잘만 다듬으면 공상과학영화 시나리오 한 편이 나오겠는걸.

실제로 우주선에 실리는 정보는 이름 정도일 것으로 생각된다. 덜렁 영문으로 쓰인 이름만 가지고 엉뚱한 일을 하기는 어려울 것이다.

이러한 이벤트를 우리나라에서 할 수 있을까? 아마도 개인정보보호법에 의거하여 동의서를 받아야만 될 것이다. 우리나라에서 이메일 주소는 개인정보로 취급하고 있다. 다른 정보를 포함하면 개인을 식별할 수 있다고 판단하기 때문이다. 따라서 화성 탐사선에 내 이름을 실어보내자는 낭만적인 이벤트를 우리나라에서는 하기 어렵다. 자유로운 상상력을 틀 안에 가두는 규제가 우리에게는 너무 많다.

2019년 9월 12일 목요일

6LQ8 PP 앰프의 소소한 개선 - low-pass filter를 달기

6LQ8 진공관은 원래 오디오용 주파수의 증폭에 쓰기 위해서 개발된 것이 아니다. 가뜩이나 증폭률이 높은 진공관이라서 오디오용 앰프를 만들면 발진(oscillation)을 일으키기 쉽다고 한다. 발진이라고 해서 반드시 '삐~'하는 소리가 난다는 뜻은 아니다. 저항이나 캐패시터와 같은 수동 부품을 적당히 덧입혀서 발진을 잡는 방법이 잘 알려져 있지만, 어차피 오디오용 관이 아닌 것으로 진지하게 음악 감상을 하기 위한 앰프를 만드는 것을 싫어하는 사람들도 있다. 이것은 선택과 취향의 문제이다.

다음은 제이앨범에서 권장하는 6LQ8 푸시풀 앰프용의 '검증된' 발진 대책이다. 초단(전압증폭단)의 플레이트에 연결된 부하 저항(R5)에 저항+캐패시터로 이루어진 바이패스 회로를 붙이는 것이다. 이어지는 회로에는 낮은 주파수를 보내는 셈이니 일종의 low-pass filter라고 불러도 무방하겠다. 높은 주파수를 차단하는 역효과가 없지는 않겠으나 가청 주파수 영역에서는 상관이 없을 것이다. 이렇게까지 하여 오디오용이 아닌 진공관을 사용하여 오디오 앰프를 만드는 것에 대하여 부정적인 시각을 가진 사람이 없지는 않다. 이런 노력을 들일 바에야 아직도 쓸만하게 많이 남아있는 오디오용 진공관을 쓰는 것이 낫다는 의미가 되겠다.


부품을 붙일 자리가 없어서 PCB를 뒤집어서 패턴면에 부품을 납땜하였다. 중간쯤에 보이는 103 메탈필름캐패시터(IC114 링크)가 이번에 새로 붙인 부품이다. 한쪽 리드선에는 1K 저항을 직렬로 연결하였다.



신호를 연결하지 않고 볼륨 노브를 최대로 돌렸을 때 들리는 잡음은 확실이 줄어들었다. 그러면 가청 주파수의 높은 쪽 대역에서 손해를 보았을까? 파형 발생기와 오실로스코프로 측정을 하지 않으면 알기가 어렵다. 뿐만 아니라 바이패스 회로를 연결하기 전후의 상황을 비교해야 차이를 발견할 수 있을 것이다. 단지 음악 신호를 연결해서는 고음 신호를 깎아먹어서 음질이 더 나빠졌는지를 알 수가 없었다. 약간 둔탁해진 것인가? '그럴 것'이라는 선입견이 감각을 왜곡하는지도 모르겠다. 만약 측정을 통해서 가청 주파수 대에서는 변화가 없다는 것이 입증되면, 아마도 그 순간부터는 갑지가 소리가 좋게 느껴질지도 모르는 것이다. 마치 플라시보 효과처럼 말이다.

2019년 9월 13일 업데이트

필터를 붙인 이후 소리가 어딘가 모르게 둔탁해졌다는 느낌이 들기 시작했다. 고음을 너무 깎아버려서 그런 것이 아닐까. 앰프를 다시 작업대에 올리고 한쪽 채널만 필터를 제거하고 신호를 연결하여 좌우를 비교하니 너무나 확연한 차이가 났다. 이런 식의 잡음 제거 효과라면 없느니만 못하다는 생각에 양 채널에서 필터를 전부 제거하였다. 정상적인 negative feedback 회로 이외의 것을 달아서 잡음 등을 제거하려는 시도는 상당히 조심해야 되겠다.

2019년 9월 9일 월요일

Ubuntu에서 hear string이 작동하지 않는 이유

CentOS(bash)에서는 잘 돌던 스크립트가 Ubuntu에서는 에러가 발생하였다. 왜 그런 것일까?

$ cat test
echo $(cut -d_ -f1 <<< "123_456")
$ sh test
test: 1: test: Syntax error: redirection unexpected
$ bash test
123

이유를 알아보자. 우분투의 기본 shell은 bash가 아니고 dash라고 한다. 이 환경에서는 here document 또는 here string이 잘 작동하지 않는다고 하였다.

[Ubuntu/Linux] #!/bin/sh에 대한 간단한 이야기

따라서 위에서 소개한 test 스크립트의 shebang line에 #!/bin/sh를 삽입해 봐야 소용이 없다. 우분투에서는 /bin/sh가 dash를 가리키기 때문이다. 이 한줄짜리 스크립트를 제대로 돌리려면 첫줄에 #!/bin/bash를 삽입해야 한다. 그러나 실행할 때 sh test라고 하면 도루묵이다. 실행 권한을 주어서 ./test라고 실행해야 한다. 당연한 이야기이다.


AWK를 이용한 fasta file splitter

여러 염기서열로 이루어진 multi-fasta file을 쪼개에서 각 서열이 하나씩의 파일에 담기게 하는 작업은 매우 흔히 벌어지는 일이다. 나도 10줄 조금 넘는 Perl 스크립트를 만들어서 fasta file을 분리하는데 종종 쓰고는 한다.

awk를 쓰면 달랑 코드 한 줄로 fasta file splitter를 만들 수 있지 않을까? 구글에서 검색을 해 보니 이에 대한 많은 질문과 답이 있었다. 이를 참조하여 다음과 같은 awk 명령어를 만들어 보았다.  awk의 명령에 내에서 shell과 유사하게 파일로 직접 인쇄결과를 리다이렉션할 수 있다는 것을 몰랐다. 파일핸들을 정의하고 여닫는 일을 하지 않아도 되니 Perl보다 더 간단한 코드가 되었다. 아무런 실수가 없을 것으로...믿는다.

$ awk '/^>/{s=$0; sub(/^>/, "", $1); F=$1".fa"; print s > F; next}{print >> F}' input.fasta

awk를 쓰면서 종종 혼동하는 것은 sub() 함수가 치환된 문자열을 반환하지는 않는다는 것이다. 즉 var = sub(regexp, replacement, target) 형태로 사용하면 안된다.

코드를 간단히 분석해 보자. 서열 ID(>seq_id)가 있는 줄을 만나면, 첫번째 컬럼($0)에서 '>'를 제거한 뒤 .fa를 붙여서 출력할 파일의 이름을 만들어 변수 F에 저장한다. 그런데 sub() 함수에서 직접 $1을 건드리게 되므로, 나중에 원본 라인을 그대로 출력하기 위하여 명령어 맨 처음에 s라는 변수에 미리 서열 ID 라인을 저장해 놓는 꼼수(s=$0)를 사용했다. 그 다음에 유의할 것은 '/조건/{조건에 맞는 줄에 대하여; next} {조건에 맞지 않는 나머지 줄에 대해 실행}' 명령을 이해하는 것이다. 여기에서 next가 매우 중요한 역할을 담당한다. 이에 대해서는 예전의 포스팅에서 두번 정도 다룬 것 같다.

이 방법을 이용하면 SRR2162225(Gopalakrishnan et al., 2018)의 fastq 파일을 각 샘플별로 쪼갤 수도 있다. 이 fastq file은 다음과 같은 형식의 sequence ID를 갖고 있다. 내용상으로는 이미 demultiplexing이 된 것에 해당하지만 하나의 fastq 파일에 전부 수록되어 있다.

@ERR2162225.10 Wargo.109865_330283 length=253

두번째 필드를 추출하여 빨간색으로 표시된 것을 파일 이름으로 하는 fastq 파일을 만들어 보자. 현 디렉토리에 43개의 fastq 파일이 생겼다.

$ awk '/^@ERR2162225/{s=$0; sub(/_.+$/, "", $2); F=$2".fastq"; print s > F; next}{print >> F}' ERR2162225.fastq
$ ls
ERR2162225.fastq    Wargo.121296.fastq  Wargo.122637.fastq  Wargo.124418.fastq  Wargo.130511.fastq  Wargo.132266.fastq
Wargo.109865.fastq  Wargo.121409.fastq  Wargo.122639.fastq  Wargo.124419.fastq  Wargo.130801.fastq  Wargo.132268.fastq
Wargo.115690.fastq  Wargo.121585.fastq  Wargo.122724.fastq  Wargo.124421.fastq  Wargo.131051.fastq  Wargo.132538.fastq
Wargo.116774.fastq  Wargo.121891.fastq  Wargo.123009.fastq  Wargo.126747.fastq  Wargo.131300.fastq  Wargo.133270.fastq
Wargo.117349.fastq  Wargo.121892.fastq  Wargo.123197.fastq  Wargo.126802.fastq  Wargo.131302.fastq
Wargo.118369.fastq  Wargo.122114.fastq  Wargo.123305.fastq  Wargo.127261.fastq  Wargo.131512.fastq
Wargo.118370.fastq  Wargo.122410.fastq  Wargo.123704.fastq  Wargo.127262.fastq  Wargo.131541.fastq
Wargo.120662.fastq  Wargo.122412.fastq  Wargo.123986.fastq  Wargo.130510.fastq  Wargo.132265.fastq

다른 사례를 하나 더 들어보자. 다음은 vsearch --derep_fulllength로 dereplication을 거친 염기서열 파일의 일부를 보이고 있다.

>Mock.1;size=492
TACGTAGGTGGCAAGCGTTATCCGGAATTATTGGGCGTAAAGCGCGCGTAGGCGGTTTTTTAAGTCTGATGTGAAAGCCCACGGCTCAACCGTGGAGGGTCATTGGAAACTGGAAAACTTGAGTGCAGAAGAGGA
AAGTGGAATTCCATGTGTAGCGGTGAAATGCGCAGAGATATGGAGGAACACCAGTGGCGAAGGCGACTTTCTGGTCTGTAACTGACGCTGATGTGCGAAAGCGTGGGGATCAAACAGG
>Mock.2;size=345
TACAGAGGGTGCGAGCGTTAATCGGATTTACTGGGCGTAAAGCGTGCGTAGGCGGCTTATTAAGTCGGATGTGAAATCCCCGAGCTTAACTTGGGAATTGCATTCGATACTGGTGAGCTAGAGTATGGGAGAGGA
TGGTAGAATTCCAGGTGTAGCGGTGAAATGCGTAGAGATCTGGAGGAATACCGATGGCGAAGGCAGCCATCTGGCCTAATACTGACGCTGAGGTACGAAAGCATGGGGAGCAAACAGG

size=뒤에 나오는 모든 숫자를 더하면 dereplication 작업 전 FASTA file에 포함된 전체 서열의 수를 알 수 있다. 오늘 익힌 awk의 sub() 함수를 이용하면 간단하다.

$ awk 'BEGIN{s=0}/^>/{sub(/^>.*size=/, "", $0);s+=$0}END{print s}' input.fasta
4268

별로 설명할 필요도 없다. 서열 ID 라인에 description이 있다면 $0을 $1로 바꾸면 그만이다. 아니, 처음부터 code를 $1로 고쳐 놓으면 description이 존재하는지 여부에 상관없이 잘 돌아간다.

Bioinformatics on-liner

One-liner 애호가를 위하여 Stephen Turner의 GitHub 사이트를 소개한다(링크).

2019년 9월 6일 금요일

Robert Edgar, 멋진 사업가? 과학자? 프로그래머? 소프트웨어 엔지니어?

16S rRNA amplicon sequencing에 기반하는 메타게놈 분석 방법(주로 QIIME)을 요즘 집중적으로 공부하는 과정에서 QIIME documentation 웹사이트 말고도 하루에도 몇번씩 방문하는 곳이 있다. 바로 http://drive.com/이다. 이 사이트의 운영자는 Robert Edgar이다.

Robert Edgar(출처)
1982년 런던 대학에서 입자물리학으로 박사학위를 받았고 IT 분야의 비즈니스 경험도 많지만 생명정보학 분야에서는 MUSCLE이나 USEARCH와 같은 유명한 프로그램의 개발자로 잘 알려져 있다. 그는 2001년부터 스스로를 특별한 소속 없이 일하는 독립과학자(independent scientist)로 칭하면서 주로 전산생물학과 생물정보학 분야에서 많은 사람들에게 도움을 주고 있다.

그가 어떤 사람인지는 개인적으로 전혀 모르지만, 대학이나 기업에 몸담고 있지 않으면서 이렇게 프리랜서와 같이 일하면서 꾸준히 프로그램을 개발하여 배포하고 논문을 발표한다는 것이 대단하다고 느껴진다. 그의 홈페이지를 방문하면 최근 발표한 논문의 목록이 보이는데 저자는 전부 혼자다! 1975년에 대학에 입학하여 지금 교수로 재직한 전형적인 한국인 과학자가 있다고 하자. 이제 정년 퇴임이 얼마 남지 않은 나이일 것이다. 과연 동료나 후배(선배는 전부 은퇴했을 것이니), 또는 대학원생의 참여 없이 논문에 저자로 이름을 올릴 수가 있을까?

R. Edgar의 USEARCH는 64비트 버전을 이용하려면 돈을 주고 구입해야 한다. 하지만 32비트 버전은 무료이다. 무료라고 해서 소스 코드가 공개되어 있지는 않다. 프로그램의 기본 알고리즘은 논문이나 drive5.com 웹사이트에 소개가 되어 있으나 소스 코드는 비공개이니 사람들이 불만을 느낄 수도 있다. 그런 취지에서 VSEARCH가 3년 전에 나왔고, 웹을 검색해 보니 아주 훌륭한 16S rRNA 서열 분석용 파이프라인이 공개된 것도 발견할 수 있었다(링크). 이것 역시 공부하기에 아주 좋은 자료이다.

VSEARCH의 논문 초록에서는 USEARCH를 살짝 '디스'하고 있다. 인용해 볼까?

 [VSEARCH] is designed as an alternative to the widely used USEARCH tool () for which the source code is not publicly available, algorithm details are only rudimentarily described, and only a memory-confined 32-bit version is freely available for academic use.

그래도 USEARCH는 학계에서 충분히 제 역할을 하고 있지 않은가?

나는 생명정보학을 체계적으로 배우질 않아서 이 학문의 역사에 대해서는 매우 단편적인 지식밖에 갖고 있지 못하다. 나의 짧은 경험으로 존경하고 싶은 생명정보학자, 또는 이 분야의 소프트웨어 개발자는 이런 분들이 있다. 이 목록은 절대로 생명정보학 명예의 전당 같은 것도 아니고, 이 분야를 모두 망라한 것도 아니다. 누구나 흔히 생각할 수 있는 David Lipman 같은 사람은 뺐다. 내가 현재 하고 있는 일에 대해서 직접적인 영향을 미친 사람들이다.

Margaret Oakley Dayhoff
Phil Green
David Gordon(CONSED의 개발자)
Jim Kent(흠, 정작 나는 BLAT를 거의 쓰지 않는데)
Sean Eddy
Lincoln Stein(BioPerl하면 떠오르는 사람)
Art Delcher(MUMmer 개발자)
Ewan Birney
Eugene Myers 등.

여기에 R. Edgar도 넣어줘야 되겠다.

개발자, 프로그래머, 컴퓨터 사이언티스트, 소프트웨어 엔지니어의 차이는?

다음의 글을 참조하라.


그리고 이 글에서 인용한 원문 및 그림(링크).

출처: Scott Hasnselman

2019년 9월 4일 수요일

QIIME 1을 위한 sequence data 준비 과정 - demultiplexed paried-end fastq의 복잡한 사정

약 일주일에 걸쳐서 QIIME 1을 집중적으로 공부하면서 느낀 것은 sequencing data 파일로부터 seqs.fna를 만드는 과정이 전체 수고의 1/3 정도는 되는 것 같다는 점이다. 더군다나 아직 실제 16S rRNA 데이터를 생산한 경험이 없어서 SRA에서 자료를 받아서 연습을 하니 그 과정이 더욱 어렵게 느껴졌다. 왜냐하면 서열 ID 라인의 형식이 실제 MiSeq에서 생산된 직후의 fastq 파일 모습을 그대로 따르고 있지 않으며, 메타데이터 역시 제대로 마련되지 않았기 때문이다. 하지만 그 덕분에 SRA-Toolkit의 prefetch와 fastq-dump의 기능을 제대로 이해하게 되었으며, NCBI 웹사이트에서 run accession의 목록 파일을 손쉽게 입수하는 방법을 알게 되는 성과는 있었다.

QIIME 1에서는  Roche/454 pyrosequencing data 또는 barcode read가 별도로 주어지는 Illumina multiplexed single end data가 가장 다루기 편한 것 같다. 바코드 서열과 샘플의 연결 관계는 metadata mapping file(map.tsv)에서 주어진다. 이는 간단히 mapping file이라고도 부른다. 그러나 2019년 9월 초순 현재 국내 시퀀싱 서비스 업체에서는 16S rRNA 시퀀싱 데이터를 이러한 형태로 고객에게 전해주는 것 같지는 않다. 결과 파일인 seqs.fna에서 각 염기서열의 ID는 (샘플이름)_(일련번호)의 형식을 갖는다.


$ split_libraries_fastq.py -o slout/ -i forward_reads.fastq.gz -b barcodes.fastq.gz -m map.tsv

Paired end read라면 join_paired_ends.py 스크립트로 연결한 뒤 추가적으로 바코드 정보를 업데이트해야 하므로 살짝 작업이 번거로워진다. 바코드 업데이트가 필요한 이유는 모든 read pair가 전부 성공적으로 연결되는 것은 아니기 때문이다. 지난주에 천랩에 고객에게 제공되는 16S rRNA amplicon sequencing data의 타입에 대해 문의하니 MiSeq 한 레인 단위의 복수의 샘플을 받아서 시퀀싱을 한 다음 전부 demultiplexing을 해서 고객에게 보내준다고 하였다. 이러한 데이터는 QIIME 1에서 오히려 다루기가 더 불편하다. QIIME 2의 문법으로 말하자면 이는 Casava 1.8 paired-end demultiplexed fastq 파일에 해당한다.

Demultiplexed paired end 데이터를 이용한 QIIME 분석의 좋은 사례는 2016년도 EDAMAME 워크샵(위키GitHub)에서 제공한 교육 자료에 있다. 이 자료를 만든 사람들 중에는 한국 사람이 틀림없는 이름(Sang-Hoon Lee)이 있어 반갑게 느껴지기도 했다. 여기에서 샘플 파일을 다운로드하여 압축을 풀면 V4 region을 증폭하여 MiSeq으로 양쪽에서 150 bp를 읽은 파일 54쌍이 나온다(C01D01F_sub.fastq, C01D01R_sub.fastq...). QIIME 1 script인 join_paired_ends.py는 한번에 한 쌍의 파일만 처리하므로, 파일이름 베이스를 수록한 list.txt를 만들어서 각 파일에 대하여 순차적으로 join_paired_ends.py을 실행한 다음 연결이 된 sequence만 가져다가 사용하는 스크립트인  Merged_Reads_Script.sh를 사용하는 방법을 소개하였다. 이 스크립트를 실행하면 몇 단계를 거쳐서 Merged_Reads라는 디렉토리에 52개의 fasta 파일이 만들어진다. 다음 단계에서는 add_qiime_labels.py를 사용하여 combined_seqs.fna라는 최종 결과물을 만든다. add_qiime_labels.py는 mapping file을 필요로 한다. 원래 이 파일에는 BarcodeSequence 컬럼이 있어서 각 read에 부가된 바코드로부터 sequence를 구분하는 중요한 역할을 하지만, 이 경우에는 이미 demultiplexing이 되어 있어서 이는 중요하지 않다. 단 InputFileName 컬럼에 있는 fasta file 이름이 각 sequence 파일을 분류하는 기준이 된다. 이 경우에는 필수 컬럼인 BarcodeSequence 컬럼은 공백으로 비워져 있어도 된다.

나는 Merged_Reads_Script.sh를 응용한 merge_paired_fasta.sh 스크립트를 만들어 보았다. 별도의 list.txt 파일이 없이도 쌍을 이룬 fastq 파일이 있으면 작동하며, 최종 결과물로서 fasta + fastq를 같이 만들어내는 것이다. Merged_Reads_Script.sh에서는 merged fastq를 지우도록 만들어 놓았다.

combined_seqs.fna 또는 seqs.fna 파일 내에서 각 서열의 번호는 새로운 샘플에 대해서 무조건 0또는 1부터 시작한다고 생각했는데 그건 착각이었다. 위에서 설명한 방법으로 만들어진 combined_seqs.fna의 서열 일련번호는 _1에서 시작하여(_0으로 시작하게 만들 수도 있음; 전산인들이 좋아하는 방법) 샘플이 바뀌어도 계속 증가한다. 사실 각 read가 구별만 되면 충분한 것이다. 만약 샘플마다 1번부터 시작하게 만들면 일련번호만으로 sequence를 구별하기 어려워지므로 이는 당연한 것이다.

Demultiplexed paird end data를 다루는 방법은 이상의 것이 가장 권장할 만한 것으로 보인다. 이것 외에도 오늘 오후를 종일 투자하여 QIIME 스크립트 자체에 충실한 방법을 만들어내기는 했는데 하도 신경쓸 것이 많아서 과연 이것을 블로그에 기록하는 것이 현명한 일인지 아닌지 잘 판단이 서지 않는다. 간단히 소개하자면 여기에서는 multiple_join_paired_ends.pymultiple_split_libraries.py를 사용한다. 하나의 디렉토리 안에 샘플별로 이름이 붙은 read pair가 전부 들어있는 경우(아마 대부분의 경우일 것임)와, 샘플별로 구분된 디렉토리 안에 한 쌍씩의 파일이 들어있고 이것 전체가 하나의 인풋 디렉토리에 들어있는 경우에 따라서 옵션이 약간 달라진다. 후자의 경우라면 fwd 및 rev read fastq file이 같은 이름을 갖고 있을 수도 있다. 샘플별로 이름이 붙은 디렉토리에 들어있으니 당장은 문제가 되지 않는다.

EDAMAME 데이터를 예로 들어서 설명해 본다. 54쌍의 read는 전부 샘플 이름을 기준으로 이름이 지어졌으니 하나의 인풋 디렉토리(예: Fastq)에 넣어서 작업을 해도 문제가 되지 않는다. --include_input_dir_path, --include_input_dir_path --remove_filepath_in_name 옵션을 주고 실행한 다음 결과 디렉토리가 어떻게 다르게 만들어지는지 한번 확인해 보라. --remove_filepath_in_name는 단독으로 쓰이지 못하고 항상 --include_input_dir_path와 같이 쓰여야 한다.

$ multiple_join_paired_ends.py -i Fastq --read1_indicator F_sub --read2_indicator R_sub -o output_folder
$ ls output_folder
C01D01F_sub  C01D02F_sub  C01D03F_sub  C02D01F_sub  C02D02F_sub  log_20190904164417.txt
$ ls output_folder/C01D01F_sub/
fastqjoin.join.fastq  fastqjoin.un1.fastq  fastqjoin.un2.fastq

각 샘플에 대하여 결과물에 대한 서브디렉토리가 생겼고 그 하위에 연결(join)된 것과 그렇지 않은 것들에 대한 fastq file이 생겼다. 여기서부터 주의를 해야 한다. 연결되지 않은 파일은 일단 제거를 해야 하고, 결과 디렉토리며에서 _sub는 없애는 것이 여러모로 편하다. 이것은 알아서 해결을 했다고 가정하고, 다음 단계인 multple_split_libraries_fastq.py로 넘어가자.

$ multiple_split_libraries_fastq.py -i output_folder/ -m sampleid_by_file -o final 
$ head -n 1 final/seqs.fna 
>fastqjoin.join.fastq_0 HWI-M03127:41:ACE13:1:2109:11596:14331 1:N:0:GGAGACAAGGGA orig_bc=AAAAAAAAAAAA new_bc=AAAAAAAAAAAA bc_diffs=0

$ multiple_split_libraries_fastq.py -i output_folder/ -m sampleid_by_file -o final2 --include_input_dir_path
$ head -n 1 final2/seqs.fna
>C01D01fastqjoin.join.fastq_0 HWI-M03127:41:ACE13:1:2109:11596:14331 1:N:0:GGAGACAAGGGA orig_bc=AAAAAAAAAAAA new_bc=AAAAAAAAAAAA bc_diffs=0

$ multiple_split_libraries_fastq.py -i output_folder/ -m sampleid_by_file -o final3 --include_input_dir_path --remove_filepath_in_name
$ head -n 1 final3/seqs.fna
>C01D01_0 HWI-M03127:41:ACE13:1:2109:11596:14331 1:N:0:GGAGACAAGGGA orig_bc=AAAAAAAAAAAA new_bc=AAAAAAAAAAAA bc_diffs=0

--include_input_dir_path --remove_filepath_in_name 옵션을 전부 준 세번째 것이 가장 바람직한 서열 ID를 만들어 내었음을 알 수 있다. 이것으로 pick_open_reference_otus.py를 아무런 에러 없이 실행하였다.

split_libraries_fastq.py를 무식하게 실행하여 소기의 목적을 달성할 수도 있다. 다음은 QIIME의 스크립트 설명에 나오는 가장 마지막 예제이다.

$ split_libraries_fastq.py -i lane1_read1.fastq.gz,lane2_read1.fastq.gz --sample_ids my.sample.1,my.sample.2 -o slout_not_multiplexed_q20/ -q 19 --barcode_type 'not-barcoded'

Fastq 형태로 join을 마친 파일을 한 곳에 가져다 놓고 그 이름을 콤마로 연결하여 -i file1,file2,file3...으로, 그리고 순서를 맞춘 샘플 이름을 --sample_ids sample1,sample2,sample3...으로 제공하면 될 것이다. Shell script를 이용하여 이는 어렵지 않게 구현해 보았다. 단, 바코드는 의미가 없으므로 --barcode_type 'not_barcoded' 옵션을 준다. 상당히 번거로왔지만 테스트는 잘 되었다.

마지막으로 가장 무식한 방법을 생각해 보았다. fastq 파일에서 barcode 판독 정보를 뽑아내는 것이다(multiple_extract_barcodes.py). 그 다음에 이들을 concatenation하여 도로 multiplexed fastq로 전환한 후 split_libraries_fastq.py를 실행하는 것. 원본 파일에 가까운 것을 재구성할 수는 있지만 너무 미련한 방법이다. 그리고 이미 demultiplexing이 된 파일을 입수해 보면 바코드 정보가 fastq 파일 내에 남아있지 않은 경우가 많다. 이론적으로는 안 될 이유가 없지만 시도하지는 말자.

2019년 9월 12일 업데이트

나의 위키 사이트(genoglobe.kr/kribb)에 일루미나 16S rRNA 시퀀싱 데이터를 처리하는 방법을 체계적으로 설명한 글을 올렸다.

2019년 9월 3일 화요일

간단한 AWK 활용 팁 - 컬럼 수의 총 합계 구하기 등

QIIME에서 사용하기에 좋은 매우 간단한 awk 활용 예제를 소개해 본다. OTU map file은 similarity에 의해 묶인 서열의 클러스터를 표현한 tab-delimited text file이다. 한 줄은 하나의 클러스터이며 맨 왼쪽은 클러스터의 ID, 나머지 컬럼은 클러스터를 이루는 각 서열의 ID이다.


총 몇 개의 서열이 클러스터를 이루는 것일까? awk가 이를 간단하게 계산해 준다.

$ awk 'BEGIN{s=0}{s+=NF-1}END{print s}' final_otu_map.txt

NF는 awk의 내장 함수로서 컬럼의 수를 의미한다. 첫번째 컬럼은 클러스터 ID므로 NF에서 하나를 뺀 것을 더해나간 뒤(변수 s에 저장), 파일의 모든 라인에 대한 처리가 끝나면 인쇄를 하면 된다.

다음은 조건에 맞는 줄은 편집을 하고, 그렇지 않은 줄은 그대로 출력하는 방법을 알아본다. 작년에 'awk를 이용한 같단한 텍스트 파일 조작(join)'이라는 제목의 글로 그 기본 원리에 대해서 이미 포스팅을 한 적이 있었다. 다음은 Gopalakrishnan의 2018년도 Science 논문에서 다룬 16S rRNA sequencing 결과 중 하나인 ERR2162226의 일부를 표시한 것이다.


엄밀히 말하자면 이 파일은 MiSeq가 생산한 그대로의 파일이 아니다. Wargo.R2d2_45029를 서열 ID로 전환하는 것이 오늘의 목표이다. '/1'은 제거해야 한다.

Awk를 사용하면 다음과 같이 명령행 한 줄로 끝난다.


$ awk '/^@ERR2162226/{printf "%s%s\n", "@", substr($2,1,length($2)-2);next}{print}' ERR2162226.fastq > ERR2162226-mod.fastq

awk '조건{명령A; next}{명령 B}' 텍스트파일

이 명령을 이해하는 것이 핵심이다. 조건에 맞으면 A를 실행한 뒤 next를 통해서 뒷쪽의 {명령B} 블록을 건너뛰고, 조건에 맞지 않으면 곧바로 {명령B}를 실행한다. if..else에 해당하는 문법이 아니다!. 만약 next가 없으면, 조건에 맞는 줄에서 명령A를 실행한 뒤, 그 줄에 대해서 또, 명령 B를 실행하게 된다. 이것을 가지고서 fasta로 전환한 뒤(split_libraries_fastq.py의 -q 19 옵션을 적용하여 quality에 의해 필터링하는 것을 똑같이 구현하려면 쉽지는 않음) pick_otus.py 명령을 실행하여 실습을 진행하면 된다.

awk의 printf 함수와 substr 함수의 용법도 이번에 공부를 해 두면 도움이 될 것이다.

2019년 8월 31일 토요일

요즘의 손목시계 크기란...


가장 최근에 산 시계 위에 갖고 있는 것 중에서 가장 오래된 결혼 예물 시계를 얹어 보았다. 과거에 비하면 너무 크다. 아마 직경이 1 cm 정도는 늘어난 것 같다. 손목이 두껍지 않은 남자에게는 과하게 크다는 느낌이 들 때가 많다.

나는 시계 디자인 요소 중에서 시인성을 가장 중요하게 생각한다. 노안이 무척 심하게 왔기 때문이다. 큰 사이즈의 디자인은 분명 도움이 된다. 그러나 시계 케이스의 지름 자체보다는 바늘과 인덱스의 크기·디자인, 다이얼과 바늘의 색깔 대조 등이 시인성에 더욱 중요하다. 그래서 안경을 쓰지 않고는 제대로 보이지 않는 날짜 및 요일 창이나 크로노그래프용 작은 다이얼을 별로 좋아하지 않는다.

시인성 측면에서는 다이버 시계만 한 것이 없다. 일반적인 다이버 시계는 그대신 무겁고 크다는 것이 문제다.

2019년 8월 30일 금요일

QIIME 1을 공부하면서 느낀 점

QIIME 2가 2018년에 공개되면서 QIIME 1에 대한 공식 지원은 중단되었다. 16S rRNA 염기서열에 의한 미생물 군집 분석을 처음 공부하는 입장이라면 당연히 QIIME 2를 가지고 시작하는 것이 바람직할 것이다. 그러나 QIIME 1에 관해서는 워낙 많은 공부자료가 인터넷에 널려있고, SRA에서 raw data를 받아서 실제로 따라서 해 보니 의외로 16S rRNA 염기서열에 기반한 microbial(요즘 유행되는 용어로는 microbiome) taxonomic profiling의 분석 과정에 대해서 많은 것을 알게 되었다. 뒤에서도 언급하겠지만 QIIME 2는 편의성과 일관된 인터페이스(물론 명령행 기반이지만) 안에 기본 원리가 살짝 숨겨져 있다는 느낌이 든다. 또한 부속 스크립트(전체 목록)가 매우 풍부하여 다른 용도로도 사용하기에도 좋다. conda environment가 아니라 CentOS 7에 원래 깔려있는 파이썬 환경에 설치하기를 잘했다고 느끼고 있다. QIIME 1을 사용할 때에는 FastTree와 USEARCH를 최신 버전이 아닌 것으로 잠시 되돌리는 트릭을 써야 하는 불편함이 있지만 말이다.

며칠 동안 QIIME 1을 다루면서 어렵다고 느낀 점은 다음의 두 가지였다. QIIME 2에서는 전부 편리하게 개선이 되었을지도 모르겠다.
  1. 입력 파일에 대한 철저한 이해가 필요하다.
  2. OTU picking과 chimera 제거의 과정에서 선택의 폭이 넓다. 특히 chimera 제거를 언제 하는 것이 좋은지에 대해서는 좀 더 고민이 필요하다.
지금까지 나의 시퀀싱 경험은 전적으로 미생물 단일 유전체에 대한 것이다. 커다란 유리판에 손으로 부어서 만드는 시퀀싱용 polyacylamide gel에서부터 ABI 3700을 거쳐 Roche/454 Illumina, Ion Torrent, PacBio, 그리고 약간의 MinION까지... 1991년부터 시퀀싱을 해 왔지만 많아봐야 일루미나 장비 기준으로 하나의 레인에서 생성된 최대 12개 정도 샘플에 대한 paired read - 이미 demultiplexing이 되어 샘플 수 x 2에 해당하는 - fastq 파일을 가지고 분석을 시작하는 것이 전부였다. 전형적인 파일 이름의 형태는 L2S357_15_L001_R1_001.fastq.gz와 같다. QIIME 2에서 쓰는 용어로 말하자면 Casava 1.8 paired-end demultiplexed fastq에 해당한다(QIIME 2 documentation - Importing data 링크). 동시에 처리했던 데이터 중 최대 규모였던 것은 150개 정도의 박테리아 균주 유전체에 대한 일루미나 결과였다. 인간 유전체를 다루는 사람에게는 명함도 내밀지 못할 수준이 아닌가.

QIIME '2'의 튜토리얼을 따라가며 공부를 하다가 제일 먼저 놀랐던 것은 바코드를 읽은 fastq 파일이 따로 존재한다는 것이었다. 그러면 SRA에 raw data를 제출할 때에는 어떻게 하지? 실제로 천랩에서 sequencing only service를 요청하면 어떤 결과를 제공할까? 다음주에 곽 박사에게 물어봐야 되겠다. QIIME 1 공식 문서의 Preparing raw Illumina data in different formats for use with QIIME에도 포맷에 따른 일루미나 파일 처리에 대한 유용한 정보가 많다. Single-end read와 barcode read로 구성된 한 쌍의 파일은 EMP(Earth Microbiome Project) protocol의 multiplexed single-end fastq라 부른다. 이것을 처리하는 QIIME 1 script는 split_libraries_fastq.py이다. Paired-end fastq는 join_paired_ends.py로 처리한다. 341F와 805R 프라이머로 16S rRNA의 V3-V4 region을 증폭한 산물의 크기는 중간값이 421 bp이다(링크). Amplicon을 만들어서 MiSeq으로 2 x 250 cycle pair end sequencing을 하면 중간을 연결하기에 매우 적당하다. Join이 얼마나 성공적이었는지 확인하고, 부속되는 바코드 read 파일을 업데이트하는 일이 필요하다. Input read 전부가 성공적으로 연결되지는 않으므로, 후속 분석 작업을 하려면 원본 바코드 read로부터 join된 read의 것만을 남겨야 하기 때문이다. 바코드 입력 데이터 파일 처리 방법은 QIIME 2가 좀 더 일관적이며 합리적인 것으로 느껴진다. QIIME 1에서는 다음과 같이 파일 타입(일루미나)에 따라 다른 방법을 취해야 한다. 
  1. EMP multiplexed SE fastq: split_libraries_fastq.py(quality filtering 가능: -q 19)
  2. EMP multiplexed PE fastq: join_paired_ends.py + split_libraries_fastq.py
  3. Casava 1.8 PE demultiplexed fasqt: join_paired_ends.py + add_qiime_labels.py 이것은 이해하기가 조금 까다롭다. Edamame course의 교육 자료를 보면 도움이 될 것이다. EDAMAME(Exploration in Data Analysis for Metagenomic Advances in Microbial Ecology)에서 개최하는 교육 코스이다.
2018년 Science에 실린 Gopalakrishnan 등의 논문 'Gut microbiome modulates response to anti–PD-1 immunotherapy in melanoma patients'에서 ENA에 등록한 FMT 실험 마우스의 16S sequencing data(study accession PRJEB22895)를 다운로드하여 보았다.


서열 ID(Wargo.R2d7_45029)를 보면 이미 demultiplexing이 된 상태임을 알 수 있다. 아마도 split_libraries_fastq.py를 --store_qual_scores 인수와 함께 실행하여 FASTA 및 .qual 파일을 함께 만든 다음, convert_fastaqual_fastq.py을 실행하여 fastq로 전환한 것 같다. 외견상으로는 single end fastq이지만, 논문에서는 paired end sequencing 결과를 join하였다고 밝히고 있다. 시퀀싱 결과물을 제출하기 편리하게 만들기 위해 전환을 한 것임에 틀림없다. 저러한 형태의 파일은 절대로 일루미나 장비에서 생산된 직후의 모습이 아니다. Wargo는 이 논문의 교신저자 이름이니 말이다.

Chimera 제거는 반드시 필요하다고 생각한다. 천랩의 자료에 의하면 16S rRNA의 454 sequencing 데이터에서 약 15-20%가 chimera였다는 논문을 인용하였다. 그러나 Illumina Overview Tutorial에서는 이 과정이 생략되어 있다는 것이 의외였다. Chimera 제거는 OTU picking 전에 모든 read(seqs.fna)에 대해서 할 수도 있고, 그 후에 할 수도 있다. 공식적으로는 identify_chimeric_seqs.py를 이용하여 제거하지만(ChimericSlayer 또는 USEARCH 6.1 사용; 설명 링크) QC 과정의 일종인 usearch quality filter(pick_otus.py -m usearch로 작동; 설명 링크)를 사용할 수도 있다. Reference sequence가 필요한 방법도 있고 de novo로 검출하는 방법도 있다. OTU picking을 마친 뒤 각 클러스터에서 뽑은 대표 서열을 가지고 chimera를 검출한 경우 phylogenetic tree와 alignment 등에서 이를 제거해야 한다. 개인적인 견해로는 UCHIME을 사용하는 usearch quality filter로 모든 read를 먼저 처리한 다음 이것을 가지고 OTU picking, 대표서열 추출, taxonomic assignment 및 tree building을 순차적으로 실행하는 것이 바람직한 것 같다. pick_open_reference_otus.py를 실행하면 단 하나의 스크립트로 이 모든 것을 다 진행할 수 있다.

OTU picking의 여러 방법, biom 파일의 구조 등 공부할 것이 너무나 많지만 워낙 양이 많아서 여기에서 다 기술하기는 어렵다. QIIME 2에서는 개념이 너무나 많이 바뀌었다. QIIME 1에서는 454 데이터에 대해서만 쓰이는 denoise라는 용어가 QIIME 2로 와서는 아주 일반적으로 쓰이는 것도 같고, OTU cluster는 feature라는 말로 바뀐 것 같으며, 모든 데이터가 .qza라는 'artifact' 파일로 다루어진다는 것이 외견상 깔끔해 보이기는 해도 마치 두꺼운 포장재로 둘러싸인 상자 속 물건을 다루는 것 같아서 아직은 좀 어색하다.

Denoising이란 오류를 교정하는 일이라고 한다. 그런데 genome assembly를 위한 일루미나 데이터의 전처리에서는 error correction이라고는 불러도 denoising이란 말은 잘 쓰지 않는다. 근본적으로 동인할 일을 서로 다른 분야에서 약간 다르게 부르는 것인지, 혹은 16S rRNA amplicon에서 오류 정정을 하는 방법이 독특하기 때문에 별도의 용어로 칭하는 것인지는 잘 모르겠다. 가령 SPAdes assembler의 error correction 모듈을 16S amplicon data에 적용해도 될까?

Alpha 및 beta diversity에 대한 간단한 설명은 metagenomics wiki에 수록되어 있다. OTU table을 만든 다음에 해야 할 일에 해당한다.

일주일 정도 더 QIIME 1을 주물러 봐야 일정 수준의 이해도에 오를 것 같다. 그 다음에는 설치만 해 놓고 방치했던 QIIME 2를 다시 시작해 봐야 한다.

QIIME 2의 특징(논문에서 인용)

  • Interactive spatial and temporal analysis and visualization tools
  • Support for metabolomics and shotgun metagenomics analysis
  • Automated data provenance tracking to ensure reproducible, transparent microbiome data science

참고 자료


2019년 8월 28일 수요일

QIIME 1 어렵게 설치하기

이미 대세는 QIIME 2(공식 웹사이트)라고 생각되는데 왜 이제와서 QIIME 1인가? 사실 내가 쓰는 서버에도 qiime2가 conda environment(v2019.1) 및 docker image(v2018.11)로 설치된 상태라서 이런 수고를 할 필요는 없었다. 그러나 요즘 읽고 있는 논문 "Microbiota and cancer immunotherapy: in search of microbial signals"(Gut 2019 Vol 68 No 3)에 큰 흥미를 느껴서 여기에서 수행한 분석 방법을 따라서 연습을 해 보기로 마음을 먹었다. 최근 면역체크포인트 억제제(PD-1 억제제)를 사용한 항암 치료가 개인에 따라서 다른 치료 성적을 보이며(R: responding vs NR: non-responding), 그것은 microbiome과 연관이 있다는 논문이 발표되어 큰 주목을 끌었다. 다음은 사례로 든 논문 세 가지. 전부 2018년 Science에 연달아서 발표된 논문이다. 나는 이 중에서 Gopalakrishnan et al이 쓴 논문의 16S sequencing raw data를 가지고 연습을 할 생각이다.

[12] Routy B, Le Chatelier E, Derosa L, et al. Gut microbiome influences efficacy of PD-1-based immunotherapy against epithelial tumors. Science 2018;359:91–7.
[13]  Gopalakrishnan V, Spencer CN, Nezi L, et al. Gut microbiome modulates response to anti-PD-1 immunotherapy in melanoma patients. Science 2018;359:97–103.
[14]  Matson V, Fessler J, Bao R, et al. The commensal microbiome is associated with anti-PD-1 efficacy in metastatic melanoma patients. Science 2018;359:104–8.


2019년도 Gut 논문에서는 이상의 세 가지의 연구 사례에서 공통적인 'microbial signal'이 없다는 점에 착안하여 같은 분석 파이프라인을 적용하여 어떤 결과가 나오는지를 살펴보기로 한 것이다. 16S 데이터는 QIIME 1.9.1을, shotgun metagenome data는 MetaPhlAn2를, R과 NR 집단에 연관된 바이오마커 동정에는 LEfSe를 사용하였다. 결론에서는 taxonomic profiling으로는 두 집단을 가르는 '미생물 시그날'을 찾아내긴 어려우며, function의 차이를 유의해서 보아야 될 것이라 하였다. 그러려면 shotgun 방색의 metagenomics가 앞으로는 더욱 중요하다는 뜻이 된다. 예전에는 assembly 기반의 shotgun metagnomic에 관심이 많았었지만 용도에 따라서는 그럴 필요가 없다고 느껴진다.

QIIME Installation Guide에 따르면 Miniconda에서 환경을 만들라고 하였다. 파이썬은 2.7을 쓰라고 하였다. 나는 Anaconda를 설치해 두었으니 여기에서 시작하면 되겠다고 생각을 했다. 그런데...

(base) $ conda create -n qiime1 python=2.7 qiime matplotlib=1.4.3 mock nose -c bioconda
...
PackagesNotFoundError: The following packages are not available from current channels:

  - matplotlib=1.4.3

matplotlib의 버전(1.4.3)이 너무 옛날 것인가? 채널에 해당되는 버전이 없다는 에러 메시지가 나왔다. 그래서 matplotlib 뒤에 지정된 버전을 지우기도 하고, 파이썬만 있는 qiime1 conda environment만 먼저 만들어서 여기에 진입하여 qiime1을 설치하는 등 여러 시도를 했지만 'Package XYZ conflicts for:'에러가 수십개나 발생하는 것이다. 이래서는 도저히 안되겠다 싶어서 alternative installation methods document를 확인하였다. 시스템에 원래 설치된 python 2.7에서 관리자 권한으로 pip를 사용하여 최소 설치를 하면 될 것이라 생각을 하였다.

회사 환경은 SSL 인증서 문제로 프로그램 설치가 참 까다롭다. conda, git, pip... 뭐 하나 쉬운 것이 없다. pip를 쓰려면 명령행에 누더기처럼 --trusted-host pypi.org --trusted-host files.pythonhosted.org를 덧붙여야 한다.

문서를 보면 먼저 numpy를 설치하란다. 이는 이미 설치가 되어 있는 상태이다. 그러면 본격적으로 QIIME 1.9.1을 깔아보자!

# pip install qiime==1.9.1 --trusted-host pypi.org --trusted-host files.pythonhosted.org
...
ERROR: ipython 5.8.0 has requirement setuptools>=18.5, but you'll have setuptools 0.9.8 which is incompatible.
ERROR: ipapython 4.6.4 has requirement dnspython>=1.15, but you'll have dnspython 1.12.0 which is incompatible.
ERROR: ipapython 4.6.4 has requirement python-ldap>=3.0.0b1, but you'll have python-ldap 2.4.15 which is incompatible.

이건 또 뭔가? setuptools, dnspython, 그리고 python-ldap만 수동으로 설치하면 되려나? pip install로 하나씩 설치를 해 나가는데 또 이런 에러 메시지가 나왔다.

ERROR: Cannot uninstall 'XYZ'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.

구글을 뒤져보니 이 에러는 distutils가 설치한 프로그램이라서 정확히 어떤 파일이 제거되어야 하는지 알 수 없다라는 의미입라고 한다(distutils는 uninstaller 를 가지고 있지 않아서 distutils로 설치하면 지우기가 어렵다고 함). 이런 경우에는 --ignore-installed 옵션을 쓰라고 한다. 즉 다음과 같이 하여 별로 필요하지 않은 requirement를 일일이 점검하지 않고 다시 QIIME을 설치하게 만들었다.

# pip install --ignore-installed qiime==1.9.1 --trusted-host pypi.org --trusted-host files.pythonhosted.org

설치가 끝났으면 테스트 스크립트를 실행한다.

# print_qiime_config.py -t
...
ImportError: No module named Tkinter

이것은 또 뭔가? Tkinter라는 Tcl/Tk 파이썬 인터페이스 패키지가 없다는 에러이다. 전에도 본 일이 있다. yum으로 tkinter를 설치하면 된다. 우분투용 패키지 이름은 python-tk, python3는 python3-tk라고 한다. 내 환경은 CentOS 7이다.

자, 그러면 다 되었겠지?

# print_qiime_config.py -t
AssertionError: Unsupported FastTree version. 2.1.3 is required, but running 2.1.10.

아이고, 별게 다 속을 썩인다. FastTree-2.1.3 소스 코드를 가져다가 컴파일하였다.

# mkdir /usr/local/apps/FastTree-2.1.3
# cd /usr/local/apps/FastTree-2.1.3
# wget http://www.microbesonline.org/fasttree/FastTree-2.1.3.c
# gcc -O3 -finline-functions -funroll-loops -Wall -o FastTree FastTree.c -lm
# ln -s FastTree fasttree

방금 빌드한 fasttree 바이너리가 가장 먼저 인식되도록 PATH 변수를 수정한 다음 다시 print_qiime_config.py -t를 실행하였다. 드디어 에러가 하나도 발생하지 않았다. 얼마나 반가운 OK 사인인가!

# PATH=/usr/local/apps/FastTree-2.1.3:$PATH
# print_qiime_config.py -t


System information
==================
         Platform: linux2
   Python version: 2.7.5 (default, Jun 20 2019, 20:27:34)  [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]
Python executable: /usr/bin/python

QIIME default reference information
===================================
For details on what files are used as QIIME's default references, see here:
 https://github.com/biocore/qiime-default-reference/releases/tag/0.1.3

Dependency versions
===================
          QIIME library version: 1.9.1
           QIIME script version: 1.9.1
qiime-default-reference version: 0.1.3
                  NumPy version: 1.16.5
                  SciPy version: 1.2.2
                 pandas version: 0.24.2
             matplotlib version: 2.2.4
            biom-format version: 2.1.7
                   h5py version: Not installed.
                   qcli version: 0.1.1
                   pyqi version: 0.3.2
             scikit-bio version: 0.2.3
                 PyNAST version: 1.2.2
                Emperor version: 0.9.61
                burrito version: 0.9.1
       burrito-fillings version: 0.1.1
              sortmerna version: SortMeRNA version 2.0, 29/11/2014
              sumaclust version: SUMACLUST Version 1.0.00
                  swarm version: Swarm 1.2.19 [Aug 28 2019 11:29:13]
                          gdata: Installed.

QIIME config values
===================
For definitions of these settings and to learn how to configure QIIME, see here:
 http://qiime.org/install/qiime_config.html
 http://qiime.org/tutorials/parallel_qiime.html

                     blastmat_dir: None
      pick_otus_reference_seqs_fp: /usr/lib/python2.7/site-packages/qiime_default_reference/gg_13_8_otus/rep_set/97_otus.fasta
                         sc_queue: all.q
      topiaryexplorer_project_dir: None
     pynast_template_alignment_fp: /usr/lib/python2.7/site-packages/qiime_default_reference/gg_13_8_otus/rep_set_aligned/85_otus.pynast.fasta
                  cluster_jobs_fp: start_parallel_jobs.py
pynast_template_alignment_blastdb: None
assign_taxonomy_reference_seqs_fp: /usr/lib/python2.7/site-packages/qiime_default_reference/gg_13_8_otus/rep_set/97_otus.fasta
                     torque_queue: friendlyq
                    jobs_to_start: 1
                       slurm_time: None
            denoiser_min_per_core: 50
assign_taxonomy_id_to_taxonomy_fp: /usr/lib/python2.7/site-packages/qiime_default_reference/gg_13_8_otus/taxonomy/97_otu_taxonomy.txt
                         temp_dir: /tmp/
                     slurm_memory: None
                      slurm_queue: None
                      blastall_fp: blastall
                 seconds_to_sleep: 1

QIIME base install test results
===============================
.........
----------------------------------------------------------------------
Ran 9 tests in 0.026s

OK

다음으로는 도커 이미지도 다운로드해 두었다.

# docker pull quay.io/biocontainers/qiime:1.9.1--np112py27_1

pip를 이용하여 개별적으로 설치하느라 괜히 고생을 한 것은 아닌지 모르겠다.


2019년 8월 26일 월요일

고등학생이 제1저자로 쓴 논문 논란에 대하여 생각해 보다

조국 법무부장관 후보자의 딸이 고등학생 시절 어느 의대에서 잠시 인턴으로 일을 하고 제1저자로 낸 논문(eNOS gene polymorphisms in perinatal hypoxic-ischemic encephalopathy 링크 doi: https://doi.org/10.4132/KoreanJPathol.2009.43.4.306)에 대한 논란이 연일 뜨겁게 펼쳐지고 있다. 장관 후보자 인사청문회에서는 후보자 개인의 자질과 정책에 대한 검증이 이루어지는 것이 우선시되어야 함은 당연하다. 현재 논란이 되는 모든 일은 일단은 조국 개인과는 관계가 없는 일이라고 볼 수도 있다. 비록 당시에는 법의 테두리 안에서 이루어진 일이라 해도, 수험생 자녀를 둔 일반인의 정서에는 맞지 않는데다가 많은 국민이 문제를 제기하고 있으니 그냥 넘어가기는 어렵다. 더군다나 부모로서 이 사태에 대하여 어느 정도의 책임이 있음은 당연하다. 만약 이 일에 조국은 일절 관여하지 않고 그 순전히 아내가 기획한 일이라면? 일단은 직접적인 책임은 없다고 본다. 하지만 그 기획 과정에서 조국과 그 아내(역시 교수)의 사회적 지위가 절대적으로 작용했음은 부인하기 어렵다.

학술지에 출간되는 논문에 대해서 정확하지 않은 정보가 너무 범람하는 것 같아서 내가 아는 한도 안에서 이를 정리해 보고자 한다.

논문이란 연구자가 자신의 업적을 인정받는 유일하고도 객관적인 결과물이다. 물론 특허라는 제도도 있지만 학계에 있는 사람에게는 좋은 논문을 내서 자주 인용되는 것만큼 영광스러운 일이 없다. 황우석 사태 이후 연구진실성에 대한 인식이 크게 높아진 것은 대단히 바람직한 일이다. 그런데 연구진실성·연구윤리에는 실험 데이터를 위·변조하지 않는 일만 포함되는 것이 아니다. 이를 논문으로 출판할 경우 저자를 부당하게 표시하지 않는 것도 포함된다. (구)교육과학기술부가 『연구윤리확보를 위한 지침』에서 제시한 연구부정행위의 범위를 알아보자.
연구부정행위(이하 "부정행위"라 함은 연구의 제안, 연구의 수행, 연구 결과의 보고 및 발표 등에서 행하여진 위조·변조·부당한 논문저자 표시 행위 등을 말하며 다음 각 호와 같다.
  • "위조"라 함은 자료나 연구결과를 허위로 만들고 이를 기록하거나 보고하는 행위를 말한다.
  • "변조"라 함은 연구와 관련된 재료·장비·과정 등을 조작하거나 데이터 또는 연구결과를 변경하거나 누락시켜 연구기록이 진실에 부합되지 않도록 하는 행위를 말한다.
  • "표절"이라 함은 타인의 아이디어, 연구내용·결과 등을 정당한 승이 또는 인용 없이 도용하는 행위를 말한다. 
  • "부당한 논문저자 표시"라 함은 연구내용 또는 결과에 대하여 과학적·기술적 공헌 또는 기여를 한 사람에게 정당한 저자 자격을 부여하지 않거나, 과학적·기술적 공헌 또는 기여를 하지 않은 자에게 감사의 표시 또는 예우 등을 이유로 논문 저자 자격을 부여하는 행위를 말한다. 
  • 본인 또는 타인의 부정행위 혐의에 대한 조사를 고의로 방해하거나 제보자에게 위해를 가하는 행위
  • 기타 학계에서 통상적으로 용인되는 범위를 심각(현저)하게 벗어난 행위
  • 타인에게 상기의 부정행위를 행할 것을 제안 강요하거나 협박하는 행위 
이상의 기준에서 판단하자면 이번 문제는 조 모 씨가 과연 정당한 제1저자가 맞는지에 대한 것으로 구체화하여 생각하면 된다. '책임저자'였던 단국대 교수가 만약 자기에게 돌아올 어떤 댓가를 기대하고 그러한 일을 했다면 그것은 또 다른 심각한 문제가 된다. 자, 그러면 논문에 저자로서 이름을 올릴 사람은 어떠한 자격을 갖추어야 하는가? 이야기가 길어지니 사이언스온에 실린 '저자의 자격': 누가 저자이며 저자가 아닌가?를 먼저 읽어보면 답은 명확하다.

일단 우리나라에서만 통용되는 '책임저자'라는 부정확한 용어에 대해서 짚고 넘어가자. 책임저자란 아마도 교신저자(corresponding author)를 번역한 것으로 생각된다. 교신저자는 논문의 투고와 수정, 저널측에 대한 저작권 양도(별로 마음에 들지는 않지만), 게재료 납부 등 저자를 대표하여 출판사 측과의 교신을 담당하는 사람을 말한다. 학교라면 대개 교수가 이 일을 맡게 된다. 투고와 출판에 이르는 모든 과정에서 소통의 창구 역할을 수행하므로 그 책임이 매우 크다. 그러나 우리나라에서는 학술 논문에 점수를 매겨서 업적으로 활용하는 체계가 워낙 잘(?) 잡혀 있지 않은가? 점수에는 늘 공정성 시비가 붙기 마련이므로 매우 객관적인 것처럼 보이는 우스꽝스런 체계를 만들게 되었으니 그것이 바로 제1저자 혹은 교신저자에 절대적인 가중치를 부여하고 나머지는 순서에 따라서 낮은 점수를 부여하는 계산식을 만들게 된 것이다. 따라서 모든 저자를 결정하는 권한 - 저자로 포함되는 것을 허락하고 그 순서를 정하는 - 이 있다고 일반적으로 여겨지는 교신저자는 논문이라는 업적에서 막강한 권위를 휘두르는 위치로 인식된다. 임팩트 팩터가 높은 학술지는 그야말로 성배와 같다. 하지만 이 계산식에 따르면 아무리 학술지 자체의 임팩트 팩터가 높다 해도 저자가 많은 논문(요즘은 협업이 워낙 많고 연구의 규모가 커져서 저자수가 많은 논문이 흔하다) 중 하나의 공저자라면 이 점수가 희석되므로 나의 일자리 찾기나 승진에 써먹기는 힘들다. 그래서 여러 고려를 한 끝에 그 논문의 혜택을 가장 많이 볼 사람, 즉 그 논문을 업적으로 삼아서 일자리(조 모 씨의 경우에는 대학입시였을 것이다)나 승진을 원하는 사람이 제1저자를, 지도교수의 경우는 교신저자 위치를 갖게 배려하였을 것이다. 그 교신저자가 이러한 저자 결정 - 즉 고등학생을 제1저자로 만듦으로써 - 을 통하여 직접적인 이득을 받았을 것으로는 여겨지지 않는다. 다만 비슷한 '계급'에 있는 사람들끼리 서로 자녀들의 대입에 도움이 되도록 품앗이를 하는 수준의 일이었을 것이다. 그렇다면 기분나쁠 사람은 누구인가? 이러한 그들만의 방식이 있다는 것을 전혀 모르는 일반 사람들, 그리고 문제의 논문을 출판한 학술지 관계자가 되겠다. 그리고 논문을 투고할 때 모든 저자는 논문의 내용에 동의해야 한다. 여기에는 저자의 포함 여부 및 서로의 위치에 대해서 동의함을 포함한다. 그러나 현실적으로는 제1저자와 교신저자 이외의 사람들은 '아니 저 사람이 무슨 일을 했다고 첫/두번째 저자요? 말도 안됩니다. 난 이 논문 내는 거 동의 못해요!'라고 나서지는 못한다. 그리고 이러한 업적 다툼을 해결하는 가장 현명하고도 교활한 방식은 공동제1저자 혹은 공동교신저자를 만드는 것이다! 두 명은 기본이며 많게는 세 명, 혹은 그 이상까지... 나는 이 치졸한 방식이 우리나라 논문에 많다고 믿는다. 뒤에서 이야기할 연구비 지원 기관의 성과 압박도 이러한 기형적인 행태에 일조를 하고 있다.

단순한 데이터의 생산이나 영문 번역으로는 저자의 자격을 가질 수 없다는 것이 요즘의 보편적인 기준이다. 조 모 씨가 뛰어난 영어 실력이 있었고 이 능력을 발휘하여 영문(번역?)을 잘 써서 제1저자 위치를 주었다는 지도교수의 변명은 너무 궁색하다. 이미 수집된 데이터에 대해서 과학적으로 의미가 있는 분석을 실시하고, 논문의 상당 부분을 처음부터 작성해서 이 주제에 대해 다른 어느 저자보다도 잘 꿰뚫고 있어야 올바른 제1저자의 자격이 있다. 고등학생이 의학분야의 전문 용어를 몇 주 공부해서 논문을 번역할 수준이 된다는 것은 말도 되지 않고(인턴을 하기 몇 달 전부터 이 분야를 열심히 공부했음을 증명할 수 있을까?), 만약 번역에서 중요한 기여를 했다 해도 이것만으로는 제1저자는커녕 공저자의 자격을 묻기도 어렵다. 이런 고마움을 표시하라고 사사(acknowledgments)가 있는 것이다. 예를 들어서 "Understanding the Differences between Genome Sequences of Escherichia coli B Strains REL606 and BL21(DE3) and Comparison of the E. coli B and K-12 Genomes" 2009년도 논문(링크)의 Fig. 1은 내가 직접 그렸다. Genome sequence alignment에서 얻어진 좌표를 xfig 데이터파일 형태로 고치는 무식한(?) Perl 스크립트를 통해서 말이다. 하지만 내 이름은 사사에만 언급되어 있을 뿐이다.

'별로 중요하지도 않는 국내저널에 내는 큰 의미없는 논문..이라면 지도교수가 제1저자와 책임저자를 다 하기는 껄끄러웠을 수도 있겠다' (기사 링크) 우종학 교수의 이러한 의견은 학술지에 대한 예의가 아니라고 생각한다. '기존의 데이터를 썼다;라는 표현도 적절하지 않다. 최소한 기존의 데이터라고 표현하려면 다른 논문에서 한번 다루었던 데이터를 새로운 측면에서 바라보기 위해 다시 분석을 했다거나, 또는 아직 논문화까지는 되지 않았다 해도 공개 DB에 등록된 데이터를 다운로드하여 분석을 했을 때 비로소 이렇게 말할 수 있다. 해당 논문을 읽어보라. 목적을 가지고 실험을 설계하여 임상 샘플로부터 DNA를 추출하여 시퀀싱을 실시했고(37명의 환자와 54명의 대조군 시료), 이를 통계적으로 분석한 것이다. 데이터 생산 시점과 분석 및 논문 작성에 시간차가 있다고 해서 기존의 데이터라고 말하기는 곤란하다. 학술지와 논문의 수준이 세계적 수준에 이르지 않는다고 하여 올바른 저자 표기 문제가 희석되리라고 생각한다면 대단히 곤란하다.

이 논문은 한국연구재단의 지원을 받아서 수행된 것이라고 한다. 논문에는 이러한 점을 사사에 보통 적게 된다. 돈을 지원했으니 논문이란 성과를 내야 하고(연구비 1억원당 임팩트 팩터 얼마짜리 논문이 몇 개나 나왔는지를 가지고 연구사업을 평가하는 슬픈 현실!), 논문과 연구과제의 연관성을 보이기 위하여 사사에 연구과제의 번호를 쓰게 하는 것이다. 게다가 그 연구사업의 책임자가 주저자(보통 제1저자와 교신저자)가 맞는지까지 점검한다. 그렇지 않으면 그 연구과제의 실적물로 인정하지 않겠다는 것이다. 심지어 사사에 포함되는 연구과제의 수가 너무 많으면 이를 인정하지 않기도 한다. 이런 경향은 우리나라가 좀 심한 것 같다. 그러나 모든 연구사업에는 기간이 있고, 기간이 종료되고 나서 논문이 나오는 일도 비일비재하다. 실제로 논문이 출판되기 위해 원래 연구사업에서 참여연구자로 등록되지 않은 다른 사람이 나중에 노력을 들이는 경우도 허다하다. 문제의 본 논문에서 사사한 KRF2006-331-E00163 과제의 책임자가 이 논문의 교신저자가 아니고 다섯번째 저자라는 것도 큰 문제는 되지 않는다. 그러나 여러 기사를 보면 교신저자가 논문을 출판하는 과정에서 이 과제를 사사했다는 것을 제5저자에게 제대로 알리지 않은 것 같다. 일단 이 문제는 제외를 하고 다음의 두 가지를 살펴보자. 이는 문제가 되는가?
  1. 연구사업이 끝나고도 상당한 시간이 지나도록 논문을 내지 않았다.
  2. 연구사업 신청서에 연구원으로 정식 등록되지 않은 사람이 이 사업에서 만들어진 데이터를 나중에 분석하여 논문을 냈다.
이상의 두 가지 사항은 연구부정이 아니다. 연구사업은 기간 내에 목적한 바를 이루고 '연구보고서'를 해당 기관에 제출하는 것으로 일단락이 된다. 임팩트 팩터 몇 점짜리 논문을 몇 편 내겠다고 사업신청서에 목표치를 제시했다고, 이를 달성하지 못하는 것을 문제시한다면 실패 가능성이 있는 도전적인 연구는 할 수가 없게 된다. 물론 아무리 노력을 해도 원하는 결과가 나오지 않거나, 결과는 잘 나왔지만 학술지 측에서 출판할만한 일로 인정을 하지 않아서 논문화가 되지 않는 일이 허다하다. 아예 논문을 쓰지 않고 있는 것과는 다른 일이다. 어쨌든 위의 두 가지 사항에 대해서는 문제를 삼지 않는 것이 맞다고 본다. 어떤 임상의는 이 논문이 정식 IRB(Institutional Review Board, 기관윤리위원회)의 심의를 통과한 것에 대해서 문제를 제기했다. 사람과 관계된 연구는 반드시 사전에 IRB를 통과해야 하고, 논문에도 이를 적시해야 한다. 하지만 IRB 승인을 위해 제출한 서류에 포함되지 않은 사람은 이 연구에서 나온 데이터를 절대 들여다보거나 분석해서는 안된다고 할 수는 없다. 그렇다면 IRB 신청서에 포함되지 않은 사람은 절대로 논문의 저자가 되어서는 안된다는 이상한 결론이 내려진다. 데이터의 민감한 부분을 제외한 나머지 사항을 분석하는 것은 상관이 없다고 생각한다.

오늘 올라온 기사(병리학회 이사장 "조국 딸 논문, IRB통과 허위땐 취소 사유" 링크)에 의하면 이 논문은 IRB를 통과했다고 적혀 있으나 실제로 병원 윤리위를 거치지 않았다고 한다. 물론 당시에는 IRB 통과가 의무 사항은 아니었다. 그러나 열리지도 않은 IRB에서 이 연구가 통과했다고 논문에 적었다면 이는 큰 문제가 된다. 내가 알기로 요즘 논문에서는 IRB 번호를 적어야 한다. 이렇게까지 해 놓지 않으면 'IRB를 분명히 열어서 통과했었었는데 관련 문서가 모두 폐기되어 입증하기가 곤란하다'고 대충 내두를 가능성도 있기 때문이다.

모든 논문은 하나의 연구과제를 통해서만 이루어진 성과라고 생각하면 현실을 너무 모르는 이야기이다. 간혹 몰염치한 연구자가 평가만 대충 통과하기 위해 하나의 논문에 여러 연구비를 사사하는 추태를 저지르기도 한다. 그렇다고 해서 연구과제에 참여연구원으로 이름을 올린 사람만 논문 저자에 포함되어야 한다거나, 인간을 대상으로 하는 연구에서 IRB 신청서에 이름이 오른 사람만 논문 저자에 포함되어야 한다고 주장한다면 이는 지나친 것이다.

다음으로는 논문에 표시된 조 모 씨의 소속기관 문제이다. 요즘 추세는 연구를 하던 당시의 소속 기관과 출간 시점의 소속 기관을 같이 표기하는 것을 원칙으로 한다. 사실 이것 가지고도 업적 다툼이 벌어진다. 만약 A라는 연구자가 미국 B 대학에서 포스트닥으로 일하던 시절 논문을 써 놓고 투고 등의 뒷일을 그쪽 지도교수에게 맡기고 귀국하여 C 대학에 조교수가 되었다고 가정하자. 조교수 A씨는 짧은 시일 내에 많은 논문을 내서 빨리 부교수로 승진을 해야 한다. 여기서 승진에 필요한 논문이라 함은 C 대학에 와서 한 일로 국한지어야 한다. C 대학에서 열심히 일을 하는 도중에 B 대학에서 써 놓고 온 논문이 좋은 학술지에 나갔다고 하자. 만약 그 논문에 저자의 소속을 C라고만 쓰는 것(옳지 않다!)과 B와 C를 같이 쓰는 것은 우리나라의 업적 계산기에서는 절반의 점수 차이를 가져온다. 마음 같아서는 C만을 소속으로 쓰고 싶겠지만, 대부분의 일이 이루어진 것은 B 대학 아니던가? 물론 C 대학에 와서 투고 및 리뷰 과정을 통과하기 위해 조금은 문서 작업을 했을 것이 당연하지만 말이다.

저널은 저자의 소속이 정말로 맞는지 재직증명서를 요구하지는 않는다. 일단 이것은 학자의 양심으로 믿고 가는 것이다. 그리고 부당한 논문저자 표시 여부를 검증할 의무 역시 저널측에는 없다. 이것은 전적으로 교신저자의 책임이다. 조 모 씨의 소속 기관은 단국대학교와 출판 당시의 소속(아마도 고등학교)이 병기되었어야 옳다고 본다. 단순 인턴이 단국대학교의 소속이었다고 볼 수 있는가? 만약 어떤 형태로든 단국대학교에서 이에 대한 경력 사항을 증명서 형태로 발급해 줄 수 있다면 괜찮다고 본다. 그러나 정식적이고 모두에게 열린 인턴 코스가 아니라 학부모끼리 '우리 애 한번 도와줘'의 형태로 논문을 만들기 위해 조 모 씨만을 위한 인턴 자리를 그때만 만들고 없앴을 가능성이 대단히 높다. 그리고 논란이 되는 것을 사전에 막기 위하여 재학 중이던 고등학교를 논문의 저자 소속에서 일부러 누락시켰을 가능성이 대단히 높다.

결론을 내리자면 이번 논문 문제는 당사자(즉 조 모 씨와 지도교수)에게 소명 기회를 준 다음, 논문을 철회하는 것이 맞다고 본다. 소명 내용에 따라 철회가 번복될 것 같지는 않다. 조 모 씨가 당시 미성년이었을 것이니 이를 감안할 수 있을지는 모르겠다. 그 논문이 만약 대학 입시에서 정말로 유리한 요소로 작용했다면, 이를 어떻게 해야 되나? 입학 취소? 그러면 대학원은? 난 그것까지는 모르겠다. 그리고 이것이 전부가 아니다. 공주대학교와 관련한 일도 해명이 필요한 상태이다.

만약 조국이 법무부 장관 후보로 거론되지 않았다면 이 일은 전혀 드러나지 않았을 것이다. 그리고 이렇게 그들끼리만 기회를 만들어서 자녀를 대학에 보내는 능력있는 부모들은 훨씬 더 많을 것이다. 그냥 이대로 사회가 굴러가게 만들 수는 없다고 생각한다.

사족

부정확한 저자 표시는 연구부정행위에 해당하며, 사안에 따라서 소속기관으로부터 징계 혹은 법적인 처벌을 받을 수 있다. 그러면 사사의 부정확한 표기는 어떻게 될까? 아직까지는 사사의 부정확한 표기에 대해서는 연구부정행위로는 다루지 않는 것 같다. 부연하자면 논문에서 사사한 과제의 계획서에 작성했던 내용과 논문이 잘 부합하는지까지를 체크하지는 못한다. 만약 여기까지 실사가 이루어지고 정직하지 못한 연구과제 사사를 문제시한다면 걸리지 않을 연구자는 별로 없을 것이다! 일반적으로 연구과제계획서는 요약본을 제외하면 일반에게 공개되지 않으며, 이를 조사하지 않으면 과제계획서의 내용과 해당 과제를 사사한 논문이 정말 연관성이 있는지 일반인 수준에서는 판명하기 쉽지 않다. 

너무 급하게 쓴 글이라 앞으로도 계속 수정이 가해질 것 같다.

2019년 8월 23일 금요일

2019 CJ R&D Global Conference "생명공학 기술로 만드는 우리의 미래"

2019년 8월 22일(어제), 작년에 이어서 CJ 블로썸 파크에서 열렸던 2019 CJ R&D Global Conference(프로그램연사)에 다녀왔다. 파견 근무지에서 걸어서 갈 수 있는 위치라서 별 부담 없이 다녀올 수 있었다.





오랜만에 만난 신수안 미래기술연구소장 겸 부사장님이 세션 I 좌장을 맡았다. 이분에게 암실에서 흑백 사진 인화를 배웠던 기억이 난다.

작년에 이어서 올해에도 microbiome에 대한 발표가 큰 비중을 차지하고 있어서 관련 업(학?)계에 있는 나로서는 관심을 갖지 않을 이유가 없다. 인간의 장내 미생물이 면역이나 대사에 관련하여 중요한 역할을 함은 잘 알려져 있는데, 신경정신과적 질환에도 연관이 있음을 시사하는 연구 결과가 최근 많이 발표되고 있다. Plenary lecture에서 첫번째로 발표(제목: The gut microbiome and neurological disorders)를 한 캘리포니아 공과대학(Caltech)의 Sarkis K. Mazmanian은 이러한 연구 분야의 선두 주자라 할 수 있다. 강연에서는 장내 미생물이 만드는 아밀로이드 단백질에 신경세포로 들어가서 파킨슨병을 유발하는 인자로 작용할 수 있음을 시사하는 결과를 보여주었다. Mazmanian 연구실의 In the News 웹사이트를 방문하면 언론에 소개된 관련 연구 성과가 나온다. 2017년 Immunity에 실렸던 리뷰 논문을 읽어봄직하다.

http://dx.doi.org/10.1016/j.immuni.2017.05.011

Plenary lecture의 두번째 연사는 합성생물학 분야의 대가로 잘 알려진 UC 버클리의 Jay Keasling은 'Engineering biology for sustainable development'라는 제목으로 미생물의 게놈 엔지니어링과 인류를 위협하는 문제(건강, 에너지, 자원 고갈 등)를 극복해 나가는 사례를 발표하였다. 말라리아 치료제로 잘 알려진 artemisinin, 맥주원료 홉을 대신할 GM 미생물, 바이오플라스틱 등의 주제는 물론 이를 어떻게 사업화로 이어가고 있는지를 소개하였다. 맥주 이야기에 관심이 있다면 Brewing hoppy beer without the hops를 참조하라.

신생학문인 미생물 내분비학(microbial endocrinology)란 무엇인가? 아이오와주립대 수의학과 교수인 Mark Lyte가 주창한 이 용어는 미생물이 숙주에 영향을 미칠 수 있는 신경전달물질을 인식하거나 만드는 능력을 연구하는 분야를 말한다(Microbial endrocrinology and the microbiota-gut-brain axis, PubMed). 인간의 체내에서 작용하는 신경전달물질은 사실 자연계에도 널리 존재하며, 따라서 진화적인 관점에서 이를 다루어야 한다는 것이다("Understanding the role of microbial endocrinology in the microbiome"). 또한 항생제가 아닌 약물이 미생물에 어떤 영향을 미치는지에 대해서는 잘 알려져있지 않은데, EMBL의 구조 및 바이오인포매틱스 그룹장인 Kiran Raosaheb Patil은 잘 설계된 실험을 통해서 대규모의 drug-bacteria interaction을 연구한 최신 결과를 발표하였다("How drugs impact our bugs"). 비록 인도식 영어 억양이라서 알아듣기가 매우 어려웠다는 것이 아쉬움으로 남는다. 이럴 거라면 나도 동시통역기를 대여하여 들어볼 것을.

학술행사와 더불어 석박사 학위 취득자(예정자 포함)를 대상으로 하는 채용/직무 상담도 동시에 진행되었다. 사전에 온라인으로 신청한 지원자들이 이날 오후 개별적으로 미팅을 하여 당일 서류전형 결과를 확인하는 독특한 방식이었다. KRIBB에 재직하던 시절부터 알던 반가운 사람들을 이 자리에서 많이 만날 수 있었다. 개방형 연구혁신을 통해 외부 아이디어를 모집하여 지원하고(CJ제일제당 블로썸 아이디어랩 1기 개최, 뉴스 링크), 국외에서도 직접 인재를 찾기 위해 사장단이 LA까지 총출동하는 등(CJ 글로벌데이 개최, 뉴스 링크) 미래를 준비하기 위해 전사적으로 힘을 쏟는 모습이 인상깊었다. 문득 대덕연구단지에 있는 선후배·동료 연구자들이 생각이 난다. 아직도 우리는 더 많은 지원을 요구하는 목소리만 내는 수준으로 머물러 있는 것은 아닐까?

논문 심사 후 거절 의견을 보내면서

연구자로서 누구나 논문을 써서 좋은 학술지에 출판하기를 원하지만 리뷰어로서 논문 심사 부탁을 받는 것은 참 성가신 일이다. 분야에 잘 맞는다면 봉사를 한다는 의미에서 심사를 수락하는 것이 바람직하지만 말이다. 내가 힘겹게 작성한 논문이 게재 승인(보통 accept가 되었다고 표현한다)을 받았다는 것은 담당 편집인(editor)과 리뷰어가 뒤에서 숨은 수고를 했다는 뜻이 되니 내가 반대로 리뷰어의 입장이 되었을 때는 되도록이면 응하는 것이 옳을 것이다. 현재 대부분의 학술지가 따르는 동료 심사(peer review)가 항상 완벽한 것은 아니지만 말이다.

요즘 주로 메일함을 어지럽히는 것은 리뷰 요청보다는 듣도 보도 못한 출판사에서 논문을 금방 실어줄테니 원고를 보내달라는 메일이다. 돈벌이를 목적으로 하는 이런 수준 이하의 '약탈적' 출판사 혹은 학회의 실상에 대해서는 국내에서도 큰 문제가 되었던 WASET 학회 사태를 통해 이제 잘 알려진 상태이다. 이를 방지하기 위해 한국연구재단에서도 2018년 9월 약탈적 부실 학술지 및 학술대회 피해를 예방하기 위한 가이드를 배포하였다.

부실 학술지 및 학술대회 피해 예방 관련 해외자료 소개

이야기가 좀 다른 곳으로 흘렀다. 오늘 글을 쓰려는 것은 부실 저널이나 학회에 관한 것이 아니라 심사 의뢰를 받은 매우 부실한 국외 논문에 관한 것이다. 리뷰어는 자신이 심사한 논문의 내용에 대해서 기밀을 유지해야 하므로 저자나 논문 내용을 특정할 수 있는 민감한 사항을 제외하고 이 문제를 짚어보고자 한다.

심사 요청을 받은 논문은 어떤 미생물 균주 4건의 유전체 해독 및 분석에 관한 내용을 다루고 있었다. 영어를 모국어로 쓰지 않는 사람이 원고의 영어 수준에 대하여 왈가왈부한다는 것이 대단히 적절치 않음은 잘 알지만, 워드프로세서에서 기본적으로 제공하는 맞춤법 검사 기능도 전혀 작동시키지 않은 듯 철자 오류가 너무나 많았다. 요즘 출판되는 유전체 논문의 수준에도 한참 못미치는 분석 방법과 해석 방법도 문제였다.

하지만 정작 나의 뚜껑(?)을 열리게 한 것은 다른 곳에 있었다. 이 논문에서는 미생물 균주를 배양하여 유전체 해독을 한 것이 주된 내용의 하나였다. 균주를 어디에서 입수했는지에 대한 기본 정보조차 쓰지 않은 것은 일단 논외로 하자. 당연히 NCBI에 유전체 염기서열을 제출하여 받은 accession number도 원고에 기재가 되어 있었다. 그런데 구글을 검색해 보니 똑같은 유전체 데이터를 사용하여 만들어진 논문이 이미 2018년에 다른 저널에 출판되어 있었다. 그 논문을 보면 NCBI에서 genome data를 '입수'하여 분석을 한 것처럼 기술하였다. 균주 배양, DNA 분리, 라이브러리 제작, 시퀀싱 및 어셈블리는 마치 저자들과 관련이 없는 것처럼 보였다. 하지만 2018년 논문과 이번에 내가 심사한 논문의 저자는 교신 저자를 포함하여 총 세 명이 일치한다.

이건 정상이 아니다. 게다가 2018년에 논문에는 어떤 유전자군의 분석 결과를 실었는데, 이번 논문에는 그 유전자군의 한 서브셋을 가지고 또 비슷한 그림을 그려 놓았다. 내가 보기에 이는 내용상 자기 표절에 가깝다.

두 개의 논문이 별도의 논문으로 존재해야 할 타당한 이유를 도저히 느낄 수가 없었다. NCBI에 유전체 정보를 등록하여 accession number가 발급되었다고 하자. 그렇다고 해서 sequencing and annotation에 해당되는 논문이 반드시 시기적으로 먼저 나와야 한다는 법은 없다. 하지만 동일 연구자 그룹이 생산하여 등록한 데이터를 마치 공개된 유전체를 입수하여 분석만 한 것처럼 첫번째 논문을 내고, 일년이 지나서 유전체 시퀀싱을 주된 내용으로 하는 논문을 별도로 낸다는 것은 이해할 수가 없다. 더군다나 두 논문의 교신 저자도 같다. 만약 두 논문이 내용적으로 별도의 논문으로 출판되기에 충분히 독립적인 일이라 한다면(균주 세트는 동일하다 해도), 두번째 논문은 첫 논문을 참고문헌으로서 인용하는 것이 자연스럽다. 하지만 이번 논문에서 2018년의 논문을 인용하는 것은 심각한 자기 모순에 빠지는 결과를 낳는다.

왜 그런가? '우리는 이미 2018년 논문에서 이 세균 균주들의 유전체 해독을 했었다'라고 할 수는 없다. 왜냐하면 2018년 논문에서는 유전체 서열을 NCBI에서 입수해서 썼다고 했고, 유전체 해독은 이번 논문의 주된 결과 중 하나인 것으로 기술했기 때문이다. 그리고 2018년 논문을 누군가 본다면 '어라? 같은 유전자를 가지고 그때 이미 그림을 그렸었네?'하고 눈치를 챌 것이 뻔하다. 저자 역시 2018년 논문에 대해서는 이번 원고에서 전혀 언급하지 않았다. 이는 다분히 의도적인 것이라 생각된다.

문제의 2018년 논문 URL을 여기에 공개해버리고 싶은 열망이 부글부글 끓어오르지만, 리뷰어의 도의상 기밀은 지켜야 하므로 참기로 하였다. 단박에 reject의견을 날렸다. 한국의 학술단체에서 출판하는 논문이라 해서 우습게 알고 이런 수준 이하의 논문을 보낸단 말인가?

2019년 8월 20일 화요일

여름 쇼핑 - 손목시계를 하나 더 구입하다

약간의 여유 자금이 생겨서 카시오 에디피스(Edifice) 브랜드의 표준 크로노그래프 손목시계 EFR-S567D-2AV(2019년 신모델)를 구입하였다. 일본산 제품에 대한 불매 운동이 한창 벌어지고 있는 요즘 상황에 비추어 볼 때 적절치 않은 구매 행위라는 소리를 들어도 어쩔 수 없다.

이 시계는 커다란 초침이 없다. 보통 크로노그래프 시계는 큰 초침이 스톱워치용 초 단위를 나타내는데(평소에는 12시 방향에 멈추어 있음), 이 시계는 12시 방향의 서브다이얼의 바늘이 그것을 대신한다. 시계가 잘 가고 있는지를 확인하려면 9시 방향의 파랑색 작은 바늘을 보아야 한다.



아직까지 나에겐 파란 다이얼의 시계가 하나도 없었기에 이것을 골랐다. 아내에게 줄 팔찌형 시계는 타임메카에서 오늘 배송될 예정이다.

2014년까지만 해도 나는 결혼 예물 시계를 그야말로 '닳도록' 차고 다녔었다. 간간이 실용적인 전자시계를 코팅이 전부 벗겨질 정도로 차기도 했었다. 시계에 대한 관심이나 욕심은 전혀 없었고, 흠집이 나지 않게 아껴서 차야겠다는 생각도 갖고 있지 않았지만 중학생이 되면서부터 시계를 차던 버릇은 휴대폰이 보편화된 지금까지 없어지지 않았다.

2014년 당시 보유 시계. 2014년 7월 맨 왼쪽의 포체 손목시계를 시작으로 시계가 조금씩 늘어나게 되었다. 세번째 타이맥스 시계는 밴드를 분리하여 요리용 스톱워치가 되었다. 출처 링크.
오늘의 글에서 사진으로 보인 것 말고도 다섯 개의 시계가 더 있다. 그중에는 오토매틱 시계에 대한 관심 때문에 구입했던 저급의 중국산 시계도 하나 포함된다. 이런 시계를 샀었던 것을 밝히고 싶지 않은(그러나 블로그에 기록은 했었다), 지금 생각하면 이런 물건을 왜 샀나 싶을 정도로 한심한 제품이었다.

시계가 점점 많아지니 지금은 거의 차지 않는 예전 시계의 관리가 문제다. 소모된 배터리를 제때 교체하지 않으면 액이 흘러나와 무브먼트를 망치게 된다. 아예 배터리를 빠 놓아야 할지, 아니면 계속 새것으로 교체를 해야 될지 고민스럽다. 현재는 서툴게 시계줄을 조정하거나 교체하는 정도만 하고 있는데, 뒷뚜껑을 열고 배터리를 직접 교체하는 수준까지 직접 해 볼 것인가?

고만고만한 시계를 사 모으지 말고 아예 한 방에 제대로 된 시계를 장만하는 것이 정석이라는 말도 흔히 듣게 된다. 나의 선택은? 모른다.

2019년 8월 19일 월요일

잘 쓴 글씨로 좋은 평가를 받으면 특혜인가?

바꾸어 말하자면 글씨를 못쓴다고 불이익을 받으면 편견이고 차별인가? 오늘 경향신문 인터넷판에 실린 기사를 소개해 본다.

글씨마저도 스펙 시대...'지렁이체 바꿔야 산다'

이 사진의 저작권은 누구에게 있는지 나는 모른다. 오늘(2019년 8월 19일) 경향신문에 입력된 기사(위의 링크 참조)에 딸린 이 사진에는 출처에 대한 아무런 정보가 없다. 놀랍게도 같은 신문 2005년에 11월 10일에 실린 기사 '[피플] 악필, 너는 내 운명인가?'에도 같은 사진이 쓰였었다. 보고서 표지의 제출일은 2005년 11월이다. 이것이 실제 과제물로 제출한 보고서를 촬영한 사진인지(허락은 받았을까) 혹은 기사의 이해를 위해 연출한 것인지를 나도 모른다. 만약 실제 존재하는 보고서를 촬영한 것이라면, 보고서를 쓴 사람에게 어떤 허락을 받아야 하나? 얼굴을 찍은 것은 아니니 초상권은 아니고, 그렇다면 저작권인가? 그것도 아닐지도 모른다. 물론 이름(성은 살짝 가렸지만)과 학번이 노출되었으므로 개인정보를 무단으로 공개한 것일 수도 있겠다. 어쩌면 기자는 이런 보고서 표지를 그냥 찍어서 기사에 곁들이기 방식으로 사용한다 해도 법적 책임은 없다는 것을 이미 알고서 사용했는지도 모른다. 이러한 상황이 꽤 많이 있다는 글을 본 적이 있다.
기사의 내용만을 보면, 시험 답안을 악필로 써서 점수가 깎인 법학전문대학원 학생이 글씨 교정학원에 등록하면서 이렇게까지 해야 하는지 부당함을 토로하는 것으로 시작한다. 가뜩이나 취업도 안되고 '스펙'을 쌓느라 시간과 금전적 부담을 져야 하는 요즘 사람들에게 글씨까지도 예쁘게 잘 쓰라고 은연중에 강요하는 사회가 되었음을 비판하는 의도로 쓰여진 기사이다.

만약 옷 매무새나 목소리로 사람을 평가한다면 그건 틀림없이 차별이라고 비난받아 마땅하다. 그러나 글씨라면? 요즘은 책장을 넘겨가며 정보를 습득하는 일도 과거에 비해서는 월등히 줄어들었고, 손으로 글씨를 쓰는 일도 마찬가지로 줄었다. 쉽게 말해서 계약서나 카드 결제기에 서명을 하는 정도 외에는 글씨를 전혀 쓰지 않아도 일상 생활에 불편함이 거의 없는 시대에 잘 쓴 답안에 더 높은 점수를 부여하고, 심지어 입사 지원 서류 중 하나로 자필 자기 소개서를 쓰게 하는 것은 부당하다고 주장할 수도 있겠다. 사실 입사 시험을 보는 그 자리에서 자필 서류를 쓰게 하지 않으면 얼마든지 대필도 가능한 세상이다. 글씨를 얼마나 잘 쓰는지의 여부로 편견을 가지면 안되니 앞으로는 평가 등을 위해서 절대 손으로 쓴 글씨를 내서는 안되게 해야 한다고 약간 급진적인 주장을 할 수도 있을 것이다.

하지만 내 생각은 좀 다르다. 글씨는 일단 정보의 전달이 주된 목적이다. 정보 전달이 심각하게 어려울 정도의 필체라면 고쳐야 한다. 이는 취업때에 임박해서 학원을 찾아다니면서 해결할 것이 아니라, 초등학교 및 중고등학교 때 어느 정도는 훈련이 되었어야 한다는 이야기이다.

각종 과제나 답안지 등을 손글씨가 아니라 손글씨로 인쇄하여 냄으로써 손글씨를 못쓰는 사람에 대한 차별을 없애고 배려하는 효과가 있다면 워드 혹은 파워포인트에 온갖 현란한 장식을 넣어서 현혹함으로써 나타나는 부작용도 분명히 존재한다. 손글씨 학원 못지 않게 파워포인트를 '그리는' 기술을 익히는 것도 경제적으로 부담이 되는 행위니까 말이다. 그럴 것이라면 손가락에 굳은살이 박히도록 지나치게 많은 분량을 요구하지 않는 수준에서 정성들여 손으로 쓴 과제나 답안지를 제출하도록 하는 것이 더욱 심플하다.

만약 사법시험 2차시험 답안을 컴퓨터로 쓴다면 어떨까? 이러한 요구는 이미 오래 전부터 있었다고 한다(2002년 기사 링크). 그러나 당시의 기준으로는 외국에서도 이러한 사례가 아직 없고, 아마 시험장에서 컴퓨터로 쳐서 답안을 입력하게 된다면 예상치 못한 부작용이 생길 것이다. 예를 들어 잘 작성된 답안이 흘러나와서 학원가를 돌아다닐 수도 있고, 전산화된 자료를 몰래 들고와서 시험장의 컴퓨터에 입력하려는 시도가 이어질 것이 뻔하다.

나는 식구들 중에서 가장 글씨를 못쓰는 사람이었다. 아니, 정확히 말하자면 글씨를 못쓴다고 지적을 받는 사람이었다. 그래서 글씨에 대해서는 늘 자신감이 없었다. 교회에서 학생회 활동을 하던 고등학생 시절, 행사 계획서를 손으로 작성하여 장소 섭외를 위하여 찾아간 곳의 책임자(나의 작은아버지)께서 하셨던 말씀이 아직도 기억이 난다.

"야, 너희는 타자기도 없니?"

교회의 공식 업무에서는 타자기를 쓰던 시절이었지만 학생회에서 만드는 보고서나 계획서는 모두 손으로 쓰던 시절이었다. 물론 나는 이 일로 좌절하지는 않았다. 오히려 나의 글씨가 개성이 있고 잘 쓴다고 칭찬을 하는 사람은 나의 아내였다.

잘 쓴 글씨를 타인에 대한 예의라고 생각하면 이는 평가의 기준이 되고 권력이 작용하는 대상이 되고 만다. 쉽게 말해서 글씨가 그게 뭐냐고 한 마디를 하면 요즘 널리 쓰이는 표현을 빌리자면 꼰대질을 하는 셈이다. 그러나 글씨의 기능성을 생각하면 효과적인 내용 전달을 위해서는 어느 수준의 필체는 되어 주어야 한다고 생각한다. 우리가 두려워할 것이 있다면 AI가 글씨체를 평가하는 시대가 아닐까?

Pan-genome analysis tool에서 산출한 strain-specific gene의 활용에 조심해야 하는 이유

여러 미생물 유전체를 모아서 pan-genome 분석을 하면 각 균주에만 특이적으로 존재하는 유전자 정보를 얻게 된다. 이는 그 균주의 존재 여부를 검출하는 특이적 마커로 유용하게 쓰일 수 있다. 몇 번의 프로젝트를 통해서 특정 균주에만 존재하는 특이적 염기서열(꼭 유전자 단위일 필요는 없지만)을 찾아서 이것이 정말 쓸만한 것인지를 점검하는 과정에서 이상한 현상을 종종 발견하게 되었다. 즉, 해당 단백질 서열을 다시 비교 대상에 쓰인 모든 유전체들에 대하여 blast로 점검하면 identity가 95%를 훨씬 넘는 match가 다른 유전체에서 발견되는 것이었다. 이는 내 상식으로는 이해할 수 없는 일이었다. 오직 LS-BSR만 이런 문제를 보이지 않았고, roary, orthoMCL, 그리고 최근 설치하여 활용 가능성을 알아보고 있는 panX 모두 그러하였다. 유전자 단위가 아니라 유전체 단위로 분석을 실시하는 panseq의 novel region finder 기능에서만 이러한 이상 현상이 발견되지 않았다.

Pairwise similarity를 클러스터링하는 알고리즘의 특성인가? 내 수준으로는 이 레벨에서 벌어지는 일들을 이해하기 어렵다. 단서를 찾기 위해 panX 웹사이트를 뒤적거리다가 눈에 뜨이는 항목을 하나 발견하였다.

panX advanced options: Resolve unclustered genes

유사도가 매우 높지만 클러스터를 이루지 못하는 유전자들을 해결하기 위한 옵션이다. panX는 클러스터를 구성하는 유전자들의 길이 분포를 스무스하게 만들기 위해 점검을 실시한다는 뜻으로 풀이된다. 즉 기본 동작 조건에서는 유사도가 높지만 길이에 큰 차이가 있는 유전자를 분리시키는 것으로 보인다.

blast 결과를 점검해 보았다. 균주 특이적 유전자로 분류된 것 중 다른 균주에 존재하는 것과 similarity가 매우 높게 나왔던 것은 유전자 길이에서 큰 차이가 있었다. 즉 match가 이루어진 유전자 쌍 중에서 어느 하나에게는 full length match이지만, 다른 쪽에게는 절반이거나 혹은 그 이하의 영역에 대해서만 match였었다. Roary 웹사이트에는 이런 예외적 현상에 대한 설명이 없었고, 나 역시 paralog를 분리하는 문제에만 관심을 갖고 있었다. 당연히 직면할 수 있는 문제임에도 불구하고 이를 미처 인지하지 못했다니 부끄럽기만 하다. blast score ration를 기반으로 클러스터를 만들지 말지를 결정하는 LS-BSR에서는 이런 문제가 나타나지 않음을 쉽게 이해할 수 있다.

온전한 유전자(A)가 sequencing error로 인하여 길이가 유사한 두 개의 CDS(C + D)로 예측되었다고 가정하자. 다른 genome에 존재하는 A의 homolog는 C와 D 모두에 대해서 높은 similarity를 보이겠지만, 길이 분포의 문제로 인하여 이를 하나의 클러스터로 모으지는 못한다. A는 또 다른 genome에 존재하는 유사한 길이의 A', A'', A''' 등과 클러스터를 형성할 수는 있으나 모든 비교대상 genome을 아우리는 core genome의 일원은 되지 못할 것이고, C와 D는 균주 특이적 유전자로 취급될 것이다. 만약 C나 D를 그 균주의 특이적 마커로 판단하여 PCR primer를 고른다면 당연히 원하는 결과를 얻는 길에서 멀어질 것이다.

panX 파라미터를 건드려서 이러한 짧은 유전자를 억지로 클러스터에 포함시키는 것은 바람직하지 못하다. 아니, 짧은 유전자가 반드시 클러스터에서 소외되리라는 것은 편견이다. 대부분이 짧은 형태이고 유난히 긴 것이 하나 있다면 그것이 클러스터에서 제외될 것이다. 균주 특이적 마커 염기서열을 찾는 것이 주된 목적이라면, 아예 유전체 서열을 기본으로 움직이는 panseq를 사용하거나 또는 기존의 도구를 통해서 얻어진 unique gene을 전체 유전체에 대하여 최종 검색을 하여 점검하는 것이 바람직할 것이다.

2019년 8월 15일 목요일

6LQ8 푸시풀 앰프의 출력 트랜스 교체

6J6 푸시풀 앰프의 덮개를 열고 66 코어 트랜스 두 개를 꺼내고야 말았다. 이영건 선생님, 죄송합니다...


오른쪽은 그동안 출력트랜스 대용으로 써 왔던 전원트랜스.
스피커처럼 즉각적으로 바꾸어 연결해 가면서 소리를 비교할 수 있는 부품이 아니니 교체를 통해서 얼마나 소리가 좋아졌는지를 냉정하게 판별하기가 어렵다. 만약 파형발생기와 오실로스코프가 있었다면 매우 객관적으로 음질을 비교 평가할 수 있었을 것이다. 하지만 귀가 느끼는 세계는 계측과는 또 다른 차원이다. 제대로 만들어진 진공관 앰프용 출력 트랜스이니 당연히 음질은 더 좋을 것이다. 코어의 재질, 샌드위치 감기, 코어의 크기 등.

교체를 한 상태에서 소리를 들어보았다. 더 나아졌을 것이라는 기대감이 더 크게 작용하고 있으니 왠지 더 좋은 소리가 나는 것 같다. 볼륨 조절기의 본체에 접지선을 연결하고 NFB를 연결하는 것으로 마무리를 하였다.




6J6 푸시풀 앰프는 일년 반 정도 사용하였는데 벌써 부품용으로 전락하였다니 아깝다는 생각이 든다. 출력이 매우 낮고 마이크로포닉 노이즈가 심하다는 고질적인 문제점이 있었다. 앞으로 부품용 및 연구용으로 충분히 쓰일 수 있으리라 믿는다.

앞으로는 케이스를 개선하는 연구를 더 해야 되겠다.

2019년 8월 17일 업데이트

상판(나무 도마) 아래에 나무젓가락을 붙여서 앞뒤 좌우로 미끄러지지 않게 하였다.

다음으로는 적당히 구멍을 뚫어서 상판과 플라스틱 상자 부분을 케이블타이로 붙들어 묶을 생각이다. 구멍을 뚫기 위하여 핀바이스를 주문해 놓았다. 나무 또는 플라스틱에 작은 직경의 구멍을 뚫으려고 전동 드릴을 들이대기는 너무 거추장스럽다.

며칠 동안 들어본 결과를 말하자면, 제대로 제작한 푸시풀 출력 트랜스로 교체를 했다는 기대감 때문인 것일까? 지금까지 내가 사용한 그 어떤 진공관 앰프보다 소리가 좋다는 느낌이 강력하게 든다. 혹시 플라시보 효과는 아닐까? 정류회로쪽의 발열이 심하고 - 캐패시터와 저항류를 너무 가깝게 붙여 놓았고, 저항도 와트 수가 큰 것을 사용하는 것이 나았을 것이다 - 외관이 허름하다는 것 말고는 문제점을 찾기가 어렵다.

2019년 8월 21일 업데이트

핀바이스로 구멍을 뚫어서 상판과 플라스틱 상자를 케이블타이로 연결하였다. 상판이 두꺼워서 그런지 핀바이스를 쓰는 것이 쉽지 않았다. 돌리는 과정에서 자꾸 드릴날 고정부분이 풀어진다. 중국산 저가 수공구라 그런 것인지, 혹은 공구를 용도에 맞지 않게 쓰는 것인지?


섀시를 완전히 새로 꾸미지 않는다면 현재 거의 완성된 상태라 볼 수도 있을 것이다. 그러나 세부적인 모습을 들여다본다면 아직 부족한 모습이 많다. 플라스틱 상자 내의 기판(정류회로 및 리플 필터)은 서포트만 달아 놓았을 뿐 고정이 되지 않은 상태이며, 전원트랜스 역시 고정을 하지 않았다. 워낙 무거운데다가 주변이 기판으로 꽉 막혀 있어서 움직이지 않을 뿐이다.

내 귀가 간사한 때문일까? 출력 트랜스를 교체한 이후로 제법 소리가 좋다고 느껴진다.

2019년 8월 11일 일요일

진공관 앰프용 출력 트랜스의 임피던스 알아내기

6J6 푸시풀 앰프가 작동 중인 모습. 전자액자에 보이는 것은 조반니 파올로 파니니의 로마 판테온 내부(1734).

이영건 선생님이 제작신 6J6 푸시풀 앰프를 파견 근무지 숙소로 가지고 왔다. 최근에 만든 6LQ8 푸시풀 앰프와 비교를 해 보고 싶었기 때문이었다. 내가 만든 앰프는 일반 전원트랜스를 출력트랜스 대신으로 사용한 것이라서 음질이 불리할지도 모른다는 생각을 늘 하고 있었다.

막상 비교 청취를 하니 6LQ8 PP 앰프가 음질이 나쁘다고 할 근거를 찾기 힘들었다. 출력은 당연히 6LQ8 앰프가 크다. 파형발생기와 오실로스코프가 있어야 왜곡이 일어나기 전의 정확한 출력이 몇 와트인지를 측정할 수 있다.

6J6 앰프에 쓰인 출력트랜스의 임피던스 비율은 얼마일까? 제작자에게는 죄송한 이야기지만, 이를 적출하여 다른 앰프에 쓸 수도 있지 않을까? UL탭은 없으며 코어 사이즈는 66 mm이다. 제작자에게 예전에 전화로 문의한 적은 있는데 정확히 기억이 나지 않는다.


출력트랜스는 커버 없이 코어가 노출된 상태이며 내부의 베이클라이트판에 케이블타이와 순간접착제로 고정되었다. 볼륨 조절기가 왜 이렇게 뻑뻑한가 했더니 모터가 달린 전동 가변저항이었다(이런 물건).

6J6은 오디오용 진공관이 아니라서 이를 이용한 앰프의 회로를 인터넷에서 구하기는 힘들다. 검색된 정보는 다음이 전부이다.

[1] 위상반전회로 https://mysite.du.edu/~etuttle/electron/elect33.htm


[2] 1.2W 6J6 하이브리드 앰프 https://ibb.co/B4hRSyv https://youtu.be/3k8jxa0s788 (동영상) 'Ra-a = 16K+16K'라 한 것은 무슨 의미인지를 모르겠다. 유튜브 링크에는 'The video OPT is incorrect the OPT is 20Ka-a , the circuit require 32Ka-a and the B+ voltage is 300V is higher then design voltage. This is the power transformer is for temporary testing use.'라 하였다. 내가 알고 있기에는 32K 트랜스포머의 중간에 탭을 내면 양단과 중간 사이의 임피던스는 절반이 아니라 1/2, 즉 4K가 되는데(임피던스비는 권선비의 제곱에 비례하므로)...




[3] 6J6 PP 앰프 http://diyaudioprojects.com/Forum/viewtopic.php?t=5598
[2]와 [3]에서는 B 전원을 위해 voltage multiplier를 사용하였다. 늘상 접해왔던 (2)배전압을 능가한다.

6J6 PP 구성의 경우 16K:8 출력트랜스를 썼다는 글은 간혹 보인다. 위에 소개한 것 중 [3]번이 그러하다. 미지의 출력트랜스가 있을 때, 임피던스 비율을 알아낼 방법은 없을까?  만약 트랜스 1차에 220V를 연결하여 2차 전압을 재면, 권선비를 알 수 있다. 이를 제곱하면 임피던스 비율이 나온다.

6J6 PP 앰프는 매우 단순한 구성이라서 negative feedback도 걸려있지 않다. 따라서 출력관을 소켓에서 빼면 출력트랜스의 1차와 2차는 전기적으로 완전히 분리된다. 이런 상태에서 220V를 1차에 연결한 뒤 2차 전압을 측정하여 보았다. 9.3V가 나온다. 이번에는 2차에 5W 시멘트 저항 두 개를 16.4옴으로 만들어 연결하여 다시 측정을 해 보았다. 이번에는 8.95~8.96V 정도가 걸렸고, 부하저항에서 소모되는 전력은 계산상으로는 4.98W 정도가 된다. 처음에는 2.2옴 저항 하나를 연결하였었는데 열이 너무 많이 나서 즉시 전원을 끊었다. 전압비는 곧 권선비이므로 24.6이 되고, 제곱을 하면 605.16이다. 이를 환산하면 4.81K:8이 된다. 대충 5K:8의 매우 흔히 쓰이는 출력트랜스가 된다.

출력트랜스 1차 양단에 220V를 공급하기 위해 만든 케이블. 한번 만들어 두면 쓸모가 많다. 잠시 착각을 하여 클립을 납땜한 다음에 절연 외피를 씌우느라 애를 먹었다. 납땜을 하기 전에 수축 튜브 등의 다른 자재를 미리 관통시켜 놓는 것을 잊는 수가 가끔 있다. 머리가 나쁘면 늘 손발이 고생이다.

내가 만든 6LQ8 앰프 PCB에 6J6 앰프의 출력트랜스를 조합하면 가장 좋은 음질이 나올까? 이는 해 보기 전에는 알 수 없다. 출력트랜스를 재활용하기 위해 6J6 앰프를 완전히 분해해 버린다? 그것 역시 쉽게 결정을 내리기 어려운 일이다.

위험한 실험?

하루가 지나서 생각을 해 보니 출력트랜스에 상용전원 220V를 직결한 것은 다소 위험한 실험이었다고 느껴진다. 출력트랜스의 센터탭에 가해지는 수백 볼트의 직류를 생각한다면 전압 자체는 유사하지만, 뽑아낼 수 있는 전류는 비교 불가하기 때문이다. 좀 더 안전한 실험을 위해서는 다른 트랜스포머를 하나 거쳐서 연결하는 것이 나았을 것이다. 꼭 1차에 220V를 연결할 필요도 없을 것이다.