0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

化合物の水溶解度を機械学習で予測してみる④:フィンガープリントの導入

0
Last updated at Posted at 2026-09-04

はじめに

ここまで,

今回は,分子の表現方法として「フィンガープリント」を導入し,記述子ベースのモデルとの比較を行います.

フィンガープリントとは

これまでのモデルでは,分子を MolLogP や Molecular Weight などの「記述子」で数値化していました.記述子は分子全体の性質を数値で表すものでした.

フィンガープリントは,これとは全く違うアプローチで分子を表現します.
分子にどんな部分構造が含まれるかを,0/1 のビット列で表します.

今回使う Morgan フィンガープリント(ECFP とも呼ばれる)は,各原子の周囲[radius]結合先までの環境を見てビット化するもので,最も広く使われているフィンガープリントです.デフォルトではradius=2,2048 ビットで表現します.
こちらこちらなどではもっと詳しい説明があります.

つまり,

  • 記述子: 分子全体の性質を数値化(MolWt=180, LogP=2.3, ...)→ 少数の特徴量
  • フィンガープリント: 部分構造の有無をビットで表現([0,1,1,0,1,0,...])→ 多数の特徴量

というように,両者は質も量も異なる特徴量であり,モデルの性能にも影響を与えると期待できます.

フィンガープリントの導入

データセットは前回の続きからです.

from rdkit.Chem import AllChem

# Morgan フィンガープリントを計算する関数
def calc_morgan_fp(mol, radius=2, n_bits=2048):
    """Mol オブジェクトから Morgan フィンガープリントを numpy 配列で返す"""
    fp = AllChem.GetMorganFingerprintAsBitVect(mol, radius=radius, nBits=n_bits)
    return np.array(fp)

# 全分子のフィンガープリントを計算
fps = np.array([calc_morgan_fp(mol) for mol in df["mol"]])
print(f"フィンガープリントの形: {fps.shape}")
print(f"1分子あたりのビット数: {fps.shape[1]}")
print(f"平均で ON になっているビット数: {fps.sum(axis=1).mean():.1f} / {fps.shape[1]}")

image.png
2048 ビットのうち,平均 21.5 個しか ON になっていません(約 1%).
これは「スパース(疎)」な表現と呼ばれています.
正常な状態で,ありうる部分構造パターンは膨大ですが,1つの分子が持つ部分構造はそのごく一部だからです.
大きくて複雑な分子ほど ON ビットが多く,小さい分子ほど少なくなります.

モデル作成・評価

3つの特徴量セットを比較します.
記述子だけ、フィンガープリントだけ、両方、の3パターンです.

from sklearn.model_selection import cross_val_score
from lightgbm import LGBMRegressor

# 特徴量セット3パターン
X_desc = df[desc_cols_v2].values           # 記述子のみ(9個)
X_fp = fps                                  # フィンガープリントのみ(2048個)
X_both = np.hstack([X_desc, fps])           # 両方(9 + 2048 = 2057個)

model = LGBMRegressor(n_estimators=200, random_state=42, verbose=-1)

for name, X_data in [
    ("記述子のみ (9個)",        X_desc),
    ("フィンガープリントのみ (2048個)", X_fp),
    ("記述子 + FP (2057個)",    X_both),
]:
    cv = cross_val_score(model, X_data, y, cv=5, scoring="r2")
    print(f"  {name:35s}: R² = {cv.mean():.4f}{cv.std():.4f})")

image.png

LightGBM では,記述子 + FP の組み合わせが最良(R² = 0.906)でした.
フィンガープリントだけ(0.709)は記述子だけ(0.887)に大きく負けています.
これは,溶解度が LogP(疎水性)に強く支配されるため,LogP を含む記述子の方が直接的な情報を持っているからです.
しかし両方を組み合わせると最良になりました.
フィンガープリントは記述子では捉えられない「特定の部分構造パターンが溶解度に効く」情報を補完しているためと考えられます.

Ridgeでも比較しました.Ridge は全特徴量を穏やかに縮小する正則化を行うため,2048 個のスパースなフィンガープリントに対しても安定して動作する可能性があるとのことです.

from sklearn.linear_model import Ridge
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

pipe_ridge = Pipeline([
    ("scaler", StandardScaler()),
    ("model", Ridge(alpha=1.0))
])

for name, X_data in [
    ("記述子のみ (9個)",        X_desc),
    ("フィンガープリントのみ (2048個)", X_fp),
    ("記述子 + FP (2057個)",    X_both),
]:
    cv = cross_val_score(pipe_ridge, X_data, y, cv=5, scoring="r2")
    print(f"  {name:35s}: R² = {cv.mean():.4f}{cv.std():.4f})")

image.png

しかし結果としては,Ridge ではフィンガープリントが全く効きませんでした(R² = -0.019).
1128 サンプルに対して 2048 特徴量は,線形モデルでは扱いきれない状況です.いわゆる次元の呪いというものです.
記述子 + FP(R² = 0.546)でも,記述子だけ(0.783)より大きく悪化しました.

他のフィンガープリント

他のフィンガープリントについても比較してみました.

  • Morgan FP (ECFP): 各原子の周囲環境をビット化.最も汎用的
  • MACCS Keys: 166 個の決められた部分構造の有無を記録.解釈しやすい
  • RDKit FP: 分子内のパス(原子の並び)をビット化
from rdkit.Chem import MACCSkeys

# MACCS Keys フィンガープリントを計算
fps_maccs = np.array([np.array(MACCSkeys.GenMACCSKeys(mol)) for mol in df["mol"]])
print(f"MACCS Keys の形: {fps_maccs.shape}")

# RDKit フィンガープリントも計算
from rdkit.Chem import RDKFingerprint
fps_rdkit = np.array([np.array(Chem.RDKFingerprint(mol)) for mol in df["mol"]])
print(f"RDKit FP の形: {fps_rdkit.shape}")

# 3種類のフィンガープリントを比較
model = LGBMRegressor(n_estimators=200, random_state=42, verbose=-1)

print("\n=== フィンガープリント比較(LightGBM) ===\n")
for name, fp_data in [
    ("Morgan FP (2048 bit)",  fps),
    ("MACCS Keys (167 bit)",  fps_maccs),
    ("RDKit FP (2048 bit)",   fps_rdkit),
]:
    cv = cross_val_score(model, fp_data, y, cv=5, scoring="r2")
    print(f"  {name:25s}: R² = {cv.mean():.4f}{cv.std():.4f})")

image.png

予想外に,MACCSが良いことがわかりました.MACCSは部分構造の有無が0,1で記録されているため,「溶解性の向上にはこの官能基が相関する」と明確にわかる場合は他のフィンガープリントよりも良い場合があるそうです.
今回は水溶解性はOH, NH2,芳香環など,割と具体的な官能基との相関があるパラメータであるというのが理由だと思われます.

まとめ

今回は,分子の表現方法として「フィンガープリント」を導入しました.
記述子は分子全体の性質(LogP,分子量など)を数値化するのに対して,フィンガープリントは部分構造の有無をビット列で表現します.
両者は異なる種類の情報を持っており,組み合わせることで精度が向上しました.

特徴量セット LightGBM R² Ridge R²
記述子のみ(9個) 0.887 0.783
Morgan FP のみ(2048個) 0.709 -0.019
記述子 + Morgan FP(2057個) 0.906 0.546

また,フィンガープリントは木系モデル(LightGBM)と相性が良いが,線形モデル(Ridge)には向かないということがわかりました.
LightGBMは2048個のスパースなビットから有効なものだけを選べますが,Ridgeは全ビットを扱おうとして次元の呪いで崩壊する,ということです.

改善の推移

ステップ 内容 CV R² 改善
1 6記述子 + 線形回帰 0.676
2 9記述子 + 線形回帰 0.783 +0.107
3 9記述子 + LightGBM 0.888 +0.105
4 9記述子 + FP + LightGBM 0.906 +0.018

次回は水溶解度予測の最後となります.
SHAP を使ってモデルの中身を解釈し,Delaney の元論文の予測式(ESOL)との性能比較を行います.

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?