KL2日目

昨日の夕飯は冠記で。

入るのにはちょっと勇気がいるローカル度。

1566559462 1566559597

ワンタンミードライはもはやワンタン麺というジャンルを超越している気がしないではないが、一緒に胃に収まれば そこがワンタンミーということなのだろう。

尚、麺の色ほど味が濃いわけではない。7RMくらいだったかな

1566559469 1566559529

朝起きたら、普通に粥を食べに漢記へ。ここもローカル度が高まっているが。

1566559619

鯉の刺し身のお粥と揚げパンで7RMちょいくらいだった。満足した。

1566559573 1566559403

この時期は、朝7時(時差が1時間あるので日本での8時)くらいから明るくなってきて、夜20時(日本で21時)くらいに完全に暗くなるので、調子が狂いますというか時差ボケ的なものがあって。普段5時に起きる私は現地時間の6時には暇で暇でしょうがなくなっていたのであった(暗いところは歩きたくないので、外出るかどうするかで悶々してた)。

そんな感じで暇すぎるんで、KLCCに行ってみることにした。

とりあえずおまけのツインタワー。ちょうど通勤ラッシュで混雑してたけど、キッチキチまで詰める感じじゃなくて 混んでたら次の電車を待つ感じだった。民度高いなとちょっと思った。日本は単一民族国家だからこそあそこまでパーソナルスペースを無視した鬼畜な所業がまかり通るのだろうなと思った。

1566559437 1566559576

そしてそこから広がる公園が良かった。ポケモン的にも散歩的にも。みんなランニングしたりウォーキングしてた。

熱帯の植物

1566559500 1566559565

個人的にはこの竹みたいに節のある木が気に入った。確か小さい種類のヤシだった気が。

1566559367 1566559516

花が咲いてたのはこれくらいだった

1566559455

nuセントラルに開店前に着いたのでコーヒータイム。fippersのサンダル物色したけどいまいちだったので買わずに地下のスーパーでシーズニングをアレヤコレヤと物色してたら1時間近く居たw

1566559356 1566559608

パサールセニに戻ってきて、南香飯店へ。営業時間が10:00-15:00くらいだから本日はこの時間帯にロックされた。

11時位に入店。人はまばら。チキン、ライス、中国茶(烏龍茶?)を注文

1566559425 1566559585

これは本当に美味しかった。感想はそれだけw

1566559628 1566559419

次に行こうと考えていたブルーモスクの入場できない時間が1200-1445だから1445くらいに着くようにセントラルマーケットでお土産買ったりして時間を潰した。ぶらぶらしてるときに見つけた壁画。

1566559484

モスクはこの記事を参考にバスで行ってみた。降りる場所がわからない(いちいち次のバス停のアナウンスなどない)のでgoogle mapで逐次調べていたけど、shah alamj bus stationだとちょっとずれたところを示すのでshah alamj city bus stationでピンを打たないと駄目なことにバスが通り過ぎる直前に気づいた。おばあさんがバスステーションでおろせって言っていたのでハッと気づいた。まじやばかった。

とりあえず外から撮ってみたけど、すごかった。

1566559361

ここが最初のフォトジェニックポイントだった。

1566559589

このあたりも良かった。

1566559543 1566559493

中もすごかった

1566559478 1566559391

一眼レフ持ってくれば良かったわ。

1566559537 1566559379

満足。帰りにラブ系のやつを発見した

1566559448

夜はSoong Kee Beef Noodlesで牛肉麵ドライを食べた。

1566559551 1566559522

湯で野菜が美味

1566559558

観光は本日で終わりだけど、観光用の日はもう少しあっても良かったかな

KL1日目

もともと2月のPycon APAC(PH)に行こうかなと思っていたところ仕事の関係で無理ってことで諦めたのだけど、 Pycon Myに夏休みをぶつけて行ってみることにした。

もちろん機内が寒いと噂のエアアジアでw。というより夜中に発なので時間を無駄にしなくていいかなと。寝ている間に着くんでしょ?みたいな軽い気持ち。エアアジアで預け入れなしでノートパソコン持っていくのは無理だったのでオプションで機内預け入れしたら結構高かったので、お土産を詰めることを決意した。

制限区域でやることがないのでビール。500円弱なので、機内で飲んでRMでお釣りをもらったほうが良かったかも。機内ではあまり寝られなかった。

1566463976 1566463952

入国審査が結構混雑していた上に、審査時間が他のレーンの3倍位かかる人の列に並んでしまった結果、入国審査に2時間以上かかって、流石にお腹が空いたので耐えきれず、空港のフードコードでチキンライス。14RM弱。美味しかった。

1566463938

両替とタッチアンドゴーカード(日本のSUICAみたいなやつ)をKLセントラルで調達するのだけど、電車でいってもなーってことでバスで移動することにした。KLIA Express TrainはKLIA2とKLセントラルを30分ちょいで移動できるのだけど55RMかかるそうです。一方でバスは同じ移動に1時間かかるけどバス代は12RMです。40RMで30分を買うかどうかということですな。ちなみにバスカウンターのお姉さんは50RM札を出したら「もう2RMだせや」って言ってきたので、これはアジア圏では通用するのかな?と思った。以前オーストラリアで端数が出ないようなことをしたらカウンターの人をものすごく混乱させたことがあるのでw

バスの内装は中華風だったが、寒かった、とにかく寒かった。エアアジアの機内よりも寒かったです。注意が必要なところ。

1566463979 1566463929

KLセントラルの隣のニューセントラルっていうショッピングセンターに入っている店で、両替とタッチアンドゴーカードの購入が終了したので、コーヒーでも飲んだ。アイスコーヒー頼んだらコーヒーの6RMにアイスとシェーク代ってことで4RMが上乗せされていて、アイスコーヒーってオプショナルな設定なんだなと思った。

1566463949

電車はこんな感じ。タッチアンドゴーカードはこのときだけ便利だと思った。この後早速トラブった。

1566463944

チェックイン前にホテルに着いたので、荷物を預けてお昼を食べに。 オールドチャイナカフェのナシレマ。これはたいへん美味しかった(15RM)

1566463932 1566463935

お昼を食べて時間があるので電車でピューッといけるバトゥ洞窟に行ってみることにした。 入り口はこんな感じ。

1566463958 1566463964

階段には猿がいて人の食べ物をかすめ取るらしいですが、私は盗難現場を目撃しませんでした。

1566463955 1566463973

洞窟の入口

1566463941 1566463970

突き当りまで行くと天井が空いていて、光が差し込んでいてキレイ。

1566463961 1566463966

さて、問題はBatu cave駅でタッチアンドゴーが全く反応しなくて困ったということだ。行きは駅員さんが、「お前はここから出ろや」って横道から出してくれたんだけど、帰りは全く反応しなくて窓口の行列に並んだ挙げ句、「カードキー動かないんだけど」って文句言ったら、いいから駅までのトークン買えやって言われて、「これどーすればいいんや?どこで直すの?」って聞いたら、「KLセントラル行けや」って投げやりに言われたのであった。

なんだよ、この対応は!チャージしている30RMどうすんだよー?って思ったけど、調べていくとなんかKRTだと反応しないことがあるらしいので、読み取り機側の問題なのかな?って気がしてきた。SuicaとかEasy cardとかはきちんと動作することが前提のインフラとして組まれてるけど、タッチアンドゴーは「とりあえずタッチしてゴーできたら便利だろ?でもピってならなかったら諦めてトークン買えや」ぐらいの位置づけのインフラなんでしょうね?ま、そうだったら駅員の態度も納得できるかな。

動かないかもしれないを前提に作られている社会ってのも面白いもんだなと思った。

戻ってきて、セントラルマーケットをぶらついてみたけど欲しいアイテムがなかった。 明日はちゃんとしたスーパーに行かねばならん。

1566463946

近所の神社で奉納DJがありました

8/15にあったのですが、忙しくてエントリをあげるのを忘れていた。

1566463319

大変に楽しかった。このDJは私が学生時代にメトロに入り浸るきっかけになったからね。 そして踊る側から踊らせる側に移ってとかいろいろ楽しい学生時代を送った。

Snorkeling at Ita Beach

Last weekend, I went snorkeling at the beach near my house for the first time this summer. One of the most famous diving and snorkeling spots is Ose-Zaki coast, which was already jammed with people as I had expected. I wanted to avoid heavy congestion, so I passed by Ose-Zaki coast and went to Ita coast, which is a smaller beach than Ose-Zaki.

The water and air temperatures were nice, but the clearness of the sea wasn't so nice.

It took about two hours on the way, but took about four hours the way back because there is only one road to the beach.

1565125372 1565125374

1565125376 1565125378

1565125381 1565125384

ワークフロー型プログラミングツールで能力ブーストは良いのか悪いのか?

プログラミングまたは機械学習の高速道路は学習の高速道路に関しての話ですが、ライブラリとかツールキットでブースト問題ってのもあります。

大体どの言語でもライブラリが充実していて、エコシステムを形成していて生産性が上がるんですが行き過ぎたプログラミング環境はどうなんかなーと思っていました。

つまりノンプログラマーのためのプログラミング環境(Pipeline Pilot/KNIME)とかRobot Process Automation(RPA)ってやつです。

ある程度の処理がコンポーネントという単位にまとめられていて、ユーザーはブロックを組み合わせる感覚でプログラミングができて、しかも処理が視覚的にわかりやすいというメリットがあります。さらに学習の初期コストが低いのでプログラミングの素養がなくてもすぐにある程度のことはできるようになります。

が、ちょっと複雑なことをしようとするととたんに複雑怪奇なワークフローになるのと、やりたいことをするためのコンポーネントがないと詰みます。

  • 前者は 結局コード書いてないだけでプログラミングはしているので、解決パターンを知らないと回り道することになる。デザインパターンを知らないプログラマーが陥るのと似た感じ
  • 後者はTensorflowのチュートリアル楽勝だけど実際自分の問題解こうとするとまったくわからんってことになるのと一緒

というわけで、ワークフローツールはどうなんかなーって思っていたのだけど、逆にノンプログラマーが利用して効率的に仕事をするのにはとてもよい選択肢だなと改めて思いました。

じゃぁなんワークフローツールをあんなに嫌っていたんだ?

よくよく考えてたら、ツールに技術がロックされることに嫌悪感を抱いていたのでした。Pipeline Pilot年間使用料がそれなりに大きいのと、すごく使いやすくてこれでしか仕事ができないケモインフォマティストが増えてしまったという製薬業界の語られない闇があります。維持費だけでも馬鹿にならないし、転職先がPP使ってないとキャリアが生きないというねw それってキャリアブルスキルなのか?っていう。一方でPPができたから良いとこに転職できたという事例もないことはないので、それがいいことなのか悪いかは一概にいえないけどね。

で、RPAツールはまさにこのサービスロックを狙っている気がします。そもそもクラス3ちらみせしてRPAのクラス1のツールに年間何百万も払わせるなんてあれなんじゃないのかな。

話がそれたけど、ノンプラグラマーなのにバイオインフォにアサインされた人間のみで構成されているうちのチームはとりあえずKNIMEブーストかけておけばいいだろうっってことでそのための学習道路の整備を急遽していますが、これはこれで色々楽しいですね。既存のKNIMEノード組み合わせてもできない処理は僕がNode作ってやればいいだけだからね。

尚、昨日始めてKNIMEデビューしました。どんだけワークフローツール嫌っていたんだ?って話w

プログラミングまたは機械学習の高速道路

梅田望夫さんの「ウェブ進化論」という名著かつ古典があります。既に13年以上も前に出版された本ですが未読であれば読んでおくことをおすすめします。

このなかで「学習の高速道路」という話がでてきます。元ネタは羽生先生の「ITとネットの進化によって将棋の世界に起きた最大の変化は、将棋が強くなるための高速道路が一気に敷かれたということです。でも高速道路を走りぬけた先では大渋滞が起きている」っていう話で、特に学習が必要なものに関してはほぼ全てにおいて当てはまっているのかなーと思います。それは今でも変わらないかなーと。

あとはドラッカーだかだれだったか覚えてないんですが、「マネジメントがマネジメントするものは人ではなく環境である」みたいなことを言っていて、「そうよねー」って感銘をうけたので、私は基本的に学習の高速道路を引くことにこだわりがあります。優秀な人間は超スピードで駆け抜けて行くべきだし、そのためのインフラはマネジメントが用意すべきというのが私の持論であって、いつの日か離陸してほしい。

やっぱ空飛ぶ車は夢よねw

イントラGithubはプログラミング学習の高速道路としてはうまく機能しているし、Mattermostも若い人の高速道路としてうまく動いているかなーと。大渋滞のなかで頭一つ抜けるのは本人の頑張りなので、成果を出して是非その分野で存在感を出していただければなぁと思っています。

やごみとリパブリュー

やごみで反省会と次回の日程決め。次回は9/21となりました

エンガワ

1561883380 1561883371

磯辺揚げとタコ唐揚げ

1561883390 1561883375

定番のアジ刺

1561883382

週末に会場を予約した帰りにリパブリューに寄った。

1561883386 1561883388

そして3Lのビールを飲んだ。

1561883377 1561883373

台北で買った魯肉飯ミックスが残っていたので豚ひき肉で魯肉飯を作ってみた。 これはなかなかいけた。

1561883384

つみき

久しぶりに出張に行ってきたました。

昼は御茶ノ水のエチオピアに行くつもりだったんだけど、混んでたので隣のしゃりんという店に変えた。 シャリンってなんやろか?と思ったらどうも六厘舎のセカンドブランドっぽい感じでした。

あんま並ばなかったのでこっちでもいいかもでも小くらいでちょうどいいかな。並は多かった

1561882911

帰りに神田のつみきに寄ったら、店が一杯だったので、外のテーブルで飲んだ。ここはコスパ良いよね。

1561882908 1561882913

このタンおろしが美味しい。

1561882918

次の日はリパブリューでデトックス

1561882916 1561882923

四神湯と魯肉飯

四神湯と魯肉飯を買ったので早速作ってみました。

四神湯は豚モツだけを用意すればいいので湯でモツを買ってきて白い脂肪を丁寧にとって臭みを抜きました。 右の液体は日本酒に胡椒を漬けたものですが、本場の謎液はもっとディープな奥深さがありましたね。

1561882009 1561882006

四神湯は美味しかったけど、本場には敵わんのでまた飲みに行かなければと思いました。

1561882001

魯肉飯は豚バラを細かく切って炒めてから、砂糖と醤油と水を入れて煮込みつつ、ミックススパイスを投入して煮込むんだけど、豚バラだとざっくりしていて歯ごたえが出るので本場感がなかった。

1561882011 1561881998

これはこれでうまいんだけど、豚バラの脂肪分多めの部位をミンチにして使うほうがよいんかな?

1561882003

Finding activity cliffs in ChEMBL

Activity cliffs are pairs of structurally similar compounds with large differences in activity, like inhibitory potency. I searched them in ChEMBL database with pychembldb.

I haven't maintained it for a long time but It works well even in Python3.7 :-)

My strategy for finding them is filtering assay data by whether it has confidence_score 9 (Direct single protein target assigned) and has enough data points(>=10 and <100) and then generating SMILES and Activity file from each of assay data for processing Matched Molecular Pairs Analysis (MMPs) by mmpdb

from pychembldb import *

for assay in chembldb.query(Assay).filter(Assay.confidence_score > 8).all():
    smiles_file = "{}.smi".format(assay.chembl_id)
    act_file = "{}.tsv".format(assay.chembl_id)
    act_list = [a for a in assay.activities if a.standard_value is not None and  and a.standard_units == "nM"]
    if len(act_list) > 9 and len(act_list) < 100::
        with open(smiles_file, "w") as sf:
            with open(act_file, "w") as af:
                af.write("ID\tVal\n")
                for activity in assay.activities:
                    if activity.standard_value is not None and \
                    activity.compound.molecule.structure is not None:
                        sf.write("{} {}\n".format(
                            activity.compound.molecule.structure.canonical_smiles,
                            activity.compound.molecule.chembl_id))
                        af.write("{}\t{}\n".format(
                            activity.compound.molecule.chembl_id,
                            activity.standard_value
                        ))

It took a few hours, but finally, I got around 55000 assay data.

I used mmpdb for generating MMP, and prepared a script for batch processing.

from glob import glob
import subprocess

def make_mmpdb(chembl_id):
    smiles_file = "{}.smi".format(chembl_id)
    act_file = "{}.tsv".format(chembl_id)
    fragments_file = "{}.fragments".format(chembl_id)
    sqlite_file = "{}.mmpdb".format(chembl_id)

    subprocess.run([
        "mmpdb",
        "fragment",
        smiles_file,
        "-o",
        fragments_file])

    subprocess.run([
        "mmpdb",
        "index",
        fragments_file,
        "-o",
        sqlite_file,
        "--properties",
        act_file])

if __name__ == "__main__":
    for fn in glob("*.smi"):
        chembl_id = fn.split(".")[0]
        make_mmpdb(chembl_id)

Finally, I extracted the pairs whose activity difference is more than 2 by pIC50.

import os
from sqlalchemy import *
from sqlalchemy.orm import create_session, relationship
from sqlalchemy.ext.declarative import declarative_base
from math import log10
from glob import glob

def search_ac(mmpdb_name):
    uri = 'sqlite:///{}'.format(mmpdb_name)

    Base = declarative_base()
    engine = create_engine(uri)
    metadata = MetaData(bind=engine)

    class Dataset(Base):
        __table__ = Table('dataset', metadata, autoload=True)

    class Compound(Base):
        __table__ = Table('compound', metadata, autoload=True)

    class PropertyName(Base):
        __table__ = Table('property_name', metadata, autoload=True)

    class CompoundProperty(Base):
        __table__ = Table('compound_property', metadata, autoload=True)
        compound = relationship('Compound', backref='compound_properties')
        property_name = relationship('PropertyName', backref='compound_properties')

    class RuleEnvironment(Base):
        __table__ = Table('rule_environment', metadata, autoload=True)

    class EnvironmentFingerprint(Base):
        __table__ = Table('environment_fingerprint', metadata, autoload=True)

    class ConstantSmiles(Base):
        __table__ = Table('constant_smiles', metadata, autoload=True)

    class Pair(Base):
        __table__ = Table('pair', metadata, autoload=True)
        constant_smiles = relationship('ConstantSmiles', backref='pair')
        rule_environment = relationship('RuleEnvironment', backref='pair')

    class RuleEnvironmentStatics(Base):
        __table__ = Table('rule_environment_statistics', metadata, autoload=True)

    sa = create_session(bind=engine)
    pIC50_dict = {}
    public_id = {}

    for cp in sa.query(CompoundProperty).filter_by(property_name_id=0).all():
        #print(cp.value)
        pIC50_dict[cp.compound_id] = 9.0 - log10(cp.value)
        public_id[cp.compound_id] = cp.compound.public_id

    pairs = []
    for pair in sa.query(Pair).all():
        if (pair.compound1_id, pair.compound2_id) not in pairs:
            pairs.append((pair.compound1_id, pair.compound2_id))
            diff = abs(pIC50_dict[pair.compound1_id] - pIC50_dict[pair.compound2_id])
            if diff >= 2.0:
                print("{}: ({}, {}) {}".format(
                    mmpdb_name.split(".")[0],
                    public_id[pair.compound1_id],
                    public_id[pair.compound2_id],
                    diff))

if __name__ == "__main__":
    for fn in glob("*.mmpdb"):
        search_ac(fn)

After this calculation I realized that I needed to eliminate cell based assays that caused AC noises.