【ハンズオン】Snowflakeでマルチオミクス解析を体験してみる
はじめに
是枝です。
ライフサイエンス領域、特に創薬R&Dの現場では、近年「マルチオミクス」というキーワードをよく目にするようになりました。ゲノム、トランスクリプトーム(mRNA発現)、プロテオーム(タンパク質発現)、メタボロームなど、生体内で起きていることを複数の層から同時に観察し、疾患のメカニズム解明や創薬ターゲットの探索につなげようというアプローチです。
ただ、実際にマルチオミクス解析を始めようとすると、最初にぶつかるのはとても地味な作業です。
- サンプルIDを揃える
- 遺伝子IDやタンパク質IDの命名規則を統一する
- 薬剤名と化合物IDを紐付ける
- 複数の研究データを横断して結合する
- 欠損や不整合がないか品質を確認する
これらを行わずに統計解析やAIに進むと、結果が出ているように見えても、実際にはデータがズレており、解釈不能な結論を出してしまうことがあります。マルチオミクス解析は、いきなり高度なAIや統計解析から始まるわけではなく、まずデータを正しくつなぐデータエンジニアリングから始まります。
この記事では、その入口の部分を、Snowflakeを使って体験してみます。
今回体験すること
このハンズオンでは、以下の流れを体験します。
- Snowflake上にマルチオミクス解析用のデータベースとテーブルを作成する
- 遺伝子発現・タンパク質発現・薬剤応答・化合物構造のデータをロードする(SQLで再現)
- SQLで複数のデータをJOINして統合ビューを作る
- EGFRやABCB1といった遺伝子と、ErlotinibやDoxorubicinといった薬剤の関係を見る
- データ品質を確認する
- 候補薬剤を抽出する
- Snowflake Notebooks(Run on Container) で RDKitなどを使い、候補化合物の3D構造を可視化する
主題は「複数の生命科学データをつなぐデータエンジニアリング」です。高度な統計解析はあえて行いません。データ取得から構造可視化までをSnowflake上で完結させます。
データセットの考え方
本記事では、ChEMBLやDepMap/CCLEのような公共ライフサイエンスデータを題材に、Snowflakeでマルチオミクス解析の入口を体験します。実際の公共データセットは大きく、前処理やロードにも時間がかかるため、今回はハンズオン用に小さなサブセットをSQLで再現できる形にしました。データ量は小さいですが、サンプルID、遺伝子、タンパク質、薬剤応答、化合物構造をつなぐ考え方は、実際の大規模オミクス解析や創薬データ基盤と同じです。
ハンズオン環境
Snowflake Trial から30日間の無料トライアルを作成してください。
手順はこちらの記事を参考にしてください。
こんな画面にログインできたら成功です。

setup
下の 「setup.sql の全内容(クリックで展開)」 を開いて、SQL を 全文 コピーしてください。テーブル定義やINSERTを部分的に貼ると途中で止まってしまうので、必ず 全文 をコピーしてください。
setup.sql の全内容(クリックで展開)
-- =====================================================================
-- setup.sql
--
-- Snowflake Trial Account の Worksheet に貼り付けて実行するだけで、
-- マルチオミクスハンズオン用のデータベース、スキーマ、ウェアハウス、
-- テーブル、サンプルデータ、統合ビューが作成されます。
-- =====================================================================
-- ---------------------------------------------------------------------
-- 1. Database / Schema / Warehouse の作成
-- ---------------------------------------------------------------------
CREATE OR REPLACE DATABASE MULTIOMICS_HANDSON;
CREATE OR REPLACE SCHEMA MULTIOMICS_HANDSON.PUBLIC;
CREATE OR REPLACE WAREHOUSE HANDSON_WH
WAREHOUSE_SIZE = 'XSMALL'
AUTO_SUSPEND = 60
AUTO_RESUME = TRUE
INITIALLY_SUSPENDED = TRUE;
USE DATABASE MULTIOMICS_HANDSON;
USE SCHEMA PUBLIC;
USE WAREHOUSE HANDSON_WH;
-- ---------------------------------------------------------------------
-- 2. Table 作成
-- ---------------------------------------------------------------------
-- 2.1 samples: 細胞株・サンプルのメタデータ
CREATE OR REPLACE TABLE samples (
sample_id STRING,
cell_line_name STRING,
cancer_type STRING,
tissue STRING,
primary_disease STRING,
mutation_summary STRING
);
-- 2.2 gene_expression_subset: サンプル×遺伝子のmRNA発現量
CREATE OR REPLACE TABLE gene_expression_subset (
sample_id STRING,
gene_symbol STRING,
tpm FLOAT
);
-- 2.3 protein_expression_subset: サンプル×タンパク質の発現量
CREATE OR REPLACE TABLE protein_expression_subset (
sample_id STRING,
protein_symbol STRING,
protein_abundance FLOAT
);
-- 2.4 drug_response_subset: サンプル×薬剤の感受性
CREATE OR REPLACE TABLE drug_response_subset (
sample_id STRING,
drug_id STRING,
drug_name STRING,
ic50_um FLOAT,
auc FLOAT,
response_label STRING
);
-- 2.5 compounds: 化合物情報
CREATE OR REPLACE TABLE compounds (
drug_id STRING,
drug_name STRING,
chembl_id STRING,
pubchem_cid STRING,
canonical_smiles STRING,
molecular_weight FLOAT,
alogp FLOAT
);
-- 2.6 compound_targets: 化合物と標的の対応
CREATE OR REPLACE TABLE compound_targets (
drug_id STRING,
drug_name STRING,
target_symbol STRING,
target_name STRING,
target_chembl_id STRING,
relationship STRING
);
-- ---------------------------------------------------------------------
-- 3. サンプルデータ投入
-- ---------------------------------------------------------------------
-- 3.1 samples
INSERT INTO samples
(sample_id, cell_line_name, cancer_type, tissue, primary_disease, mutation_summary)
VALUES
('S001', 'HepG2', 'Liver Cancer', 'Liver', 'Hepatocellular Carcinoma', 'TP53 mut'),
('S002', 'Huh7', 'Liver Cancer', 'Liver', 'Hepatocellular Carcinoma', 'TP53 mut'),
('S003', 'A549', 'Lung Cancer', 'Lung', 'NSCLC', 'KRAS G12S mut'),
('S004', 'MCF7', 'Breast Cancer', 'Breast', 'Breast Adenocarcinoma', 'PIK3CA mut'),
('S005', 'HT29', 'Colon Cancer', 'Colon', 'Colorectal Adenocarcinoma', 'BRAF V600E mut');
-- 3.2 gene_expression_subset
INSERT INTO gene_expression_subset
(sample_id, gene_symbol, tpm)
VALUES
-- HepG2
('S001', 'EGFR', 10.2),
('S001', 'ERBB2', 11.5),
('S001', 'ABCB1', 3.2),
('S001', 'MGAT5', 5.0),
('S001', 'FUT8', 11.0),
('S001', 'TP53', 18.0),
('S001', 'KRAS', 22.0),
-- Huh7 (ABCB1 high)
('S002', 'EGFR', 5.5),
('S002', 'ERBB2', 9.5),
('S002', 'ABCB1', 32.0),
('S002', 'MGAT5', 6.0),
('S002', 'FUT8', 13.0),
('S002', 'TP53', 22.0),
('S002', 'KRAS', 19.0),
-- A549 (EGFR high, KRAS high)
('S003', 'EGFR', 45.0),
('S003', 'ERBB2', 8.0),
('S003', 'ABCB1', 5.0),
('S003', 'MGAT5', 14.0),
('S003', 'FUT8', 20.0),
('S003', 'TP53', 12.0),
('S003', 'KRAS', 55.0),
-- MCF7 (ERBB2 high)
('S004', 'EGFR', 8.0),
('S004', 'ERBB2', 40.0),
('S004', 'ABCB1', 2.5),
('S004', 'MGAT5', 8.0),
('S004', 'FUT8', 9.5),
('S004', 'TP53', 25.0),
('S004', 'KRAS', 18.0),
-- HT29 (EGFR moderate-high)
('S005', 'EGFR', 22.0),
('S005', 'ERBB2', 15.0),
('S005', 'ABCB1', 6.0),
('S005', 'MGAT5', 11.0),
('S005', 'FUT8', 14.0),
('S005', 'TP53', 20.0),
('S005', 'KRAS', 28.0);
-- 3.3 protein_expression_subset (mRNAと完全相関しないように調整)
INSERT INTO protein_expression_subset
(sample_id, protein_symbol, protein_abundance)
VALUES
-- HepG2
('S001', 'EGFR', 8.0),
('S001', 'ERBB2', 14.0),
('S001', 'ABCB1', 4.0),
('S001', 'MGAT5', 6.5),
('S001', 'FUT8', 13.0),
('S001', 'TP53', 22.0),
('S001', 'KRAS', 20.0),
-- Huh7
('S002', 'EGFR', 12.0), -- mRNAは低いがタンパクは中程度(mRNA-protein乖離)
('S002', 'ERBB2', 10.0),
('S002', 'ABCB1', 35.0),
('S002', 'MGAT5', 7.5),
('S002', 'FUT8', 12.5),
('S002', 'TP53', 24.0),
('S002', 'KRAS', 17.5),
-- A549
('S003', 'EGFR', 52.0),
('S003', 'ERBB2', 9.0),
('S003', 'ABCB1', 6.0),
('S003', 'MGAT5', 16.0),
('S003', 'FUT8', 22.0),
('S003', 'TP53', 11.0),
('S003', 'KRAS', 50.0),
-- MCF7
('S004', 'EGFR', 6.0),
('S004', 'ERBB2', 42.0),
('S004', 'ABCB1', 3.0),
('S004', 'MGAT5', 9.0),
('S004', 'FUT8', 10.0),
('S004', 'TP53', 26.0),
('S004', 'KRAS', 18.5),
-- HT29
('S005', 'EGFR', 18.0),
('S005', 'ERBB2', 16.0),
('S005', 'ABCB1', 7.5),
('S005', 'MGAT5', 12.0),
('S005', 'FUT8', 15.0),
('S005', 'TP53', 18.0),
('S005', 'KRAS', 26.0);
-- 3.4 drug_response_subset
INSERT INTO drug_response_subset
(sample_id, drug_id, drug_name, ic50_um, auc, response_label)
VALUES
-- HepG2
('S001', 'DRUG001', 'Erlotinib', 4.0, 0.55, 'Intermediate'),
('S001', 'DRUG002', 'Doxorubicin', 0.5, 0.28, 'Sensitive'),
('S001', 'DRUG003', 'Gefitinib', 4.5, 0.58, 'Intermediate'),
('S001', 'DRUG004', 'Lapatinib', 4.0, 0.55, 'Intermediate'),
-- Huh7 (ABCB1 high → Doxorubicin resistant)
('S002', 'DRUG001', 'Erlotinib', 9.5, 0.78, 'Resistant'),
('S002', 'DRUG002', 'Doxorubicin', 15.0, 0.88, 'Resistant'),
('S002', 'DRUG003', 'Gefitinib', 10.0, 0.80, 'Resistant'),
('S002', 'DRUG004', 'Lapatinib', 9.0, 0.76, 'Resistant'),
-- A549 (EGFR high → EGFR inhibitors sensitive)
('S003', 'DRUG001', 'Erlotinib', 0.8, 0.18, 'Sensitive'),
('S003', 'DRUG002', 'Doxorubicin', 1.0, 0.30, 'Sensitive'),
('S003', 'DRUG003', 'Gefitinib', 0.9, 0.20, 'Sensitive'),
('S003', 'DRUG004', 'Lapatinib', 2.5, 0.42, 'Intermediate'),
-- MCF7 (ERBB2 high → Lapatinib sensitive)
('S004', 'DRUG001', 'Erlotinib', 5.5, 0.62, 'Intermediate'),
('S004', 'DRUG002', 'Doxorubicin', 0.4, 0.25, 'Sensitive'),
('S004', 'DRUG003', 'Gefitinib', 6.0, 0.65, 'Intermediate'),
('S004', 'DRUG004', 'Lapatinib', 0.6, 0.18, 'Sensitive'),
-- HT29
('S005', 'DRUG001', 'Erlotinib', 2.0, 0.38, 'Sensitive'),
('S005', 'DRUG002', 'Doxorubicin', 0.8, 0.30, 'Sensitive'),
('S005', 'DRUG003', 'Gefitinib', 2.5, 0.42, 'Sensitive'),
('S005', 'DRUG004', 'Lapatinib', 3.5, 0.50, 'Intermediate');
-- 3.5 compounds
INSERT INTO compounds
(drug_id, drug_name, chembl_id, pubchem_cid, canonical_smiles, molecular_weight, alogp)
VALUES
('DRUG001', 'Erlotinib', 'CHEMBL553', '176870', 'COCCOc1cc2ncnc(Nc3cccc(Cl)c3)c2cc1OCCOC', 393.4, 2.7),
('DRUG002', 'Doxorubicin', 'CHEMBL53463', '31703', 'COc1cccc2c1C(=O)c1c(O)c3c(c(O)c1C2=O)CC(O)(C(=O)CO)CC3OC1CC(N)C(O)C(C)O1', 543.5, 1.3),
('DRUG003', 'Gefitinib', 'CHEMBL939', '123631', 'COc1cc2ncnc(Nc3ccc(F)c(Cl)c3)c2cc1OCCCN1CCOCC1', 446.9, 3.7),
('DRUG004', 'Lapatinib', 'CHEMBL554', '208908', 'CS(=O)(=O)CCNCc1ccc(-c2ccc3ncnc(Nc4ccc(OCc5cccc(F)c5)c(Cl)c4)c3c2)o1', 581.1, 5.4);
-- 3.6 compound_targets
INSERT INTO compound_targets
(drug_id, drug_name, target_symbol, target_name, target_chembl_id, relationship)
VALUES
('DRUG001', 'Erlotinib', 'EGFR', 'Epidermal growth factor receptor', 'CHEMBL203', 'primary'),
('DRUG002', 'Doxorubicin', 'TOP2A', 'DNA topoisomerase 2-alpha', 'CHEMBL1806', 'primary'),
('DRUG003', 'Gefitinib', 'EGFR', 'Epidermal growth factor receptor', 'CHEMBL203', 'primary'),
('DRUG004', 'Lapatinib', 'EGFR', 'Epidermal growth factor receptor', 'CHEMBL203', 'primary'),
('DRUG004', 'Lapatinib', 'ERBB2', 'Receptor tyrosine-protein kinase erbB-2', 'CHEMBL1824', 'primary');
-- ---------------------------------------------------------------------
-- 4. 統合 View 作成
-- ---------------------------------------------------------------------
CREATE OR REPLACE VIEW multiomics_drug_response_view AS
SELECT
s.sample_id,
s.cell_line_name,
s.cancer_type,
s.tissue,
s.primary_disease,
s.mutation_summary,
g.gene_symbol,
g.tpm,
p.protein_abundance,
d.drug_id,
d.drug_name,
d.ic50_um,
d.auc,
d.response_label
FROM samples s
JOIN gene_expression_subset g
ON s.sample_id = g.sample_id
JOIN protein_expression_subset p
ON s.sample_id = p.sample_id
AND g.gene_symbol = p.protein_symbol
JOIN drug_response_subset d
ON s.sample_id = d.sample_id;
-- ---------------------------------------------------------------------
-- 5. セットアップ完了確認
-- ---------------------------------------------------------------------
SELECT 'setup completed' AS status;
SELECT COUNT(*) AS samples_count FROM samples;
SELECT COUNT(*) AS gene_expression_count FROM gene_expression_subset;
SELECT COUNT(*) AS protein_expression_count FROM protein_expression_subset;
SELECT COUNT(*) AS drug_response_count FROM drug_response_subset;
SELECT COUNT(*) AS compounds_count FROM compounds;
SELECT COUNT(*) AS compound_targets_count FROM compound_targets;
SELECT COUNT(*) AS multiomics_view_row_count FROM multiomics_drug_response_view;
操作手順は以下です。
-
Snowsightで
Projects>Add new>SQL fileと進む

-
ファイル名(例:
setup.sql)を決めるとシートが開くので、setup.sqlの 全文 を貼り付ける -
SQL を全選択 したうえで(必ず全選択してください。カーソル位置のクエリだけだと一部しか走りません)、左上の ▶ ボタンでクエリを実行する

-
最後に 140 が返ってくれば成功です。

SQLで各データを確認する
まずは個別のテーブルを覗いてみます。下記をworksheetに貼り付けてください。
SELECT * FROM samples;
SELECT * FROM gene_expression_subset LIMIT 10;
SELECT * FROM protein_expression_subset LIMIT 10;
SELECT * FROM drug_response_subset LIMIT 10;
SELECT * FROM compounds;
SELECT * FROM compound_targets;
今度は全選択をせず、「SELECT * FROM samples;」行だけを選択して▶をクリックします。

samples には HepG2、Huh7、A549、MCF7、HT29 など、よく研究で使われるがん細胞株が並んでいます。
他のSQLも実行していき、中身を見てみてください。今回扱うテーブルは以下の6つになっています。
| テーブル名 | 内容 |
|---|---|
samples |
細胞株・サンプルのメタデータ |
gene_expression_subset |
サンプル×遺伝子のmRNA発現量(TPM) |
protein_expression_subset |
サンプル×タンパク質の発現量 |
drug_response_subset |
サンプル×薬剤の感受性(IC50, AUC, ラベル) |
compounds |
化合物情報(SMILES, ChEMBL ID, PubChem CIDなど) |
compound_targets |
化合物と標的タンパク質の対応 |
gene_expression_subset にはEGFR、ERBB2、ABCB1、TP53などの主要な遺伝子のTPM値、compounds にはErlotinib、Doxorubicin、Gefitinib、LapatinibなどのSMILESが格納されています。
これらを sample_id、gene_symbol/protein_symbol、drug_id で結合することで、「どの細胞株で、どの遺伝子がどれくらい発現していて、どの薬剤に感受性があり、その薬剤はどんな構造で何を標的にしているか」を1行で表現できる統合ビューを作ります。
遺伝子発現とタンパク質発現をつなぐ
mRNA発現量とタンパク質量は、必ずしも一致しません。転写後制御、翻訳効率、タンパク質の分解速度などの影響があるためです。にもかかわらず、多くの解析で「遺伝子発現=タンパク質量」と暗黙に仮定されてしまうことがあります。
Snowflakeで簡単に比較してみます。
SELECT
s.cell_line_name,
g.gene_symbol,
g.tpm AS mrna_tpm,
p.protein_abundance AS protein_level
FROM samples s
JOIN gene_expression_subset g
ON s.sample_id = g.sample_id
JOIN protein_expression_subset p
ON s.sample_id = p.sample_id
AND g.gene_symbol = p.protein_symbol
ORDER BY s.cell_line_name, g.gene_symbol;

mRNAとタンパク質量の乖離を眺めてみると、「mRNAだけ高い」「タンパク質だけ高い」という細胞株があることに気づきます。
EGFR発現とEGFR阻害薬の感受性を見る
EGFR(上皮成長因子受容体)は、肺がんや乳がんなどで重要な創薬ターゲットです。Erlotinib、Gefitinib、LapatinibはEGFR/ERBB2阻害薬として知られています。
EGFRの発現量と、Erlotinib・Gefitinibに対する感受性(IC50)を見てみます。
SELECT
v.cell_line_name,
v.cancer_type,
v.gene_symbol,
v.tpm,
v.protein_abundance,
v.drug_name,
v.ic50_um,
v.response_label
FROM multiomics_drug_response_view v
WHERE v.gene_symbol = 'EGFR'
AND v.drug_name IN ('Erlotinib', 'Gefitinib')
ORDER BY v.ic50_um ASC;
EGFRが高発現している細胞株のIC50が低い(=感受性が高い)傾向があれば、「EGFR発現が高い細胞株はEGFR阻害薬に効きやすい」という古典的な仮説を、データで眺めることができます。

ただし、これは仮説生成の入口です。実際の薬剤感受性は、EGFR単独ではなく、変異、ダウンストリームのシグナル経路、薬剤耐性機構、細胞株背景など、複数の要因で決まります。
ABCB1と薬剤耐性の関係を考える
ABCB1(別名 MDR1、P-glycoprotein)は、細胞外に薬剤を排出する輸送体です。ABCB1が高発現している細胞は、抗がん剤の中でもDoxorubicinなどを効きにくくすることが知られています。
SELECT
v.cell_line_name,
v.cancer_type,
v.gene_symbol,
v.tpm,
v.drug_name,
v.ic50_um,
v.response_label
FROM multiomics_drug_response_view v
WHERE v.gene_symbol = 'ABCB1'
AND v.drug_name = 'Doxorubicin'
ORDER BY v.tpm DESC;
ABCB1のTPMが高い細胞株でIC50が大きく(=効きにくい)なっていれば、薬剤耐性メカニズムの一端を眺めたことになります。

分析しやすいビューを作る
ここまでに使ったような結合は、毎回SQLで書くと冗長です。setup.sql の最後に統合ビューを作っておきます。
CREATE OR REPLACE VIEW multiomics_drug_response_view AS
SELECT
s.sample_id,
s.cell_line_name,
s.cancer_type,
s.tissue,
s.primary_disease,
s.mutation_summary,
g.gene_symbol,
g.tpm,
p.protein_abundance,
d.drug_id,
d.drug_name,
d.ic50_um,
d.auc,
d.response_label
FROM samples s
JOIN gene_expression_subset g
ON s.sample_id = g.sample_id
JOIN protein_expression_subset p
ON s.sample_id = p.sample_id
AND g.gene_symbol = p.protein_symbol
JOIN drug_response_subset d
ON s.sample_id = d.sample_id;
ビューを作っておくと次回以降は下記のような簡単なSQLで同じ結果を返すことができます。
select * from multiomics_drug_response_view;

このビューを使うことで、サンプル・遺伝子・タンパク質・薬剤応答を1行で扱えるようになり、後続の分析が一気にシンプルになります。
データ品質を確認する
高度な解析の前に必ずやっておくべきことが、データ品質の確認です。サンプルIDの不一致は、解析結果を大きく壊します。
典型的なチェックは以下のような形です。いずれも 「問題があるレコードを拾う」検査クエリ なので、setup.sql 通りにデータが入っていれば すべて No rows (空の結果)が返るのが正解 です。逆に何か行が返ってきたら、その行が壊れているサンプルです。
-- gene_expression_subset の sample_id が samples に存在するか
-- → No rows なら「孤児サンプルなし」
SELECT DISTINCT sample_id
FROM gene_expression_subset
MINUS
SELECT sample_id FROM samples;
-- drug_response_subset の drug_id が compounds に存在するか
-- → No rows なら「未登録の薬剤IDなし」
SELECT DISTINCT drug_id
FROM drug_response_subset
MINUS
SELECT drug_id FROM compounds;
-- IC50が負値になっていないか
-- → No rows なら「不正な負値なし」
SELECT *
FROM drug_response_subset
WHERE ic50_um < 0;
-- 重複チェック
-- → No rows なら「(sample_id, gene_symbol) ユニーク」
SELECT sample_id, gene_symbol, COUNT(*) AS cnt
FROM gene_expression_subset
GROUP BY sample_id, gene_symbol
HAVING COUNT(*) > 1;

正解の画面。no resultsで返ってきます
地味ですが、ここを飛ばすと「結果は出たが意味がない」状態になりがちです。マルチオミクス解析でデータ品質確認は必須工程です。
候補薬剤を抽出する
それでは、response_label = 'Sensitive' の薬剤、つまり「効きやすい」とラベルされた薬剤を抽出してみます。
SELECT
v.cell_line_name,
v.cancer_type,
v.gene_symbol,
v.tpm,
v.protein_abundance,
v.drug_id,
v.drug_name,
v.ic50_um,
v.response_label
FROM multiomics_drug_response_view v
WHERE v.response_label = 'Sensitive'
ORDER BY v.ic50_um ASC;
IC50昇順なので、最も感受性が高い組み合わせから並びます。

候補薬剤の構造情報を付与する
候補薬剤が抽出できたら、SMILESや標的情報を付与します。これでデータ統合の最終形になります。
SELECT
v.cell_line_name,
v.cancer_type,
v.gene_symbol,
v.tpm,
v.protein_abundance,
v.drug_id,
v.drug_name,
v.ic50_um,
v.response_label,
c.chembl_id,
c.pubchem_cid,
c.canonical_smiles,
t.target_symbol,
t.target_name
FROM multiomics_drug_response_view v
JOIN compounds c
ON v.drug_id = c.drug_id
LEFT JOIN compound_targets t
ON v.drug_id = t.drug_id
WHERE v.response_label = 'Sensitive'
ORDER BY v.ic50_um ASC;
結果を少し右にスクロールするとあらたに構造情報が付与されています。

ここまで来ると、1行の中に「細胞株、遺伝子発現、タンパク質発現、薬剤感受性、化合物構造、標的」がすべて揃います。マルチオミクス×ケミカル空間の結合点です。
Snowflake Notebooks でPythonを使いながら詳細に解析してみる
ここまでで、SQL だけで「サンプル × 遺伝子 × タンパク質 × 薬剤応答 × 化合物構造」を1つのビューに統合し、Sensitive な候補薬剤を抽出できました。ただし、抽出した候補化合物が どんな立体構造を持っているか は SMILES 文字列のままでは分かりません。さらに、その薬剤の 機序や適応 を補足情報として並べたい場面もあります。
ここからは Python に切り替えて、候補化合物の3D構造を RDKit + matplotlib で可視化するを行います。Snowflake Notebooks を使えば、Snowflake が用意したコンテナ内で pip install rdkit などの外部ライブラリが利用でき、SQL → Python を Snowflake 上で完結させられます。
準備は以下の手順で行います。
Notebook を作成して Service に接続する
-
Workspaces>+ Add new>Notebook (.ipynb)を作成(例: multiomics.ipynb) -
Notebook 上部の
Connectをクリック -
Connect your notebook ダイアログで以下を設定
-
Service name: 任意の名前(例:
MULTIOMICS_SERVICE_1) -
Artifact repositories:
SNOWFLAKE.SNOWPARK.PYPI_SHARED_REPOSITORYを選択
-
Service name: 任意の名前(例:

-
Create and connectをクリック
ステータスが Connected になったら準備完了です。(2~3分かかります)

準備
notebooksを始める前に準備コードを実行します。

from snowflake.snowpark.context import get_active_session
session = get_active_session()
session.sql("USE DATABASE MULTIOMICS_HANDSON").collect()
session.sql("USE SCHEMA MULTIOMICS_HANDSON.PUBLIC").collect()
session.sql("USE WAREHOUSE HANDSON_WH").collect()
[Row(status='Statement executed successfully.')] と出れば成功です。
Notebook内でパッケージをインストールする
Notebook 内では 2D 描画までを行うため、 rdkit を入れます。
「+Python」をクリックしてcellを追加し、以下を実行してください。

!pip install --quiet rdkit
こんな状態が正解です。警告は無視でOKです。

RDKitで分子構造を扱う
候補薬剤を取得して2D構造を可視化します。
Pythonセルを追加してから以下を実行してください。
from rdkit import Chem
from rdkit.Chem import Draw, AllChem
candidates_df = session.sql("""
SELECT v.drug_name, c.canonical_smiles, v.ic50_um
FROM multiomics_drug_response_view v
JOIN compounds c ON v.drug_id = c.drug_id
WHERE v.response_label = 'Sensitive'
ORDER BY v.ic50_um ASC
""").to_pandas()
row = candidates_df.iloc[0]
smiles = row["CANONICAL_SMILES"]
name = row["DRUG_NAME"]
mol = Chem.MolFromSmiles(smiles)
Draw.MolToImage(mol, size=(500, 400), legend=name)

これでSnowflakeから直接取得したSMILESの2D構造が、Snowflake上のNotebookに描画されます。
候補化合物を3D構造で眺める
Notebook内で RDKit が生成した3Dコンフォマーを、matplotlib の3D scatter+bond lineで描画します。
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # noqa: F401 3D投影の有効化に必要
mol3d = Chem.AddHs(mol)
params = AllChem.ETKDGv3()
params.randomSeed = 42
AllChem.EmbedMolecule(mol3d, params)
AllChem.MMFFOptimizeMolecule(mol3d)
conf = mol3d.GetConformer()
xs, ys, zs, syms = [], [], [], []
for atom in mol3d.GetAtoms():
p = conf.GetAtomPosition(atom.GetIdx())
xs.append(p.x); ys.append(p.y); zs.append(p.z)
syms.append(atom.GetSymbol())
# 主要元素の色分け(CPK風)
color_map = {
"C": "#2c2c2c", "H": "#cccccc", "N": "#3358ff", "O": "#ff3030",
"S": "#e0c000", "F": "#80ff80", "Cl": "#30c030", "Br": "#a52a2a",
"P": "#ff8000",
}
colors = [color_map.get(s, "#888888") for s in syms]
fig = plt.figure(figsize=(7, 6))
ax = fig.add_subplot(111, projection="3d")
# 結合線
for bond in mol3d.GetBonds():
a1 = conf.GetAtomPosition(bond.GetBeginAtomIdx())
a2 = conf.GetAtomPosition(bond.GetEndAtomIdx())
ax.plot([a1.x, a2.x], [a1.y, a2.y], [a1.z, a2.z],
color="#555555", linewidth=0.8)
# 原子
ax.scatter(xs, ys, zs, c=colors, s=80, edgecolors="black",
linewidths=0.4, depthshade=True)
ax.set_title(name)
ax.set_xlabel("X (Å)"); ax.set_ylabel("Y (Å)"); ax.set_zlabel("Z (Å)")
plt.tight_layout()
plt.show()

Snowflake Notebookのセル内に、Sensitive な候補薬剤の代表的な3Dコンフォマーが静的画像として描画されます。
Cortex Code で次の解析を追加してもらう
Snowflake Notebooks には Cortex Code というAIアシスタントが内蔵されています。ノートブック内のセルやデータ構造を把握した上で、自然言語の指示に応じてコードセルを生成・追加してくれます。「次に何を分析するか」をAIと対話しながら進められるのが特徴です。
右下のマークをクリックしたら、Cortex Codeを呼び出すことができます。


それでは、Cortex Code に、感受性Top10化合物のグリッド表示を追加してもらいましょう。
以下のメッセージを送信する
「感受性の高い候補化合物 Top10をRdkitで可視化するコードを追加してください」
Cortex Code がノートブック内のセルとデータ構造を読み取り、解析セルを自動で追加し実行までしてくれます。

IC50が低い順に上位10化合物の2D構造がグリッド形式で一覧表示されます。候補化合物を構造レベルで比較する出発点として使えます。
他にも色々な解析を追加してもらいましょう。例えば以下のようなメッセージを送ってみてどうなるか確認してみましょう。
- 「Sensitive な化合物について、分子量と LogP の散布図を描いてください」
- 「各サンプルで Sensitive だった薬剤の数を棒グラフで比較するコードを追加してください」
- 「EGFR 発現量と Erlotinib の IC50 の相関を散布図で可視化するコードを追加してください」
まとめ
いかがだったでしょうか。
マルチオミクス解析の入口は、派手な統計やAIではなく、データを正しくつなぐエンジニアリング作業です。Snowflakeはそこに非常に向いたプラットフォームで、SQL一本で複数の研究データを統合し、Notebooks on Container Runtime で構造可視化までを同じ環境内で完結させ、後続の AI解析へと自然に拡張できます。
今回はSnowflake初心者向けに、SQLベースでデータを準備しましたが、数億を超える大規模なデータを扱うときにはまた手法が異なります。それはまた別の記事でハンズオン資料としてまとめていこうと思います。
Discussion