【書評】機械学習を解釈する技術〜予測力と説明力を両立する実践テクニック
森下さんの「機械学習を解釈する技術〜予測力と説明力を両立する実践テクニック」を読んだので、まだ隅々までは読めていないが、感想を書きます。
Interpretable Machine Learningってとても話題で、最近だとHACARUSさんがInterpretable Machine Learningを翻訳して話題になっていたけどもこれともまた違った内容です。 hacarus.github.io どちらかというと、より実践的で、4つの機械学習の解釈手法をPythonで実装して、アルゴリズムを理解し分析から急所を捉えるといった構成になっていると感じました。
本書の概要
感想
解釈手法をマクロな解釈手法からミクロな解釈手法と使い分けで段階としては
- Permutation Feature Importance
- Partial Dependence
- Individual Conditional Expectation
という流れは非常にわかりやすかったです。またその解釈手法の使い方を安全か注意が必要かという点で区別しており、
- モデルのデバッグ
- モデルの振る舞いを解釈
- 因果関係の探索
という点で段階を分けて考えるというのは、実際の業務にも活きてくる内容と思いました。
書籍全体の流れは
- 線形回帰モデル
- Permutation Feature Importance
- Partial Dependence
- Individual Conditional Expectation
- SHapley Additive exPlanations
という流れで構成されており、私は特に後半の Individual Conditional ExpectationとSHapley Additive exPlanationsの章が秀逸と思いました。というのもこれらをここまで丁寧に説明している書籍が殆どないので、とても理解が深まりました(Permutation Feature Importance, Partial Dependenceに関しても同様です)
コードはこちらでサポートされています。
特に、交互作用はよく使い割に説明性が欠けることが多く、理論実装ともにわかりやすかったです。
SHapley Additive exPlanationsの説明はとりあえず僕が知る限り一番わかりやすかったので、これまで理解できなかった方も理解が進むのではないでしょうか?
私にとっては、このIndividual Conditional ExpectationとSHapley Additive exPlanationsの実装を試せたことが最大の収穫です。
あと何気に、付録のRの実装があったのがなにげに嬉しかった。 そして、付録Bで「線形回帰モデルが元来備えている解釈」と「機械学習の解釈手法を通した解釈」が整合的であることを示しているのはとてもおもしろかった。むしろこれで完全に納得したといった感じです。
終わりに
すべての章に通じて言えますが、 数学的な内容は最低限に抑え、高度な内容を平易な文章と簡易なコードでとてもわかり易く解説されていると思いました。
「解釈可能な機械学習」を題材に非常に勉強になる書籍でした。普段から意識はしているので、実践にすでに使っているものもあれば、これは使えるなという新しい発見もできました。このような技術はきちんと実践に活かせるようにならなくては意味がないので得た知識を実践に活かせるようになりたいものです。
参考図書
同時に出版されている齋藤さんと安井さんの「施策デザインのための機械学習入門〜データ分析技術のビジネス活用における正しい考え方」 こちらも書評を書いてあるが、すでに業務等の実践で機械学習をガンガン使っている人向けで特に「バイアス」「反実仮想」を考慮した機械学習をフレームワークを提唱しており、私としては「「推薦」の内容でバイアスも考慮した具体的な解説と実践的なコードがここままでわかりやすく書かれている書籍は他にはないと思います
安井さんの「効果検証入門」、反実仮想についてわかりやすく記述されているのでオススメ
【書評】施策デザインのための機械学習入門〜データ分析技術のビジネス活用における正しい考え方
齋藤さんと安井さんの「施策デザインのための機械学習入門〜データ分析技術のビジネス活用における正しい考え方」を読んだので、まだ隅々までは読めていないが、感想を書きます。
今回の書籍は初学者向けというよりは、すでに業務等の実践で機械学習をガンガン使っている人向け、もちろんこれからという人も事前に読むと実践の場面でとてもスキルが活きると思います。これまで、共著の安井さんは、「効果検証入門〜正しい比較のための因果推論/計量経済学の基礎 」という書籍を以前書かれていて、合わせて読むと効果的とも思いました。
基本的に機械学習をベースに「推薦」の内容でバイアスも考慮した具体的な解説と実践的なコードがここままでわかりやすく書かれている書籍は他にはないと思います。
- 本書の概要
- 1章 機械学習実践のためのフレームワーク
- 2章 機械学習実践のための基礎技術
- 3章 Explicit Feedbackを用いた推薦システム構築の実践
- 4章 Implicit Feedbackを用いた推薦システムの構築
- 5章 因果効果を考慮したランキングシステムの構築
本書の概要
感想
まずいきなり、「機械学習を使ってまで解くべき問題はあくまで意思決定の最適化問題であって、予測誤差の最小化問題を解くべきではありません」というのはそのとおりで、データサイエンティストが陥りがちな急所をよく突いているなと思いました。
1章 機械学習実践のためのフレームワーク
1章ではフレームワークについて言及されており
- KPI を設定する
- データの観測構造をモデル化する
- 解くべき問題を特定する
- 観測データのみを用いて問題を解く方法を考える
- 機械学習モデルを学習する
- 施策を導入する
このフレームワークを実践することで「機械学習モデルを学習する」の部分がとても活きていくるということを述べられております。
2章 機械学習実践のための基礎技術
2章以降は上記のフレームワーク則り、正確な予測と高性能な意思決定を導く流れが具体的に記述されていて、なるほどなと思わされました。また私が一番うれしかったのはOpen Bandit Piplineについての言及があったことです
以前発表があったときにちょっとやってみようかなぁと思ったのですが、当時私の理解が浅かったこともありうまく手をつけられなかったのですが、本書では詳しく解説されているし、サポートページでJupyter Notebookもあるので、あーこういうことねっていう使い方がすぐわかります。
Notebookや書籍にも書かれている通り、全データは11G程度あるので、まずはサンプルでやるのをおすすめします。
ここのことですね、data_path=Noneでいけます
全データはメッチャ重いが現実のデータを想定するとこのくらいでも不思議では無いので感覚を掴むには良いかと思います。 また、多くの方がこのようなlogデータを取り扱うと思うのでどのようなデータがアレばこのフレームワークに収められるのかということを理解するためにもぜひ実行しながら読みすすめることをおすすめします。
3章 Explicit Feedbackを用いた推薦システム構築の実践
ここからは思っきり推薦の話です。推薦には、☆ x 3のように「明示的」に評価がされているものとログデータにおけるコンバーションポイントのクリックのように「暗黙的」に評価がさえているものに分かれます。3章はExplicit Feedback(明示的の方)を扱っています。私は、MFを業務でガンガン使っておりますが、バイアスの考え方を含め今後の参考になることがたくさん記述されおりました。また、Yahoo! R3データは使ったことがなかったのですが、とても興味深い結果になっており実践のデータに適用してみたいなと思いました(MFのコードは巨大なデータを使うのでCythonで実装されたものを使っているのですが傾向スコアやナイーブ推定量を考慮した実装を書かなきゃいけないなぁ・・・なんておもったり)
4章 Implicit Feedbackを用いた推薦システムの構築
実践の場ではExplicit Feedbackはほぼ無いので、どちらかといえば私の興味はこちらの、 Implicit Feedbackの推薦システムです。こちもフレームワークに則り、ランキング学習に焦点を絞って語られており、Pytorchでの実装もとてもわかり易く結果もとてもおもしろい結果が見えています。
5章 因果効果を考慮したランキングシステムの構築
こちらは更に発展的な内容で、4章においては、「真の嗜好度合いの総量の最大化」を問題設定としていたが、 「推薦枠経由で観測されるコンバーション数や収益、コンテンツ視聴時間等のKPIの最大化」 「推薦経由ではなく、プラットフォーム全体で観測されるコンバーション数や収益、コンテンツ視聴時間等のKPIの最大化」 を問題設定としており、こちらは実際の実務に直結する内容で、速攻取り入れていきたいなというような内容でした。
あと、付録がとても充実していて、追加の解説や演習問題があるので理解が深まります。(演習問題の略解でもいいのでほしいなぁと思いました。合ってるのかどうか判断できないし)
終わりに
すべての章に通じて言えますが、具体的な図表が書かれているのでとても状況がわかりやすく、理解が促されます。
数学的な議論はとても多く数式は省略せずきちんと説明されているため理解が促されました。特に随所に登場する「バイアス」を考慮するための考え方はとてもわかり易く解説されていると思いました。
「反実仮想機械学習」を題材に非常に勉強になる書籍でした。今回はザーッと読んで手を動かした程度の理解ですので、きちんと実践に活かせるようにするには実戦投入していくのが一番かと思いました。
CounterFactual Machine Learning勉強会には、何度か参加させていただいたが、今後も是非開催していただきたいと思います。 cfml.connpass.com
参考図書
安井さんの「効果検証入門」、反実仮想についてわかりやすく記述されているのでオススメ
同時に出版されている森下さんの「機械学習を解釈する技術〜予測力と説明力を両立する実践テクニック」 こちらも書評を書いてあるが、現在実践で多く求められる説明可能 AI について解説している書籍
星野本「調査観察データの統計科学」 私はここから先に勉強していたので、比較的すっと入ってこられたので、こちらも一読すると良いかもです。
論文執筆TeX環境
経緯
社会人ドクター生活も、4ヶ月経って結構バタバタしていたため完全ブログストップ状態。
2021年4月に入ってすぐ、論文を書く流れになったもののTeXはよくわからんけどOverleafなら問題なく出来るよっていうことで、TeXを使い始めました。
結果的に便利で、作法もなれては来たが、差分管理とかぐちゃぐちゃになりがちで(GitHub連携はカネがかかるし)仕方なくTeX環境をローカルに作ってGitHubで管理する。必要に応じてというか最終段階に入る頃にOverleafを使うのがいいんじゃんっていうところに行き着きました。
これは@hyper_pigeonさんも言っていることであながち間違いじゃないんだなぁというか共通認識を持っている方がいるということで、さっと環境を準備するかとなったという経緯です。 hyper-pigeon.hatenablog.com
環境構築
TeXの知識吸収
TeXの知識が殆どないので奥村先生のLaTeX2ε美文書作成入門読めよっていう話。こちらを読めば、今抱えている問題も解決しそう。マダ読み中
どうやるか
- 絶対にローカルに環境をセットアップしたくないのでDocker一択
- まぁ他に同じようにやっている人いるでしょう
- というわけで、結論から言うと、 先程紹介した@hyper_pigeonさんのレポジトリ github.com とTwitterでepsが変換できないとぼやいていたら神の一言で、「テンプレートあるよ」ってな感じで@meta1127さんのレポジトリを参考にしました。(ご本人からもeps自体の解決にはならないかもだけど、参考までにっていうことで。)
よく使われていたTexLiveイメージ(若干TexLiveのバージョンは古い)https://t.co/sDVRku0RVS
— meta (@meta1127) August 6, 2021
GitHub ActionsでPDFビルドするテンプレート(Dockerイメージは上のもの)(自前)https://t.co/h3nvvsMK1w
結論
ここでつぶやいている通り、以下のようになりました。
フォーマット次第で
— くろたんく@激しく多忙 (@black_tank_top) 2021年8月7日
・Docker imageは大きく2つ使い分ける
・.latexmkrcでいい感じに設定する
・latexmkでpdf化まで持っていく
・dockerコマンド長いからMakefileでタスクっぽく実行する
・GitHub Actionsも設定してバーション管理
これで多分ほぼ解決なはず
型ができれば怖くない
Overleafみたいにどんなフォーマットでも平気だぜみたいな感じにはならんので、
Docker imageは大きく2つ使い分ける
- pman0214/docker-alpine-texlive-ja-epspdf
Paperist/docker-alpine-texlive-ja github.com github.com
主に、英語はpman0214/docker-alpine-texlive-ja-epspdfを日本語はPaperist/docker-alpine-texlive-jaを使う。どちらでも平気なものもある。
- 先程言及したepsをfigureやtemplate自体に使われている場合は前者を使うとできます。
.latexmkrcでいい感じに設定する
- これは変換コマンドがテンプレートと合っていないといい感じに変換できないということのようで、きちんとは理解できていないですが、エラーが出たら適宜対応するとなんとかなりそうということがわかりました。
latexmkでpdf化まで持っていく
- 複数のコマンドでゴニョゴニョやるのはむずい(めんどくさかった)ので latexmkコマンドで一発(ただし、.latexmkrcをつかって設定はコントロールする)
- dockerコマンド長いからMakefileでタスクっぽく実行する
- これは@hyper_pigeonさんのアイディアをそのまま使わせていただきました。後で示す私のレポジトリの場合はもっと簡略化して
make latexmk
で動くようにしました。
- これは@hyper_pigeonさんのアイディアをそのまま使わせていただきました。後で示す私のレポジトリの場合はもっと簡略化して
- GitHub Actionsも設定してバーション管理
- これはどちらでも良かったのですが、せっかくなので@meta1127さんが教えてくれたものを参考にさせていただきました。ただGitHub Actionsやtagなどは使ったことがほぼなかったのでこちらも勉強しました。
成果物
こちらに最終的に挙動を一応確認したものをpushしておきました。
解決しました。単純に.gitignoreに*.pdfとしていてpushされてないということでした。!/figure/*.pdf
などとすることでpushできて問題なくbuildできました。
ただ、これには若干問題があり、figureのpdfなどをfig/というディレクトリに入れた状態で実行するとローカルではビルドできるけどGitHub Actionsではコケるという状態を確認しています。
. ├── Definitions ├── Makefile ├── figure │ ├── fig1_XXX.pdf │ ├── fig2_YYY.pdf └── main.tex
イメージとしてはこんな状態のものです。解決法がわかる方がいたら教えてほしいです。
終わりに
この作業に2日位は費やしてしまったが、博士論文のフォーマットもその他のジャーナルのフォーマットも、とりあえず挙動が確認できたので、一旦、書くことに集中出来るという状態になりました。
環境系は疲れる。
GraphQL-based APIによるPDBのデータ取得(Ligand 情報編)
はじめに
はじめて(PDB)https://www.rcsb.org/というタンパク質のDBを触ったが、GUIではなくAPIを利用したデータ取得に少し手間取ったのでメモ。参考は以下
今回は主に、GraphQLによる取得について書く
GraphQL-based API
GraphQLは使ったことがなかったが、JSON形式でqueryを記述することで複雑なデーター構造の所望のデータを取得できるようで、今回の需要にあっていると感じたし、そもそもこっちで取得しろよっていう雰囲気を感じた。
https://data.rcsb.org/#data-api https://data.rcsb.org/migration-guide.html#legacy-fetch-api
経緯
今回は以下のような状況でLigand情報を取得しようと試みた。
目的はLigandの分子量、ALOGPなどの各種特性を計算したいが、 そのLigandの
- ID
- 名前
- SMILES
が不明である。
ただし、
- 論文上で複数のProtein+Ligand複合体のPDB IDがわかっている。
- そのLigandとされる構造式も書かれている。
PDB IDからのLigand情報の取得
ドキュメントを読む限り、
Entry:特定のPDB構造関するデータ。
- 4文字の英数字による識別子(PDB IDで例えば、1Q2W)
- タイトル、寄託者のリスト、登録日、公開日、実験の詳細
Entity : PDBに存在する化学的な分子の内容。大きく分けて3種類ある
- polymer_entity - タンパク質、DNA、RNA
- Branched_entity - 直鎖状または分岐状の炭水化物(糖類およびオリゴ糖とか)
- nonpolymer_entity - 低分子化学物質(酵素の補酵素、Ligand、ionとか)
Entity Instance : PDBに存在するEntityのコピーでEntityと同様3種類ある
- polymer_entity_instance
- branched_entity_instance
- nonpolymer_entity_instance
Assembly : 生物学的ユニットを形成する構造要素
例えば、以下のようなものが記述されている
Chemical Component : PDBエントリーに含まれる全ての残基や低分子のデータ
例えば、以下のようなものが記述されている
- 化学記述子(SMILES & InChI)
- 化学式
- 系統的な化学名
ドキュメントを頼りに色々やったが、クエリ上で、フィルターするやり方がいまいちわからない。今回で言えば、pdbx_chem_comp_descriptor.type == 'SMILES_CANONICAL' & pdbx_chem_comp_descriptor.program == 'OpenEye OEToolkits'
この様に絞りたいが、どの様にクエリを書けばいいのだろうか・・・それに、階層構造もスキーマを見てもよくわからん
しかし幸い、サンプルにLigandのSMILESを取得するQueryが書かれていたのでそちらを参考にPythonで取得できるようにした。
import requests query = ''' { entry(entry_id:"1AZ1") { nonpolymer_entities { rcsb_nonpolymer_entity_container_identifiers { entry_id } nonpolymer_comp { chem_comp { id type } pdbx_chem_comp_descriptor { descriptor type program } } } } } ''' url = "https://data.rcsb.org/graphql?query=" + query response = requests.get(url) json_data = response.json() json_data
とすると以下のような結果が返ってくる
{'data': {'entry': {'nonpolymer_entities': [{'nonpolymer_comp': {'chem_comp': {'id': 'NAP', 'type': 'non-polymer'}, 'pdbx_chem_comp_descriptor': [{'descriptor': 'NC(=O)c1ccc[n+](c1)[C@@H]2O[C@H](CO[P]([O-])(=O)O[P@@](O)(=O)OC[C@H]3O[C@H]([C@H](O[P](O)(O)=O)[C@@H]3O)n4cnc5c(N)ncnc45)[C@@H](O)[C@H]2O', 'program': 'CACTVS', 'type': 'SMILES_CANONICAL'}, {'descriptor': 'NC(=O)c1ccc[n+](c1)[CH]2O[CH](CO[P]([O-])(=O)O[P](O)(=O)OC[CH]3O[CH]([CH](O[P](O)(O)=O)[CH]3O)n4cnc5c(N)ncnc45)[CH](O)[CH]2O', 'program': 'CACTVS', 'type': 'SMILES'}, {'descriptor': 'c1cc(c[n+](c1)[C@H]2[C@@H]([C@@H]([C@H](O2)CO[P@@](=O)([O-])O[P@](=O)(O)OC[C@@H]3[C@H]([C@H]([C@@H](O3)n4cnc5c4ncnc5N)OP(=O)(O)O)O)O)O)C(=O)N', 'program': 'OpenEye OEToolkits', 'type': 'SMILES_CANONICAL'}, {'descriptor': 'c1cc(c[n+](c1)C2C(C(C(O2)COP(=O)([O-])OP(=O)(O)OCC3C(C(C(O3)n4cnc5c4ncnc5N)OP(=O)(O)O)O)O)O)C(=O)N', 'program': 'OpenEye OEToolkits', 'type': 'SMILES'}, {'descriptor': 'InChI=1S/C21H28N7O17P3/c22-17-12-19(25-7-24-17)28(8-26-12)21-16(44-46(33,34)35)14(30)11(43-21)6-41-48(38,39)45-47(36,37)40-5-10-13(29)15(31)20(42-10)27-3-1-2-9(4-27)18(23)32/h1-4,7-8,10-11,13-16,20-21,29-31H,5-6H2,(H7-,22,23,24,25,32,33,34,35,36,37,38,39)/t10-,11-,13-,14-,15-,16-,20-,21-/m1/s1', 'program': 'InChI', 'type': 'InChI'}, {'descriptor': 'XJLXINKUBYWONI-NNYOXOHSSA-N', 'program': 'InChI', 'type': 'InChIKey'}]}, 'rcsb_nonpolymer_entity_container_identifiers': {'entry_id': '1AZ1'}}, {'nonpolymer_comp': {'chem_comp': {'id': 'ALR', 'type': 'non-polymer'}, 'pdbx_chem_comp_descriptor': [{'descriptor': 'O=C2c1c3c(ccc1)cccc3C(=O)N2CC(=O)O', 'program': 'ACDLabs', 'type': 'SMILES'}, {'descriptor': 'OC(=O)CN1C(=O)c2cccc3cccc(C1=O)c23', 'program': 'CACTVS', 'type': 'SMILES_CANONICAL'}, {'descriptor': 'OC(=O)CN1C(=O)c2cccc3cccc(C1=O)c23', 'program': 'CACTVS', 'type': 'SMILES'}, {'descriptor': 'c1cc2cccc3c2c(c1)C(=O)N(C3=O)CC(=O)O', 'program': 'OpenEye OEToolkits', 'type': 'SMILES_CANONICAL'}, {'descriptor': 'c1cc2cccc3c2c(c1)C(=O)N(C3=O)CC(=O)O', 'program': 'OpenEye OEToolkits', 'type': 'SMILES'}, {'descriptor': 'InChI=1S/C14H9NO4/c16-11(17)7-15-13(18)9-5-1-3-8-4-2-6-10(12(8)9)14(15)19/h1-6H,7H2,(H,16,17)', 'program': 'InChI', 'type': 'InChI'}, {'descriptor': 'GCUCIFQCGJIRNT-UHFFFAOYSA-N', 'program': 'InChI', 'type': 'InChIKey'}]}, 'rcsb_nonpolymer_entity_container_identifiers': {'entry_id': '1AZ1'}}]}}}
対応するLigandは複数存在することもあるようだ。 今回はひとまずすべて取得し後に構造式から判断する。
以下のような関数を作成
- PDB IDを引数とする
- 特定のSMILESも絞れていないので取得後に、
pdbx_chem_comp_descriptor.type == 'SMILES_CANONICAL' & pdbx_chem_comp_descriptor.program == 'OpenEye OEToolkits'
となるデータのみ抽出する
import requests def entry_to_ligand(entry_id): ligand_list = [] query = ''' { entry(entry_id:"''' + entry_id + '''") { nonpolymer_entities { rcsb_nonpolymer_entity_container_identifiers { entry_id } nonpolymer_comp { chem_comp { id type } pdbx_chem_comp_descriptor { descriptor type program } } } } } ''' url = "https://data.rcsb.org/graphql?query=" + query response = requests.get(url) json_data = response.json() for i in json_data.get('data').get('entry').get('nonpolymer_entities'): entry_id = i.get('rcsb_nonpolymer_entity_container_identifiers') nonpolymer_comp = i.get('nonpolymer_comp') ligand_id = nonpolymer_comp.get('chem_comp').get('id') for data in nonpolymer_comp.get('pdbx_chem_comp_descriptor'): if (data.get('type') == "SMILES_CANONICAL") and (data.get('program') == "OpenEye OEToolkits"): smiles = [data.get('descriptor')] type = [data.get('type')] program = [data.get('program')] d = {'entry':entry_id, 'ligand_id':ligand_id, 'smiles':smiles, 'type': type, 'program': program} ligand_list.append(d) return ligand_list entry_to_ligand("1AZ1") # [{'entry': {'entry_id': '1AZ1'}, # 'ligand_id': 'NAP', # 'program': ['OpenEye OEToolkits'], # 'smiles': ['c1cc(c[n+](c1)[C@H]2[C@@H]([C@@H]([C@H](O2)CO[P@@](=O)([O-])O[P@](=O)(O)OC[C@@H]3[C@H]([C@H]([C@@H](O3)n4cnc5c4ncnc5N)OP(=O)(O)O)O)O)O)C(=O)N'], # 'type': ['SMILES_CANONICAL']}, # {'entry': {'entry_id': '1AZ1'}, # 'ligand_id': 'ALR', # 'program': ['OpenEye OEToolkits'], # 'smiles': ['c1cc2cccc3c2c(c1)C(=O)N(C3=O)CC(=O)O'], # 'type': ['SMILES_CANONICAL']} # ]
DataFrameで扱いたいなら適宜pandasで
pd.DataFrame(entry_to_ligand("1AZ1")) # entry_id ligand_id smiles type program # 1AZ1 NAP [c1cc(c[n+](c1)[C@H]2[C@@H]([C@@H]([C@H](O2)CO... [SMILES_CANONICAL] [OpenEye OEToolkits] # 1AZ1 ALR [c1cc2cccc3c2c(c1)C(=O)N(C3=O)CC(=O)O] [SMILES_CANONICAL] [OpenEye OEToolkits]
あとは適宜、ProteinとLigand PDB IDを適宜流し込んであげれば欲しいデータは取得できた。(ただし、NAP, CL, URE, PO4などのようなLigandを弾きたければ適宜弾く必要はある。)
df = pd.DataFrame() for entry_id in entry_ids: tmp = pd.DataFrame(entry_to_ligand(entry_id)) df = pd.concat([df, tmp]) df.reset_index().drop('index', axis=1) # entry_id ligand_id smiles type program # 1AZ1 NAP [c1cc(c[n+](c1)[C@H]2[C@@H]([C@@H]([C@H](O2)CO... [SMILES_CANONICAL] [OpenEye OEToolkits] # 1AZ1 ALR [c1cc2cccc3c2c(c1)C(=O)N(C3=O)CC(=O)O] [SMILES_CANONICAL] [OpenEye OEToolkits] # 1DDR CL [[Cl-]] [SMILES_CANONICAL] [OpenEye OEToolkits] # 1DDR MTX [CN(Cc1cnc2c(n1)c(nc(n2)N)N)c3ccc(cc3)C(=O)N[C... [SMILES_CANONICAL] [OpenEye OEToolkits] # 1DDR URE [C(=O)(N)N] [SMILES_CANONICAL] [OpenEye OEToolkits] # ... ... ... ... ... # 2BGD CL [[Cl-]] [SMILES_CANONICAL] [OpenEye OEToolkits] # 2BGD PO4 [[O-]P(=O)([O-])[O-]] [SMILES_CANONICAL] [OpenEye OEToolkits] # 2BGD NA [[Na+]] [SMILES_CANONICAL] [OpenEye OEToolkits] # 7STD CA [[Ca+2]] [SMILES_CANONICAL] [OpenEye OEToolkits] # 7STD CRP [CC[C@]1([C@H](C1(Cl)Cl)C)C(=O)N[C@H](C)c2ccc(... [SMILES_CANONICAL] [OpenEye OEToolkits]
終わりに
正直、Protein:Ligandの組が1:1対応と思っていたのだが、いわゆる低分子だけでなく、NAPとかイオンとかその他諸々も含むので複数もあり得るのかと思った。
仕方がないので一旦すべて取得して、不要なものはルールで除去し、差雌雄的にRDKitで構造式に直して、目視で論文に書かれている構造式と照らし合わせて、目的のLigandのSMILESを得ることができた。
GraphQLでの取得はDBの構造というかKeyの単語がスキーマをみてもよくわからなかったりするのでちょっと困る。ちょっとずつおぼえていくしかないか
社会人ドクター生活スタート
とてもバタバタしていて、ブログは放置していましたが、理由があって、
結論から言うと、博士後期課程の学生として、東京工業大学 情報理工学院 情報工学系の大上研究室に所属することになりました。
経緯
以前より、創薬分野に関わる研究がしたいと思っていて、現職は続けながら、社会人として学位取得を目指し頑張っていことと思い立ったのが2020年の8-9月
ケモインフォの博士課程行こうかと企みなう。社会人枠あるとこ探している。
— くろたんく@激しく多忙 (@black_tank_top) August 22, 2020
Twitter上でいろんな方が教えてくれて、色々検討しつつ、所属先の指導教員である大上先生が声をかけてくれたのがきっかけで、受け入れについて相談にのってもらいました。
上司と家族に説明し、去年からTOEIC受けたり、10年くらい前の修士論文を引っ張り出して取りまとめたり、今年の2月の入試に向けての準備や実際の入試はとても大変だったけれど、3月に無事に合格発表を受けてホッとしました。
本日付で、博士後期課程の学生として、東京工業大学 情報理工学院 情報工学系の大上研究室に所属することになりました。https://t.co/tydKlfKJmd
— くろたんく@激しく多忙 (@black_tank_top) 2021年3月31日
これまでの経験を活かし、コンピュータサイエンスの応用として、おもしろい生命科学の課題解決ができたらいいなと思っています。
今後
これまでの経験は
これらの経験も活かしつつ、 コンピュータサイエンスの応用として、おもしろい生命科学の課題解決ができたらいいなと思っています。
2020年を振り返る
- 簿記(2020-02)
- はてぶ(2020-06~)
- AtCoder (2020-05~)
- 書評 (2020-07~)
- 移住 (2020-07~)
- スタサプ・TOEIC(2020-09-10)
- 業績まとめ
- 終わりに
今年はコロナ情勢の中、いろんな事をやった一年だった。 結果的に、AtCoderにチャレンジしたのが大きかった。その他にも試験を何個か受けたり、本読んで感想書いたりして、まぁまぁ充実していた。
簿記(2020-02)
XBRLから財務分析を行う話があったのだがXBRLの取り扱い自体はできても、そもそも財務に関するドメイン知識が皆無だったので、基礎を学ぶためにまずは簿記の試験を1ヶ月程度かけて行った。無事合格。3級は基礎中の基礎でこれはこれで勉強になったが、いわゆる財務分析についても勉強していきたい。
はてぶ(2020-06~)
とりあえず、自分がやってることというのはだいたい忘れていくし、なにかの折に何者なのかもわかりやすいように、当時興味あったことをログとして残すことにした。
AtCoder (2020-05~)
時間もあったのと数学的思考をプログラミング化するいい題材がないか考えて、AtCoderを始めた。
なんだかんだ半年くらいは続いて、今もコンテストには参加しているけど、とっさのひらめき・知識・実装力不足を実感した。そして半年もやってるのにまだ沼から抜け出せてないOrz
初めて慣れてきた頃に、良い書籍が出て勉強になった。 blacktanktop.hatenablog.com
今年は合計で数百問は解いたけど、コンテストの復習も兼ねて、再度解き直しを行った。
書評 (2020-07~)
今年は、本を読むだけでなく、とりあえずまとめてみるっていうことを何回かやった。ただただ読むだけよりも、文章にすることで、細かいところをきちんと調べるようになったので、よりinputが捗った。これら以外の本も色々読んだけど、まとめられたのは、このくらいで、これからも続けていきたい。
移住 (2020-07~)
なにげに、結構でかい話で一生に1−2度くらいしかな異買い物をすることに。去年秋くらいから家庭の事情もあり、移住計画スタート。いい場所に家を建てられそうだったので、速攻土地をおさえ、なんだかんだ、去年末から家全体の設計を考えて、インテリアはどうするだの、ZEHにするだのと進んで、諸々終えたのが今年の2−3月。4月の緊急事態宣言直前に地鎮祭。ものの数ヶ月建築工事が終わって、引き渡しってな感じである意味激動の数ヶ月が裏では動いてたっていう。まぁ計画当初は去年秋で、まさかコロナの騒ぎがここまで大きくなるとは想像もしていなかったけど、結果的には無事に移住もできてフルリモートで働けるしイイコトづくし。
スタサプ・TOEIC(2020-09-10)
諸事情でTOEICを受けざるを得ず、1ヶ月くらい真剣にスタサプと向き合った。これまでTOEICは受けたことがなくどんなものかもよくわかっていなかったが、結果はギリ700超えでまぁ初手ではこんなもんかと、一旦納得した(分布的には平均よりちょっといいってことになってる)。家で模試を解いてたときは素点計算で800位だったので、もう少し試験慣れが重要かなと思ったけど、ここ数年割と離れていた割には、やはりリスニングの方ができるのはNetflixを英語字幕で観まくったり、友人と会話しているおかげかな・・・っていうかReadingが悪すぎ。まぁ機会があればもう少し対策して実際に800くらいはいけそうと思ったので、まぁもうすこし頑張ってもいいかな。英語の試験対策はつまらない・・・TOEICできなくてもある程度の英語でのコミュニケーションはできるしね。まぁ逆にTOEICできても話す場面で全く話せないっていうのだけは避けたくて、日常会話に力を入れてきたのがとりあえず受けて成果を出すって言うところに単純に活きた感じだった。
ちなみに、スタサプは月3000円位だったけど割とコスパがいいと思った。集中して1−2ヶ月やるだけで感触はつかめる。ただ試験対策は模試を時間通りに解いてやり直してを繰り返さないと、試験の感覚を養えないのと、試験は音が聞きづらい(ホールに響く感じになる)のでそこらへんの慣れも重要な気がした。
業績まとめ
諸事情で、過去の業績をまとめる必要があり、大学から大学院・その後理研・現職までをザーッとまとめるっていう作業をしていた。修論を整理しながら改めて、自分のやりたいことの方向性も固まってきたので、来年以降その方向で進んでいけるといいなと思っている。
終わりに
今年は、思いったら始めるっていう感じで通したので、来年はもう少し計画的にやりたい。来年からは何ヶ年計画で色々とやりたいことがあるので、年明けから結構忙しくなりそうだ。
Python3で解いた AtCoderの勉強になった問題 2020
- サマリー
- AtCoder Beginner Contest
- 169 C-Multiplication 3 (2020-05-31)
- 169 D - Div Game (2020-05-31)
- 170 D - Not Divisible (2020-06-14)
- 172 C - Tsundoku (2020-06-27)
- 172 D - Sum of Divisors (2020-06-27)
- 173 C - H and V (2020-07-05)
- 174 C - Repsept (2020-08-02)
- 176 D - Wizard in Maze (2020-08-22)
- 178 C - Ubiquity (2020-09-13)
- 180 C - Cream puff (2020-11-01)
- 181 D - Hachi (2020-10-17)
- 182 D - Wandering (2020-11-08)
- 183 D - Water Heater (2020-11-15)
- 184 D - increment of coins (2020-11-22)
- 186 D - Sum of difference (2020-12-19)
- AtCoder Regular Contest
- 最後に
- 参考書籍
サマリー
- 6月くらいから、AtCoderやってみようと、ふと思い立って初めて約半年。
- 年末時間ができたから復習していてそこで面白かった問題を上げていく。
- 基本過去記事の再掲しつつ、もう一度振り返る。
AtCoder Beginner Contest
169 C-Multiplication 3 (2020-05-31)
問題は以下 atcoder.jp 初めての参戦で、いきなりこの問題でWAを超絶だした記憶。オーバーフローや計算精度に関する問題も出るのかと痛感した。
どういう時に問題が起きるのかをそもそも理解できずに、試行錯誤しつつ、以下のうように、浮動小数は実際には正しい値を保持していないことを改めて知って勉強になった。
0.07 * 100 # 7.000000000000001 0.29 * 100 # 28.999999999999996
でもDecimalモジュール使えばいいやと思って通した。
a, b = map(str, input().split()) res = int(a) * Decimal(b) print(int(res))
けど本来は、数値をそのまま掛け合わせて後で割って整数部分だけ取得するとやってほしかったんだろうなぁ
a, b = map(str, input().split()) c,d = b.split('.') # int(c+d)とするとbを文字通り100倍された結果になる。 res = a * int(c+d) print(res//100)
169 D - Div Game (2020-05-31)
問題は以下 atcoder.jp この当時は、素因数分解をする方法もコードに落としてなくて1から実装しなきゃで大変だったが、それさえできればあと一工夫でできる。
170 D - Not Divisible (2020-06-14)
問題は以下
この当時は、エラトステネスの篩的な考えもコードに落としてないし、発想としても持っていなかった。
- リストに含まれるある値の定数倍の値をふるい落とすという考えを学んだ
- また、
in
で探すときは対象をlist
ではなくset
にしておくことが速度として重要というのも学んだ
n = int(input()) a = list(map(int, input().split())) a_s = sorted(a) a_set = set(a_s) maxv = max(a) res = [0] * (maxv+1) rep = 0 for i in a_s: # iを評価してない時はiを含むの定数倍のところは+1 if res[i] == 0: for j in range(i, maxv+1, i): res[j] += 1 # iを評価してあればiを+1 # すでに定数倍として評価されていたら2以上にしたい else: res[i] += 1 cnt = 0 # 最終的に検索対象が定数倍リスト内で1になっているものだけをカウントする for i in range(n): if res[a[i]] == 1: cnt += res[a[i]] print(cnt)
172 C - Tsundoku (2020-06-27)
問題は以下 atcoder.jp
ここらへんから記事書き始めた。
- しゃくとり
- 累積和と二分探索
この時、これらのイメージを掴んだ感じ
172 D - Sum of Divisors (2020-06-27)
問題は以下 atcoder.jp
Pythonだとでもだと通らないということを感じた回だった。
工夫すれば、
約数 等差数列の和で計算できる。
173 C - H and V (2020-07-05)
問題は以下 atcoder.jp
はじめてbitをコードで起こした。bit演算子である、'&'や '>'の意味を学んだ。
- bit全探索
- itertoolsのproduct の両者を学んだ。bitは未だに苦手でbitで全パターン検索するような場合は先にproductで作ってしまうほうが考えやすい。
174 C - Repsept (2020-08-02)
問題は以下 atcoder.jp
愚直に'7'をいくつも並べたものを順に割っていくっていうのはだめ。基本的にという様にたくさん文字列を羅列する形は遅い。
純粋に'7', '77', '777' ... なので初項7, 公比10の等比数列と考える。
- 等比数列の和
- 余りで考えれば良いのでモジュラの性質をうまく使って10倍されていく時にあまりを10倍して考えればオーバーフローなどを木にする必要がなくなる。
176 D - Wizard in Maze (2020-08-22)
問題は以下 atcoder.jp
結構重くて、なかなか通らなかった。 対策としては、外側へのはみ出しを防止。結構むずくて、今解き直しても素直に実装できなそう。
- 上下左右を'##'で埋める。
- あとは歩いていけなくなるまで普通の迷路探索 。
- ワープのパターン出いけるところに歩いていける範囲としてキューに加える。
178 C - Ubiquity (2020-09-13)
問題は以下 atcoder.jp
愚直に条件に当てはまるものを求めるのではなく、包括原理より、全パターンから条件に合わないものを引くとしたほうがいいパターン。
ポイントとして、という形は愚直に計算すると遅いので計算過程ではくり返し二乗法を使う
180 C - Cream puff (2020-11-01)
問題は以下 atcoder.jp
単純な約数列挙だが、いちからコード書くと結構大変だった。考え方としては素因数分解と同じようなイメージでいけた。からまで試し割りして、 割り切れたものと、割り切れたときの商を別々に保持して後でリストを連結
181 D - Hachi (2020-10-17)
問題は以下 atcoder.jp
単純な倍数判定だが、入れ替えを考慮するため侮れない。 結果から言うと、Counterで8の倍数の下3桁の文字列のパターンと一致するかどうかで判断。Counterの結果は引き算できることがポイント
182 D - Wandering (2020-11-08)
問題は以下 atcoder.jp
その時までの値の累積和とその時までの値の最大値の和を考える。 図示しながら考えるとわかり良い。
183 D - Water Heater (2020-11-15)
問題は以下 atcoder.jp
持ち方がポイントで、使うスケジュールの最初の時刻でプラス、終わりでマイナスしたリストを頭から順に足し合わせていくようにして、スケジュールの累積和として考える
184 D - increment of coins (2020-11-22)
問題は以下 atcoder.jp
メモ化を自動的にやってくれるlru_cacheというデコレータを知った。 メモ化と比較するとスッキリすることがわかる。
186 D - Sum of difference (2020-12-19)
問題は以下 atcoder.jp
久しぶりにコンテストの最中にDまで解けた。
引き算の絶対値がポイントで、事例を書き出して、ソートして考えても良いと考えられれば単純な数え上げとなる。
AtCoder Regular Contest
106 B - Value (2020-10-24)
問題は以下
Union-Find問題。連結しているグループの値の和が一致するかを検討するだけ。このとき注意しなくてはいけないのは、find()でrootを求めていく。
109 B - log (2020-11-28)
問題は以下
これまで、リストが存在する二分探索はやったことがあったが、この問題ではリストを作ってから行うと、TLEとなってしまうため、midの値を適切に変形し 探索したい値と比較する。
110 B - many (2020-12-05)
問題は以下
最初'0'にアサインできたら、最後、左から数えて何番目の'0'にアサインできるかを考える問題
最後に
結局だいたい実際にコンテストで解いた問題全部あげただけみたいになってしまったがまとめながら、半日かけて、ここに書き出した問題をもう一度解き直しして良い復習ができた。
ブログにまとめながらやっていたおかげで数ヶ月前に書いたコードを少し見直しただけで思い出せたし、復習が比較的楽にできてよかった。
2020年06月以前の問題も実際には精進として解いていて、その中でも良さげな問題はあったが、とりあえず今回は取り扱わないでおいた。
参考書籍
けんちょんさんの本。非常に参考になる。行き詰まった時にもう一度読み直したりしてる。
こちらで、書籍を7章まで進めている。