RでPubMedの検索結果を機械学習

はじめに

本稿はRのパッケージでdeep learningができると聞いて、ネットで調べながら、パッケージを使う道筋をつけるまでの、忘備録です。サンプルにしたのは、「A薬」で検索した結果と「B薬」で検索した結果を、テキスト形式でA.txt, B.txtとしてPCに保存したうえで、一部を学習用サンプル、残りをテスト用サンプルにして、学習の効果(?)を測定しました。集計に入る前に、ダウンロードしたデータの中の、検索キーワードを削除しました。(←これをしないとさすがに検索キーワードそのものがそれぞれの集団にばっちり入ってしまうので分類の性能が評価できないのではないかと)

はっきり分類しやすいように、今回はAは抗癌薬、Bは免疫神経系疾患治療薬と治療対象の疾患の性質が違うものにしています。検索結果は、Medline形式でダウンロードします。このあたりの手順は、【Rで自然言語処理】を、ほぼそのまま利用しています。(「データ分析系男子」さんありがとうございます。)分類に使用したMXNetの周りのスクリプトは【RのMXNetでirisを分類】を、ほぼそのまま利用しています(「なんとなくなDeveloper」さんありがとうございます。)


{mxnet}パッケージのインストール

とりあえずこのパッケージのインストールです。インストール方法は、他の日本語のサイトの説明通りでは、なぜかうまくゆきません。一応以下の流れでインストールできました。他のパッケージは特に苦労することなくinstall.packages()でインストールできました。

# first add the repo
drat::addRepo(“dmlc”)
# either install just one or more given packages
install.packages(“xgboost”)

cran <- getOption(“repos”)
cran[“dmlc”] <- “https://s3-us-west-2.amazonaws.com/apache-mxnet/R/CRAN/”
options(repos = cran)
install.packages(“mxnet”)


MedLine検索と保管

検索キーワードは普通に入力して検索すればよいのですが、あまりたくさんの文献があっても取り回しが悪いので今回は検索対象を今年出版の文献としました。またアブストラクトで分類しますので、アブストラクトが入力されている英語の文献に絞って出力するようにしました。

保存に当たっては、send toからFile-Medline形式を選択しました。

Medline読み込み

setwd(“C:/Users/Oshima/Documents/2018/R deep learning/TXT/”)

## define function
medline <- function(file_name){
lines <- readLines(file_name)
medline_records <- list()
key <- 0
record <- 0
for(line in lines){
header <- sub(” {1,20}”, “”, substring(line, 1, 4))
value <- sub(“^.{6}”, “”, line)
if(header == “” & value == “”){
next
}
else if(header == “PMID”){
record = record + 1
medline_records[[record]] <- list()
medline_records[[record]][header] <- value
}
else if(header == “” & value != “”){
medline_records[[record]][key] <- paste(medline_records[[record]][key], value)
}
else{
key <- header
if(is.null(medline_records[[record]][key][[1]])){
medline_records[[record]][key] <- value
}
else {
medline_records[[record]][key] <- paste(medline_records[[record]][key], value, sep=”;”)
}
}
}
return(medline_records)
}

## read Medline
fileVec <- list.files(file.path(getwd()),
pattern=”.txt”,
full.names = T)
categoryVec <- list.files(file.path(getwd()),
pattern=”.txt”)
dataMed <- lapply(fileVec,medline)

## exstract Title, Abstract and CategoryVec
dataMedList <- lapply(seq(1,length(dataMed)),function(x){
res <- lapply(seq(1,length(dataMed[[x]])),function(y){
out <- data.frame(title=dataMed[[x]][[y]]$TI,
abst=dataMed[[x]][[y]]$AB,
category=categoryVec[x])
return(out)
# return(x)
})
return(do.call(rbind,res))
# return(y)
})

dataMedDF <- do.call(rbind,dataMedList)

データの前処理

dataMH <- sapply(dataMed,function(i){
sapply(i,function(x){
if(all(!(names(x) %in% “MH”))){
strMH <- c()
}else{
strMH <- strsplit(x$MH,”;”)
}
strMHgsub <- gsub(” “,”_”,strMH[[1]])
strMHpaste <- paste(strMHgsub,collapse = ” “)
return(strMHpaste)
})
})

トピック頻度のデータフレームを作成しました。ここでは、上述のサイトに倣ってk=20でやっています。

library(textmineR)
library(text2vec)
library(tm)
library(topicmodels)

# create vector of abstracts
allTexts <- sapply(dataMed,function(i){
sapply(i,function(x){
ti <- gsub(“\\[|\\]”,””,x$TI)
if(all(!(names(x) %in% “MH”))){
strMH <- c()
}else{
strMH <- strsplit(x$MH,”;”)
}
strMHgsub <- gsub(” “,”_”,strMH[[1]])
strMHpaste <- paste(strMHgsub,collapse = ” “)
paste(ti,x$AB,strMHpaste,collapse=” “)
})
})

allTexts <- unlist(allTexts)

# preprocess
sw <- c(“i”, “me”, “my”, “myself”, “we”, “our”, “ours”,
“ourselves”, “you”, “your”, “yours”, tm:::stopwords(“English”))
preText <- tolower(allTexts)
preText <- tm::removePunctuation(preText)
preText <- tm::removeWords(preText,sw)
preText <- tm::removeNumbers(preText)
preText <- tm::stemDocument(preText, language = “english”)

# tokenize(split into single words)
it <- itoken(preText,
preprocess_function = tolower,
tokenizer = word_tokenizer)
#, ids = abstID)

# delete stopwords and build vocablary
vocab <- create_vocabulary(it,
stopwords = sw)

# word vectorize
vectorizer <- vocab_vectorizer(vocab)

# create DTM
dtm <- create_dtm(it, vectorizer)
# Term frecency
TDF <- TermDocFreq(dtm)

# modeling by package “topicmodels”
model <- LDA(dtm, control=list(seed=37464847),k = 20, method = “Gibbs”)

termsDF <- get_terms(model,100)
topicProbability <- data.frame(model@gamma,dataMedDF$category)

今回は学習用サンプルを80%, 評価用サンプルを20%にして、分けました。

train_size <- 0.8
n <- nrow(topicProbability)
perm <- sample(n, size=round(n * train_size))

# data for training
train <- topicProbability[perm, ]

# data for test
test <- topicProbability[-perm, ]

# imput data for training
train.x <- data.matrix(train[1:20])

# label for training
train.y <- as.numeric(train$dataMedDF.category) -1

# imput data for test
test.x <- data.matrix(test[1:20])

# label for test
test.y <- as.numeric(test$dataMedDF.category) -1


以上データの前処理でした。

階層型ニューラルネットワーク

データの前処理が終わりましたので、ここからがいわゆる機械学習の処理になります。iris記事に倣って、本稿でも次のようにしています。

引数備考今回のパラメータ
hidden_node隠れ層のノード(ニューロン)数 デフォルトは15
out_node出力ノード数(分類数、今回はA薬とB薬の2)2
num.round繰り返し回数(デフォルトは10)100
array.batch.sizeバッチサイズ(デフォルトは128)10
learning.rate学習係数0.1
activation活性化係数(デフォルトは'tanh')'relu'

‘tanh’, ‘relu’とはなんぞや、というのは解らない。「フリーランスのプログラマ」さんによると、「結論から言うとReluを使おう」なのだそうです。

# deep learning

library(mxnet)
mx.set.seed(0)

# 学習
model <- mx.mlp(train.x, train.y,
hidden_node = 5,
out_node = 2,
num.round = 100,
learning.rate = 0.1,
array.batch.size = 10,
activation = ‘relu’,
array.layout = ‘rowmajor’,
eval.metric = mx.metric.accuracy)

# 評価
pred <- predict(model, test.x, array.layout = ‘rowmajor’)

# 評価用データの分類結果(0, 1)
pred.y <- max.col(t(pred)) -1

# 評価データの正解の割合を算出
acc <- sum(pred.y == test.y) / length(pred.y)

print(acc)

結果

次の通り97.1% (95%CI; 92.6 – 99.2) の割合で正解に分類できました。

ナイーブベイズ分類器

機械学習的な何か

はじめに

その昔、2001年~2007年にかけて、遺伝子発現解析をやっていた頃、SVM (support vector machine)やNeural Networkを使用していました。肝臓由来の細胞に対し肝臓関連の副作用が知られている医薬品と、そうでない医薬品を曝露して、曝露後の遺伝子発現のパターンを見て、医薬品の肝毒性をin vitroで予測する、実験モデルを組み立てようとしていました。あまり、基礎的な経験のない中であれこれ考えても打開策が見つからず、また今思えば、根本的なデザインに無理があったようでもあり、結局なかなかよい出力が得られなかった苦い経験でした。

今回は基礎体力をつける意味で、インターネット上ですでにうまくいっているようなデータやスクリプトを基に自分なりに試してみます。正解があるものをトレースするのは、良い練習になります。

ナイーブベイズ分類器

今回試したのは、「ナイーブベイズ分類器」というものです。なぜこれを試すかと言うと、良い資料を見つけたからです。その資料を基に、試してみたという記事もあるようです。ざっと見たところ、数式でクラクラするのを我慢すると、何をやっているのかおぼろげながら見えてきます。あるカテゴリで相対的に高い頻度で出現する単語を指標にモデルを構築することになるようです。

スクリプト

機能する仕組みは使いながら考えるとして、スクリプトは次のようになります。全くリンク先の資料通りでは本当に芸がなさすぎるので、ちょっとだけ変えてみました。サンプルとしては、森鴎外と夏目漱石の作品を見分けるという課題で、MeCabのサイトで配布されているもの、を学習用の文章として、あとは青空文庫から「草枕」「こころ」(以上漱石)「花子」「あそび」(以上鴎外)をテスト用文章として、用いました。なお、青空文庫の文章はルビがうるさいので、delruby.exeを用いて処理したものでテストしました。

ルビの処理の様子(MS-DOSのコマンドプロンプトから)

delruby asobi.txt > ogai_asobi.txt
delruby hanako.txt > ogai_hanako.txt
delruby kokoro.txt > soseki_kokoro.txt
delruby kusamakura.txt > soseki_kusamakura.txt

これらの出力ファイルとMeCabのサイトから入手したデータをまとめて、setwdで指定したディレクトリの下の/data/writers/の下に置いて、次を実行しました。

 

library(RMeCab)

# data is downloaded from
# shift JIS
# http://web.ias.tokushima-u.ac.jp/linguistik/RMeCab/data.zip
# UTF8
# http://web.ias.tokushima-u.ac.jp/linguistik/RMeCab/data.tar.gz

# indicate data folder
setwd(“C:/Users/Oshima/Documents/2018/R MeCab/”)

# convert text files to vector
d <- t(docMatrix2(“data/writers”))

myNaiveBayes <- function(x, y) {
lev <- levels(y) #1
# term frequency in each category
ctf <- sapply(lev, function(label) colSums(x[y == label,])) #2
# term probability in each category smoothed using Laplace smoothing
ctp <- t(t(ctf + 1) / (colSums(ctf) + nrow(ctf))) #3
# number of each class documents
nc <- table(y, dnn = NULL) #4
# class prior
cp <- nc / sum(nc) #5
structure(list(lev = lev, cp = cp, ctp = ctp), class = “myNaiveBayes”) #6
}

predict.myNaiveBayes <- function(model, x) {
prob <- apply(x, 1, function(x) colSums(log(model$ctp) * x)) #7
prob <- prob + log(as.numeric(model$cp)) #8
level <- apply(prob, 2, which.max) #9
model$lev[level] #10!!
}

train.index <- c(1:2, 5:9, 11)
y <- factor(sub(“^([a-z]*?)_.*”, “\\1”, rownames(d), perl = TRUE))
# y; c(“ogai”, “soseki”)

model <- myNaiveBayes(d[train.index,], y[train.index])
predict(model, d[-train.index,])

ファイルは名前順にソートされますので、テストサンプルは、ogai, ogai, soseki, sosekiの順に出力されれば正解です。

 

おわりに

とりあえず、正解が得られていますが、これは元のリンク先の方の功績でしょう。正確な方法で他の手法と比較して実行時間を測定した訳ではないので印象なのすが、この手法は学習がかなり速いです。いずれにしても、とりあえずこのスクリプトの使い方は理解できたぞ。

たまごぶらす 第3回コンサート

たまごぶらす 3rd コンサート

2018.7.26 (木) 19:00 – 新宿のグラムシュタインで行われました、たまごぶらすのコンサートを聴きにいきました。2部構成で曲目は次の通りです。

第1部

01 ウィリアム・テル序曲

(: Ouverture de Guillaume Tell, : William Tell Overture)は、1829ジョアキーノ・ロッシーニが作曲したオペラギヨーム・テル(ウィリアム・テル)』のための序曲

02 アヴェ・ヴェルム・コルプス

WA モーツァルト作曲 アヴェ・ヴェルム・コルプス K 618

(Ave verum corpus) は、カトリックで用いられる聖体賛美歌である。トリエント公会議で確立された対抗宗教改革の一環として典礼に取り入れられ、主に聖体祭ミサで用いられた[1]。現在では、他にウィリアム・バードフォーレ作曲によるものが有名(モーツァルトらのテキストには一部変更もみられる)。

03 メンバー紹介

次の「アメリカ組曲」が奏者にとって難曲という事で、メンバーの調性も兼ねて少しおしゃべり。

04 アメリカ組曲 (1, 2, 3)

エンリケ・クリスポ (Enrique Crespo) 作曲 組曲「アメリカーナ」第1番 (Suite Americana No.1 for Brass Quintet)

I. Ragtiime (ラグタイム)
II. Bossa Nova (ボサ・ノヴァ)
III.Vals Peruano (ペルーのワルツ)

05 アメリカ組曲 (4,5)

IV. Zamba Gaucha (ガウチャのサンバ)
V. Son do Mexico (メキシコのうた)

第2部 ミュージカル特集

06 Another Day of Sun

「La La Land」 より

07 The Phantom of the Opera

「オペラ座の怪人」より

08 FINDING NEVERLAND

「ネバーランド」より

09 Wicked

「オズの魔法使い」エピソード0=「ウィキッド」より

10 Mamma Mia ~ encore

「マンマ・ミーア」より ~ アンコール

https://www.instagram.com/p/Bm–N1zhiqQ/?utm_source=ig_share_sheet&igshid=e3gancw07cse

Starry night

星空を見上げて

PovRayを用いて星空を撮影しました。撮影と言ってもカメラのレンズを空に向けるのではなく、星のデータを元に星空をコンピューター上で再現したものです。今回はstarmap.incを用いて簡単に画を作成しました。

starmap.inc のダウンロード用リンク先です。公開は可能だが、コピーライトを主張しないようにと言うようなことが書かれていましたので、とりあえず、リンク先のみ。

<http://news.povray.org/povray.binaries.scene-files/attachment/%3C4a02be66%40news.povray.org%3E/starmap.inc.txt>

 

いよいよ、お写真の撮影です。スクリプトは次のようになります。

#declare LimMag = 6;
#declare fDec=15;
#declare fRA=75;

#macro StarMapStar(vPosition, fMag)
#if (fMag < LimMag)
#local vPos = vrotate(vPosition, <0, -fDec, -fRA>);
#local c = ((LimMag+1)-fMag)/(LimMag+1);
sphere
{
vPos * 10000, 32
texture{pigment{colour rgb<c, c ,c>}finish{ambient 1 diffuse 0}}
}
#end
#end

#include “starmap.inc”

camera {
spherical
location <0,0,0>
look_at <0,0,1>
angle 270
}

Sample size calculation for a classical case-control study

ケースコントロールスタディのサンプルサイズの見積もり

臨床試験だと、試験に参加する被験者をリクルートするのは骨が折れる仕事ですので、必要最低限の被験者で正確な結果を得たいという欲求は大きく、「サンプルサイズ」の正確な見積もりが求められます。ケースコントロールスタディをする場合も、最終的に元資料を確認したり、新たにデータを入手したりする手間は少ない方が良いので、精密な見積もりが出来た方がベターです。しかし、新たにデータを得ることを想定していないデータベース研究では、サンプルサイズを見積もる要求はどのあたりに発生するでしょうか?データベースをベンダーから購入したり、解析をCROに依頼する際に目的の結果にアプローチできるだけの情報を持っているかどうかを見積もる場合には有用かもしれません。まぁ、流行だということで偉い人からの号令で動いているような多くの人は、何らかの結論にアプローチしたいのではなく「アプローチしている姿勢を見せる」と言う、行動計画ありきで動いているみたいですので、当該ベンダーのデータには、リサーチで明らかにしたい結論に到達できるような、十分なデータが含まれないことが購入前あるいは解析の発注前に明らかになったとして、頭を切り替えるかそのまま突き進むかは目に見えていますが。

それはさておき、単純にケースおよびコントロールでそれぞれ、何人中何人が被疑薬に曝露されていて、そのオッズ比を求めるというようなデザインでのサンプルサイズの求め方がありますので、次の資料のデータをトレースしてみます。

Woodward M (2005). Epidemiology Study Design and Data Analysis. Chapman & Hall/CRC, New York, pp. 381 – 426.

(p. 412) A case-control study of the relationship between smoking and CHD is planned. A sample of men with newly diagnosed CHD will be compared for smoking status with a sample of controls. Assuming an equal number of cases and controls, how many study subject are required to detect an odds ratio of 2.0 with 0.90 power using a two-sided 0.05 test? Previous surveys have shown that around 0.30 of males without CHD are smoker.

事前の見積もりに必要なのは、odds ratio 2.0, power 0.90, two-sided 0.05 testという、研究者が設定するパラメータと、先行研究から得ておくべき背景の情報として「冠動脈疾患にかかっていない男性の30%がスモーカーだ」という、コントロール群の曝露頻度に相当する情報です。あと、コントロールを選ぶ際はマッチングは行わないで、ケースと1:1となる人数にするとしています。ここで設定しているオッズ比は、「オッズ比2.0以上だとリスクとして警告する価値がある」と研究者が思い込むような任意の数字で、基準があるわけではないです。これを、認識しているかどうかで、結果が出た際に(特に差がつかなかった時に)データの解釈の書き方が大きく変わります。

> epi.ccsize(OR = 2.0, p0 = 0.30, n = NA, power = 0.90, r = 1, rho = 0,
+ design = 1, sided.test = 2, conf.level = 0.95, method = “unmatched”,
+ fleiss = FALSE)
$n.total
[1] 376

$n.case
[1] 188

$n.control
[1] 188

答えは
A total of 376 men need to be sampled: 188 cases and 188 controlsだそうですので、一応、数値は正解です。

「冠動脈疾患にかかっていない男性の30%がスモーカーだ」という先行研究も、よくよく考えると書かれていることがあいまいです。冠動脈疾患にかかっていない男性が将来かからないとは言えないですし。禁煙に成功した人をどう扱っているのか情報もないです。ま、それもさておき、背景の喫煙男性が30%も世の中にいたおかげで、少ないサンプルで研究が成立しそうです。これが、世の中の男子の1%しか使用していない曝露(これが医薬品への曝露なら、世の中の1%の男性が使用しているような薬ならブロックバスターですが)曝露との関係を見ようとすると、次のようになります。

> epi.ccsize(OR = 2.0, p0 = 0.01, n = NA, power = 0.90, r = 1, rho = 0,
+ design = 1, sided.test = 2, conf.level = 0.95, method = “unmatched”,
+ fleiss = FALSE)
$n.total
[1] 6418

$n.case
[1] 3209

$n.control
[1] 3209

6418例の情報を収集する必要が出てきます。このくらいの数になると、どのようにデータを集めるにしても自前でデータを準備して集計するのは大変そうです。組織だって行動する必要がありそうです。さらに、背景の曝露を0.1%に下げると、次のように6万人超えのサンプルの収集が必要になります。

> epi.ccsize(OR = 2.0, p0 = 0.001, n = NA, power = 0.90, r = 1, rho = 0,
+ design = 1, sided.test = 2, conf.level = 0.95, method = “unmatched”,
+ fleiss = FALSE)
$n.total
[1] 63158

$n.case
[1] 31579

$n.control
[1] 31579

副作用を研究対象にしていると、このcaseの3万人超えの副作用が出ていないと、結論が出せないように見えます。つまり、副作用の例にあてはめますと、3万人以上の患者さんが副作用になるという、結構な大惨事になってからしかこの方法で結論が出せないという、悲惨な手法です。どこに間違いがあるのでしょうか。おそらくそれは、有名なレンツの研究では結果として上記の例よりかなり大きな数字になっているパラメータでしょう。「オッズ比が20~50になるくらいの本当の強いリスクかどうか」を検証したいという、リサーチクエスチョンを立てるのです。

もう一点できる事やるべき事は、背景での曝露頻度を上げるために、対照集団を絞り込むこともできそうです。結論部分で述べたい一般論との兼ね合いにもなりますが、多くの場合世の中一般の集団からサンプルを得る必要はなく、気になる医薬品が使用されるような特定の基礎疾患にかかっている人の中での曝露でp0を設定すれば、調査対象数を少なく見積もることもできそうです。

Don’t forget to load a library prior to the above-mentioned scrips.

library(epiR)

Gali proof of a specialty journal

今月は2件のガリプルーフのチェックを行いました。ないときは何か月もないのですが、集中する時は近いタイミングで発生します。2件のうち1件は非常に短い(語数が少ない)ので、確認は楽勝でしたが、もう1件は、自分自身が非専門領域の専門誌で、全体で3000語弱の英文のフルペーパーでしたので神経を使います。このジャーナルはaccept前のレビューも若干長めで時間がかかっていましたし、レビューワーのコメントもデータの解釈の方向や議論の主張の仕方など細かい指示が多かったように思います。一方、多くのジャーナルで指摘される「英語が読みにくい」「専門の英文校閲会社を利用しなさい」といった指摘はありませんでした。私が急に英作文が上手くなったはずはなく、その専門領域の先生方の特性を反映しているものではないかと思います。

今回イラついたのは、出版社が組版に際して手を加えてきたことでした。a や theを入れ替えたり、文法が間違ったりしているのを修正すると言うのは他の出版社でもあります。しかし、今回は1つのテーブルを2つに分割して、新たにテーブル番号を振ってきました。テーブルは本文で参照する際に紐付しているのですが、紐付が間違っていて、本文中で参照するテーブル番号が当初意図していたのとは別のテーブルを指しています。これを修正するのは神経を使います。そして、出来上がってみたら、参照する順に番号が1, 2, 5, 3, 4になって、途中で参照するTable 5が最後のページに来るといった仕上がりになります。間違って紐付するよりはましだけど、なんか不愉快な感じです。

安楽死

安楽死について

2018年6月はじめに、京都大学で開催されました米国内科学会日本支部年次総会の役員会で、黒川清先生が安楽死について語っておられました。これだけ高齢化が進むことが何十年も前から予測されながら各時代の政権が実質的な手を打たずに、不作為を続けてきてしまった、というご認識でいらっしゃるようで、声を上げておられるという事でした。安楽死と高齢化? これを結びつけたロジックが解りませんでしたが、年をとったら(健康であっても?)自分で死を選ぶオプションを想定しているのであれば、SFの世界の様な話です。何か見解があれば、ご自身のブログにコメントを寄せてほしい、と言う事でしたのでそのブログを見に行きました。

黒川先生のブログ

まず、ブログを見て圧倒されたのが文字数の多さです。一通りザーッと流し読みするにも小一時間。そして、このテーマを「医学生のお勉強」として取り上げておられることもびっくりしました。安楽死にまつわる周辺の様々なことについて議論されています。雑談の様に雑多な話題から周辺の情報もちゃんぽんの様に入っている。議論として積みあがるというよりは、周辺ばかり。そう、話題の「安楽死とは」どういうものを言うのか、定義していない。何について議論しているのか、共通の認識を確認しないまま進んでいるのでなにか落ち着かないのです。

なぜ定義にこだわるのでしょうか。それなしでは、何を議論してどこに落ち着こうとするのかが見えないからです。いろいろな定義があってしかるべきですが、少なくとも「自分たちが、今議論しているものはこういうものだ」というのを確認する必要はあります。

自分が死にたいと思って死を選ぶ、「安楽死」-「尊厳死」-「自殺」 何が違ってどこに境界線があるか、整理できてますか? 国内では「安楽死」は過去に裁判を通して司法が4要件(6要件)を示して整理してくれています。4要件を少し緩めた物が「尊厳死」ですが、海外では日本の「安楽死」の要件を緩めて「安楽死」の様に扱っている様でもあります。「尊厳死」と「自殺」は、一般の人が思い浮かべるようなイメージでは明確に分かれていると思いますが、性質としては非常に近くて線引きは難しいものです。そこに至る社会的な背景が違うだけのようにも思います。安楽死を選ぶ権利を許容するが、自殺は許容しない、といった具合に真逆な判断をするためには、その2者の間に明確な線を引くことが必要になります。

とりあえず、東海大学安楽死事件の判決文を張っておきます。4要件が書かれています。(つづく

魚雷観音

魚雷観音

2018年6月はじめに学会で京都に行きました。今回は学会前日の理事会から始まって、最終日最後のプログラムのビジネスミーティングまでいたので週末ずっと京都にいました。理事会は金曜日午後ということで、出席するために会社の方は有休を取りました。そして、少し早めに行って観光をしました。場所は嵐山付近を散策しました。立派なお寺を一つ観て、「これはかつて我が家の定番カレンダーだった、シオノギ卓上カレンダーか国鉄壁掛けで絶対に観たことがある」と思える景色を観てきました。その、普通の感じのやつはいいとして、そのカレンダー寺の付近で気になるオブジェを見つけました。

まず、このネーミングにひっかかりました。「魚雷観音」平和なイメージの観音様と戦争なイメージの魚雷、このミスマッチな組み合わせが、他のオブジェとは何か惹きつけるものを持っていました。

この魚雷は、インプットしたスクリュー音を追尾する仕組みでもなく、あらかじめプログラムされた航路を進む仕組みでもなく、人がマイクロプロセッサ代わりに搭載されていたそうです。

作戦に関わった多くの方が亡くなっていますので、その方々を慰める観音様ということだろうと思います。