2018년 4월 29일 일요일

독서 기록 - <인간을 위한 신>외 네 권

이번 주에는 문재인 대통령과 김정은 북한 국무위원장 간의 정상회담이라는 역사적인 대사건이 있었다. 남북 분단이 이대로 고착되는 것은 아닌지, 지금까지 수십 년 동안 살아오던 방식 그대로 앞으로도 살아가게 될 것이라는 타성에 젖어들 무렵 놀라운 일이 벌어진 것이다. 이렇게 세상은 변한다. 그 변화가 바람직한 것이고, 더 나은 세상이 앞으로 올 것이라는 희망이 있다는 것이 너무나 반갑다.

이번에는 철학 서적에 치중하여 독서를 하였다.


나는 태어나자마자 속기 시작했다

  • 오찬호 지음
  • "의심 많은 사람을 위한 생애 첫 번째 사회학"
...사회가 한 명의 힘으로 변화하지 않는다는 사실이다. 사회는 그 안을 살아가는 절대 다수의 대중들이 '비판적 시민'으로서의 권리를 주장하고, 누릴수록 개선된다. 이 상식을 한국 사회에서는 가르쳐주지 않고 오히려 '일단 순응하고 나중에 바꾸든지 하라!'면서 '탈'시민이 되기를 강요한다(13쪽).

철학 읽는 힘

  • 사이토 다카시 지음, 홍성민 옮김
  • "지적 교양을 위한 철학 안내서"
2500년의 서양 철학을 세 가지 산맥으로 명쾌하게 정리한 입문서.


세상을 바꾸는 언어

  • 양정철 지음(2018년 1월 6일 한겨레신문 기사)
  • "민주주의로 가는 말과 글의 힘"
문재인 대통령을 '기획'하고 만든 일등공신이지만 홀연히 권력의 곁을 떠나 외국에 머물며 '민주'의 홍보(즉 언어)를 위하여 쓴 책. 잘 알려진 말이지만 언어가 의식과 사고를 지배한다. 올바른 언어는 평등·배려·공존·독립 및 존중을 위해 필수적인 조건이다.

인간을 위한 신(The GOD Argument)

  • A. C. 그레일링 지음, 하윤숙 옮김
"휴머니즘은 인간의 삶에 관한 것이며 내세에 관한 믿음을 필요로 하지 않는다."

가벼움의 시대

  • 질 리포베츠키 지음, 이재형 옮김
  • "우리 시대를 지배하는 가벼운 것의 문명"
"우리 시대의 위험은 변덕스러운 가벼움이 아니라 가벼움의 비대함이다!"

2018년 4월 26일 목요일

[하루에 한 R] clustering 결과에서 Newick format의 트리 파일 추출하기

R에서 데이터프레임을 hclust() 함수로 처리하여 얻어진 클러스터링 결과물을 시각적으로 분석하는 일이 흔하다. 여기에서 만들어진 dendrogram을 Newick file로 추출하여 다른 응용프로그램에서 확인하려면 어떻게 하면 좋을까?

내가 구하는 대부분의 질문은 인터넷을 잘 검색만 해도 그 답이 나온다. 이번에는 StackOverflow에서 그 해답을 찾았다.

How to create a newick file form a cluster in R?

재료로 사용한 파일은 pyani가 생성한 ANIb_percentage_identity.tab이다. 이 파일은 헤더 라인의 첫 컬럼이 비어있으므로 row.names=1을 설정하면 아주 쉽게 데이터프레임으로 읽어들일 수 있다. R 코드는 아주 심플하다. as.phylo() 함수에 들어갈 값은 hclust class여야 한다.

> install.package("ape")
> library(ape)
> d = read.table("ANIb_percentage_identity.tab",sep="\t",header=T,row.names=1)
> fit = hclust(dist(as.matrix(d)),method="average")
> my_tree=as.phylo(fit)
> write.tree(phy=my_tree,file="test.newick")

참조했던 링크에서는 heatmap.2() 함수로 만든 자료를 연속적으로 변화시켜 가면서 newick 파일을 추출하는 방법도 소개되어 있는데 약간 번거롭다. Row와 column dendrogram 중 필요한 것을 골라서 변형시키면 된다. 이 방법 역시 ape 패키지를 로드해야 하며, heatmap.2() 함수를 쓰려면 gplots 패키지도 로드해야 한다.

> heat = heatmap.2(as.matrix(data))
> row.dendro = heat$rowDendrogram
> row.hcclust = as.hclust(row.dendro)
> row.phylo = as.phylo(row.hcclust)
> row.newick = write.tree(row.phylo)

마지막 명령은 좀 이상하다. 저런 방법으로 실행하면 R prompt에서 row.newick이라고 쳐서 화면에 newick 파일의 내용을 출력할 수는 있지만 이를 마우스로 긁어서 파일로 저장할 수는 없지 않은가. 다음과 같이 하는 것을 추천한다.

> write.tree(phy=row.phylo,file="test.newick")

2018년 4월 25일 수요일

도쿠위키(DokuWiki) 최신판 업그레이드 하려다 망한 사연

DokuWiki 최신판인 2018-04-22 "Greebo"가 나왔다고 하여 위키 업그레이드 플러그인을 사용하여 업그레이드를 하였더니 접속이 안되는 대참사가 발생하였다. 미생물 유전체 대상의 생명정보학 실무와 관련한 상당히 많은 자료를 정리해 두었는데 이를 어떻게 복구할 것인가? 이 위키사이트는 주로 개인적으로만 활용하고 있어서 접속이 되지 않는다고 해서 큰일이 날 것은 없지만 내가 불편하다는 것이 문제이다.

내가 사용하는 호스팅 업체에서는 일주일 단위의 백업을 제공하기 때문에 이것을 가져다가 어렵사리 복구를 하였다. 왜 문제가 생긴 것이었을까? 이번 버전의 DokuWiki로 업그레이드를 하려면 업그레이드 플러그인 자체를 먼저 업데이트하라는 것을 미처 눈치채지 못하였다.

현재 기준의 old stable 버전인 2017-02-19e 버전을 호스팅 사이트에 별도로 설치한 다음 최신의 업그레이드 플러그인을 설치한 뒤 업그레이드를 시도해 보았다.


PHP 버전을 5.6으로 올리지 않으면 DokuWiki를 업그레이드하지 못한다는 경고 메시지가 나왔다. 업그레이드 플러그인을 업데이트하지 않은 상황에서는 이런 경고가 전혀 나오지 않은 상태로 끝까지 진행이 되었으니 문제가 있음을 알 수가 없었다.

그렇다면 위키 업그레이드가 아예 불가능한가? 그건 아니다. 왜냐하면 호스팅 사이트의 제어판에서 PHP의 버전을 얼마든지 올릴 수 있기 때문이다. PHP를 버전 5.6으로 올린 뒤 시험용 DokuWiki를 업그레이드해 보았다. 성공적으로 업그레이드가 되어서 잘 작동함을 확인하였다. 이에 용기를 얻어서 먹통이 되었던 위키 사이트를 성공적으로 업그레이드하였다.

2018년 4월 23일 월요일

6N1 + 6P1 싱글 엔디드 진공관 앰프의 트랜스 울림 해결

난생 처음으로 전원 트랜스를 주문제작하여 진공관 앰프를 조립하였는데 전원 트랜스에서 웅~ 하는 떨림이 심하게 난다. 그 이유가 무엇일까? 인터넷을 뒤져보았다.

  1. 함침(impregnation) 불충분. 함침이란 트랜스 내부의 공기를 빼내고 절연 바니쉬 등으로 메우는 것이다.
  2. 용량 부족
  3. 전원에 DC가 유입될 경우
제이앨범(링크)에 계속 글을 올리면서 문제점을 점검해 나갔다. 첫번째 제안은 전원 용량이 부족한 것이 아니겠느냐는 지적이었다. 설계 용량은 230 V 120 mA, 6.3 V 1.6 A였다. 초크 코일 대용으로 넣은 220옴 5와트 시멘트 저항 양단의 전압 강하를 측정하여 저항으로 나누면 전류값이 나온다. 계산으로는 85 mA였다. 계획한 120 mA에 비하여 너무 낮은 것이 아닐까? 하지만 제이앨범에서는 괜찮은 수치라고 했다. 그렇다면 히터용 전원이 의심스럽다. 부하를 걸지 않으면 울림이 없는 것으로 보아서 분명히 작동 중에만 일어나는 현상이다.

만약 히터를 제2의 전원으로 점화하면 어떻게 될까? 마침 나에게는 LM1876 앰프에 사용하던 13 V - 0 V - 13 V 전원 트랜스가 하나 더 있다. 중간 탭과 13 V 탭을 출력관(6P2) 두 개의 히터에 연결하면 될 것 같았다. 히터는 직렬로 연결하면 각 히터에 대해서 6.5 V 정도의 전압이 잘 배분될 것 같았다.


부하를 건 상태에서 실제로 히터 양단 간의 전압을 측정하니 7 V가 넘는 전압이 걸렸다. 이대로 쓰기에는 전압이 너무 높다. 주변에 있는 저항을 적당히 조합하여 원하는 전압이 나오도록 조절해 보았다. 8.2 Ohm 5 W 저항 두 개를 병렬로 연결하여 합성저항 4.1 Ohm을 만든 뒤 중간에 삽입하니 6.2 V 정도로 아주 적당한 히터 전압이 나왔다. 저항의 발열도 그다지 크지 않았다. 계산을 통해 히터 회로에는 0.45 A의 전류가 흐름을 알았다. 6P1 specification에 나온 그대로이다.

테스트용 음악을 하루 종일 연주하는 지금의 모습이다. 소출력 앰프 하나에 전원 트랜스를 무려 두 개나 동원하다니! 앰프의 경량화는 이미 예전에 물건너 갔다. 이제 전원 트랜스 울림은 들리지 않는다. 음질은 라디오를 듣는 것과 약간 유사한 느낌인데, 이는 일반 전원 트랜스를 적당히 개조하여 아웃풋 트랜스로 사용했기 때문일 것이다. 그렇다 해도 음량은 꽤 높게 나와서 책상 앞의 SPL 87 dB 스피커를 충분히 울려준다. 사실 여기에 차마 옮기기 부끄러운 - 그리고 위험한 - 실수도 많이 있었다. 힘은 들었으나 좋은 경험이었다. 아마도 다음번 프로젝트는 R 코어를 이용한 출력 트랜스 제작이 아닐까 생각한다.


[하루에 한 R] reshape 패키지를 이용하여 쌍(pairwise) 자료를 매트릭스로 전환하기

dRep(논문, GitHub)은 수십, 혹은 그 이상의 미생물 유전체를 신속하게 비교하여 중복을 제거하는 도구이다. 메타게놈 데이터의 처리에도 유용하지만 다량의 유전체 자료를 비교하여 유사도(gANI) 기준으로 샘플을 묶는 데에도 편리하게 쓰일 수 있다. 그러나 pyani 처럼 매트릭스 형태의 자료를 제시하지 않는다. ANI 값들이 일단 매트릭스로 주어진다면 분석자의 입맛에 맞는 가공과 시각화가 가능하지 않겠는가?

결과 디렉토리 안에 활용 가능한 자료가 있을 것이라 생각하고 data_table 디렉토리를 열어보았다. 다음과 같은 네 개의 csv 파일이 존재한다.

Bdb.csv  Cdb.csv  Mdb.csv  Ndb.csv

하나씩 열어보면 무슨 자료를 담고 있는지 누구나 파악할 수 있다. 이 중에서 Ndb.csv가 모든 유전체를 1:1로 pairwise 비교를 하여 계산한 수치를 담은 파일이다. 파일의 형식은 다음과 같이 첫 줄에 나온다. 왜 query가 아니고 querry인가? 내가 잘못 타이핑한 것이 아니라 실제 결과 파일을 복사해서 여기에 가져다 놓았을 뿐이다.

alignment_coverage,ani,querry,reference,MASH_cluster

굵은 글씨로 표현된 컬럼만 뽑아내면 된다. 이는 awk를 적절히 사용하는 것으로 가능하다.

$ awk -F"," -v OFS="\t" '!/^alignment/{print $3, $4, $2}' Ndb.csv > matrix.txt

query와 reference 컬럼은 실제 dRep 계산에 사용한 파일 이름 그대로이다. 나의 경우는 다음과 같다.

Lactobacillus_rhamnosus_116_GCF_000801045.1.fna

너무 길어서 보기가 좋지 않다. Lacto..에서 GCF까지를 non-greedy하게 제거하고, 다음으로 .fna 확장자를 제거하는 것이 좋을 것이다. GCF_까지 없애면 나중에 R로 읽어들였을 때 숫자로 인식을 하여 약간 번거로워진다. non greedy하게 매치된 문자열을 없애려면 vim의 last line mode에서 다음과 같이 입력한다.

:1,$s/Lacto.\{-}_GCF//g
:1,$s/.fna//g

그 다음으로는 R에서 데이터프레임으로 읽어들여서 처리하면 된다. Ndb.csv는 두 샘플이 각각 query와 reference일 때의 gANI 값을 두 개의 라인으로 기록해 놓은 것이다. 따라서 매트릭스로 전환한 다음에는 대각선에 대하여 대칭이 아니다. 이는 t() 함수로 역행렬을 만든 것을 자기 자신에게 더한 뒤 둘로 나눔으로써 해결한다.

R 코드는 다음과 같다. reshape 패키지(링크)가 큰 도움이 되었으며, 힌트는 여기에서 얻었다. 이 패키지는 R 개발자로 널리 알려진 해들리 위캠의 작품이다.
> install.packages("reshape")
> library(reshape)
> d = read.table(file="matrix.txt",sep="\t",header=F)
> d2 = cast(d,V1~V2)
> rownames(d2) = d2[,1]
> d2 = d2[,-1]
> d3 = (d2 + t(d2))/2
# 확인용
> dim(d3)
> View(d3)

[업데이트]

위에서 보인 R 코드는 언제나 적용 가능한 것이 아니다. 자세한 것은 [하루에 한 R] pair 형태의 데이터를 matrix로 전환할 때 주의할 점을 참고하라.

[2021년 8월 26일 업데이트]

무려 3년이 지난 상황에 위 R code의 오류를 발견하였다. cast() 함수로 읽어들인 데이터는 매트릭스의 대각선을 기준으로 절반에 대한 것이다. 나머지 절반은 같은 값으로 채워야 한다. 따라서 d3 = (d2 + t(d2))/2가 아니라 d3 = (d2 + t(d2))가 되어야 한다. 으이그...

2018년 4월 21일 토요일

6N1 + 6P1 싱글 엔디드 진공관 앰프 조립

헤드폰 앰프를 제외하면 내가 소유한 세번째의 진공관 앰프이다. 주문제작한 전원트랜스가 어제 도착하는 바람에 조립이 늦어졌다. 엄밀히 말하자면 조립이라고 할 것도 없다. 나무판 위에 부품을 늘어놓고 배선을 한 것이 전부이기 때문이다. 번듯한 섀시에 꾸며 넣어야 조립이라고 할 수 있지 않을까.

토요일 오전, 많은 기대를 갖고서 작업을 진행하였다. 혹시 잘못 배선하여 불꽃이 튀지는 않을지 걱정하며 전원을 넣었다. 아무런 문제가 없었다. B+ 전압도 정상이고 진공관의 히터에도 불이 잘 들어왔다. 그러면 소스기를 연결할 차례이다.

어라? '두두두두...'하는 소리만 날뿐, 볼륨 폿을 아무리 올려도 음악이 들리지 않는다. 게다가 전원트랜스는 왜 이렇게 우는가. 이것은 트랜스 문제라고 치자. 다 만들어진 PCB에 배선만 했을 뿐인데 도대체 뭘 잘못했기에 이것밖에 안된단 말인가. 정말 오디오 자작은 내 실력으로는 안되는 일인가.

실망감을 가득 안은 상태로 아내와 함께 시내 나들이를 하였다. 중앙시장 원단·부자재 시장에서 필요한 물건을 사고 소나무집에서 오징어찌개 칼국수를 먹었다. 이 식당은 처음 방문이다. 별 다섯 개 만점에 네 개를 주겠다.


집에 돌아와서 다시 앰프를 들여다보았다. 전원 트랜스를 개조하여 출력 트랜스로 사용했다고 하여 이렇게까지 엉망일 수는 없는 노릇이다. 매우 단순한 오류가 아니었을까? 다시 배선을 살펴보니 입력 RCA 단자에서 그라운드쪽 선이 끊어진 것이 아닌가? 그러면 그렇지! 다시 튼튼하게 납땜을 마친 뒤 전원을 넣었다. 그러면 그렇지! 채널 당 3 W라는데 SPL 89 dB의 스피커를 아주 잘 울려준다. 소리도 만족스럽다.




못쓰는 PC용 파워 서플라이를 활용하여 전원 트랜스를 수납하고 원래 달려있던 파워 소켓과 전원 스위치를 활용하였다. 스피커 단자도 여기에 고정하였다. 전원 트랜스의 누설 자속을 차폐하는 효과가 있을 것으로 기대했는데 트랜스 자체의 떨림이 심하니 어떻게 해야 할지를 모르겠다. 배선 수준은 별로 아름답지 못하다.


CD 플레이어를 연결하여 음악을 듣다가 도중에 스피커 단자를 빼 보았다. 그러자 놀라운 일이 벌어졌다. 아주 작게 음악이 울려 나오는 것이 아닌가? 진공관이 울릴 것 같지는 않고, 그렇다면 출력 트랜스?

알리익스프레스에서 구입한 앰프 보드는 일단 만족스럽다. 일반 전원 트랜스(220V:9V)를 개조하여 출력 트랜스로 사용하는 실험 역시 성공적이었다. 문제는 전원 트랜스의 떨림이다. 이것은 트랜스를 바꾸는 것 말고는 해결 방법이 없는 것일까? 절반의 성공으로 만족할 수는 없다.

2018년 4월 20일 금요일

시공간 단축의 욕망

과도한 소비 문화는 현대 사회의 한 특징이다. 워낙 주변에 만연하여 있고 계속 퍼져나가기 때문에 마치 감염병과 유사하다. 이를 비판적으로 표현하는 신조어인 어플루엔자(affluenza = affluence + influenza)라는 말이 생길 정도니 말이다.

재활용 쓰레기 처리 문제로 전국이 한바탕 난리를 치렀다. 미봉책으로 겨우 땜질은 하였지만, 근본적인 대책이 필요하다. 쓰레기를 잘 분리하고 씻어서 재활용 업체가 제 값을 받고 팔 수 있게 만드는 것은 최선이 아니다. 일회용품의 배출 자체를 줄이려는 노력이 필요하다.

풍요롭지는 않았지만 그렇다고 해서 부족하지도 않았던 어린 시절을 돌이켜 보았다. 그때는 그 어느 누구도 물병을 들고 다니지 않았고, 커피잔을 들고 다니지 않았다. 여름에 길을 가다가 목이 마르면 노점에서 냉차를 사먹거나, 가게에서 유리병에 든 탄산음료를 마셨다. 거리를 돌아다니면서 무엇을 먹는 것은 흔한 일이 아니었다. 하지만 지금은 어떤가.

출처: 동아일보
이러한 산업 덕분에 많은 사람들이 생계를 유지한다지만, 넘쳐나는 쓰레기는 어떻게 하란 말인가. 이제는 설거지 일손을 줄이기 위해 매장에서 음료를 마시는 손님에게도 일회용 잔에 커피를 담아준다.

'되도록 이런 소비를 하지 말자'고 주장할 수는 있다. 기호성 음료수를 마시는 것은 선택의 문제니까 말이다.

오늘 아침, 오디오 DIY를 위한 부품을 택배로 받았다. 4월 2일에 주문한 것을 거의 3주나 걸려서 입수한 것이다. 제조사에서 평판이 별로 좋지 못한 택배회사에 물건을 맡긴 것도 이런 불편을 초래한 주요 원인이 되었다. 운송장 번호도 자동으로 알려오지 않았고, 언제 배달이 될 것이라는 연락도 없었다. 기다리다 못해 지역 사무실에 전화를 하여 물어보니 배송 기사 전화번호를 알려주었다. 하지만 기사는 하루 종일 전화를 받지 않았고, 사무실에서도 무슨 일인지 기사에게 연락이 안되니 다음날에는 꼭 배달이 되게 하겠다는 말만 전해 들었다.

배송 기사가 연락 두절 상태라니!

기대를 하지 않고 있었는데 다음날에 해당하는 오늘 아침, 결국 물건을 받았다. 익일 배달 원칙이라고는 하지만 그러고도 이틀이나 더 지나서 물건을 받게 된 것이다. 저녁이 다 된 지금 배송조회 사이트를 가 보았다. 아직도 배송완료로 전환되지 않았다.

지친 배송기사의 모습을 보면서 많은 생각을 하였다. 현대 사회는 대중이 원하는 제품이나 서비스를 만들고 우리는 이를 소비한다. 얼마 되지 않는 비용을 내고서 음식이나 물건이 금방 집앞으로 배달되는 것을 보면 한국의 물류산업의 수준이 대단하다는 착각이 들 정도이다. 그러나 배달할 물건이 열 배, 스무 배 많아진다고 해서 배송 기사들이 행복해질까? 더 많은 수익을 낼 수 있어서? 그렇지 않다는 것은 우리가 너무나 잘 알고 있다. 그렇다면 물류산업이 자동화와 뼈를 깎는 혁신을 통해서 영세성을 타파하고 수익을 올릴 수 있을까?

"이렇게 수요가 많은데 왜 수익을 못 내? 비용 절감하고 혁신하면 되잖아?"

이것은 너무나 소비자 위주의 관점이다. 이렇게 말하는 것과 무엇이 다른가?

"재활용 업자가 왜 쓰레기를 안 사갖고 가지? 다 돈이 되는데?"

게다가 너무나 많은 물건을 온라인으로 구입하게 되면서 엄청난 양의 포장 쓰레기가 발생한다. 과연 내가 택배 서비스 없이 취미생활을 할 수 있을까? 과거에는 없어도 상관이 없었고 있으면 고마왔던 서비스가 이제는 어떻게 되었나? 없으면 살기 어려울 지경으로 우리 생활 속에 깊숙이 파고 들고 말았다. 상황이 이러하니, '왜 일회용 컵에 음료를 마시는 걸까. 이건 선택할 수 있는 거잖아'라는 논리를 택배 서비스에도 들이댈 수 있다. '직접 가서 사면 되지, 왜 쓰레기(포장재)를 만드는 서비스를 이용한단 말인가?' 어느 것은 불가피하고 다른 어느 것은 선택할 수 있고... 그런 수준의 일이 아닌 것이다.

모든 것은 시공간 단축을 향한 인간의 욕망에서 온 것이라 생각한다. 더 많은 것을 갖고, 누리고 싶은 욕망이라고 보아도 좋다. 기다리지 않고도 만들어진 음식을 먹고 싶고, 시장에 직접 가지 않고도 물건을 사고 싶고, 제철이 아닌데도 신선한 과일을 먹고 싶고, 바닷가에 살지 않으면서도 해산물을 먹고 싶고, 가게가 문 열 시간을 기다리지 않고 새벽 세 시에도 물건을 사고 싶고... 기술과 산업이 이 욕망을 충족하고 돈을 벌게 해 준다. 그런데 그 부산물은 결코 긍정적이지 않다. 이를 뒷받침하는 저임금 노동자는 오늘 하루도 고단한 몸으로 온갖 손님을 상대하고, 길거리는 쓰레기로 넘쳐난다.

좀 더 나아질 방법은 없을까?

추가로 작성한 글

국내 물류산업이 영세하다는 뉴스를 하나 인용해 보자.

국내 물류산업 중소기업 비중 "99.9%" (카고뉴스 링크)
... 우리나라 물류산업의 가장 큰 문제점으로 기업 규모의 영세성을 들었다. 전체 물류산업에서 300인 미만의 중소기업이 차지하는 비중은 기업 수 기준 99.9%로 가장 높은데 평균 매출은 7,500만 원으로 대기업 5,310억 원에 비해 턱없이 낮은 수준이라는 설명이다.
이럴때 쓰는 말인지는 모르겠지만, 소위 '규모의 경제'를 위해서 영세한 업자는 전부 대기업에 자리를 내주어야 하는가? 농업이 그러했고, 동네 상점이 그러했다. 그러면 밀려난 사람들은 어떻게 하란 말인가?