Matrices, Regularized Regression and Interpretation

数値計算・機械学習

分子・反応を行、記述子を列とする行列を定義し、再現可能な前処理、正則化回帰、次元削減、モデル解釈へ進みます。

数値基盤
NumPy・線形代数
モデル
Ridge・Lasso・Elastic Net・PCA
解釈
係数、loading、SHAP

1. 化学データを行列にする

n個の分子・反応とp個の特徴量を、design matrix XRn×pに並べます。目的変数はyRnです。

X=x11x1pxn1xnp

列にはfingerprint bit、物性記述子、Sterimol、%Vbur、cubeから抽出したfield特徴量などが入ります。定義・単位・欠損処理をmetadataとして保存します。

2. NumPy配列の基礎

線形代数でもnumpy.matrixではなく通常のndarrayを使います。*は要素積、@は行列積です。

Python
import numpy as np

X = np.array([
    [2.1, 0.32, 71.4],
    [2.5, 0.41, 74.8],
    [3.0, 0.55, 80.2],
], dtype=float)
y = np.array([1.2, 1.8, 2.5])

print(X.shape)       # (n_samples, n_features)
print(X[:, 0])       # first feature
print(X.T @ X)       # Gram matrix
print(X.mean(axis=0))
print(X.std(axis=0, ddof=1))
処理NumPy意味
内積・行列積a @ bshapeの内側の次元を縮約
連立方程式np.linalg.solve(A, b)Ax=bを解く
最小二乗np.linalg.lstsq(X, y)residual normを最小化
固有値分解np.linalg.eigh(C)対称行列向け
特異値分解np.linalg.svd(X)rank・主成分・conditionを調べる

3. 最小二乗と行列計算

β^=arg minβy-Xβ22

形式的なnormal equationはβ^=(XTX)-1XTyですが、逆行列を明示的に作ると数値誤差が増えます。lstsq、QR、SVD、scikit-learn estimatorを使います。

Python
beta, residuals, rank, singular_values = np.linalg.lstsq(
    X, y, rcond=None
)
condition_number = singular_values.max() / singular_values.min()
print(beta, rank, condition_number)

非常に大きいcondition numberは、特徴量のscale差や多重共線性を示します。化学記述子は互いに強く相関しやすいため、標準化と正則化を検討します。

4. 正則化回帰

Ridge

minβ12ny-Xβ22+αβ22

L2 penaltyで係数を連続的に縮小します。相関した記述子を含む場合にも比較的安定ですが、通常は係数を完全な0にはしません。

Lasso・Elastic Net

minβ12ny-Xβ22+αρβ1+α(1-ρ)2β22

ρ=1がLasso、0<ρ<1がElastic Netです。Lassoはsparseな係数を作れますが、強く相関した特徴群から一つを不安定に選ぶ場合があります。

scikit-learn
from sklearn.linear_model import ElasticNetCV
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

model = make_pipeline(
    StandardScaler(),
    ElasticNetCV(
        l1_ratio=[0.1, 0.5, 0.9, 1.0],
        alphas=100,
        cv=5,
        max_iter=20000,
    ),
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

5. 分割・前処理・評価

Pipeline内でstandardizationとfeature selectionをfitすると、各cross-validation foldのtraining部分だけから変換parameterを学習できます。

指標式・意味注意
MAE絶対誤差の平均outlierの影響がRMSEより小さい
RMSE二乗誤差平均の平方根大誤差を強くpenalize
R2平均予測からの改善度test setでは負にもなり得る
反応系列をまたぐ検証

random splitは同一scaffoldや類似触媒をtrain/testへ分散し、性能を過大評価する場合があります。scaffold、基質系列、触媒系列、文献sourceなど、実際の外挿課題に対応するgroup splitを併記します。

6. PCA

PCAはcentered matrixを、分散を最大化する直交方向へ射影します。scikit-learnのPCAはcenterしますがscaleは揃えないため、単位の異なる記述子では通常StandardScalerを先に適用します。

tk=Xpkwithpk=arg maxp=1Var(Xp)
scikit-learn
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler

X_scaled = StandardScaler().fit_transform(X)
pca = PCA(n_components=0.95)
scores = pca.fit_transform(X_scaled)
loadings = pca.components_.T

print(pca.explained_variance_ratio_)
print(scores.shape, loadings.shape)

scoreはsampleの位置、loadingは元特徴量が主成分へ寄与する方向です。符号は主成分全体で反転可能なので、符号そのものではなく相対方向を解釈します。PCAは目的変数を使わない教師なし解析です。

7. SHAPによるモデル解釈

SHAPは予測値をbaselineと各特徴量の寄与へ加法分解します。

f(x)=ϕ0+j=1pϕj
読む内容
bar / beeswarmdataset全体での寄与の大きさと方向
waterfall一つのsampleがbaselineから予測値へ移る内訳
scatter特徴量値とSHAP値の関係、非線形性・interactionの候補
SHAP
import shap

explainer = shap.Explainer(fitted_model, X_background)
shap_values = explainer(X_test)

shap.plots.beeswarm(shap_values)
shap.plots.waterfall(shap_values[0])
shap.plots.scatter(shap_values[:, "B5"])
寄与は因果効果ではない

SHAPはmodelとbackground distributionに対する説明です。相関した特徴量間で寄与の配分が変わり、未測定交絡も残ります。「特徴量を操作すれば選択性が変わる」という因果主張には追加の仮定・実験が必要です。

8. 実践workflow

  1. 解析単位と外挿したいchemical spaceを定義する。
  2. train/testまたはgroup splitを最初に固定する。
  3. 欠損補完・標準化・特徴量選択をPipelineへ入れる。
  4. inner CVでhyperparameterを選び、outer testで性能を評価する。
  5. baseline、MAE/RMSE、prediction plot、applicability domainを確認する。
  6. 係数、PCA loading、SHAPの安定性をbootstrapや分割変更で調べる。
  7. data、code、random seed、library version、feature定義を保存する。

RDKit特徴量立体・場記述子を同じ表へ統合するときも、各列の由来と配座集約法を追跡できるようにします。

9. 参考資料

最終更新: