変数のクラスタリングとデンドログラム作成

回帰分析やクラス分類をする際、ある2つの説明変数間に強い相関がある(=相関係数の絶対値が大きい)とき、それらの変数のうちどちらか1つの変数を削除する必要がある。
単に、説明変数の数を減らすだけならこの方法で問題ないが、モデルに解釈な必要な変数などが消失してしまう場合がある。

このような問題に対する対策として、例えば変数同士をクラスタリング&可視化することで変数同士の傾向を把握したり、クラスタリングごとに変数を選んだり新たな変数の作成が挙げられる。
(参考:[Pythonコード付き] 相関係数で変数選択したり変数のクラスタリングをしたりしてみましょう

やったこと

RDkitの記述子のうちフラグメントに関するもの以外のものを、以下2パターンでクラスタリングしてみた。

  1. 各サンプルでとる変数の値が近いもの
  2. 相関係数の絶対値の値が近いもの

(変数を計算するための元データは、水溶解度のデータセットを使用した)

コード

モジュールのインポート〜データの準備

import os
import pandas as pd
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.figure as figure
import matplotlib.pyplot as plt
from rdkit import Chem
from rdkit.ML.Descriptors import MoleculeDescriptors
from sklearn.preprocessing import StandardScaler

#水溶解度データに含まれる1290化合物
data = pd.read_csv(os.getcwd() + '/logSdataset1290.csv',index_col=0)
smiles_list = data.index.tolist()
print(smiles_list[:5])
"""output
['CC(N)=O', 'CNN', 'CC(=O)O', 'C1CCNC1', 'NC(=O)NO']
"""

#MOLオブジェクトに変換
mols_list = [Chem.MolFromSmiles(smiles) for smiles in smiles_list]

#RDkit記述子の計算とDataFrame化
descriptor_names = [descriptor_name[0] for descriptor_name in Chem.Descriptors._descList]
descriptor_calculation = MoleculeDescriptors.MolecularDescriptorCalculator(descriptor_names)
RDkit = [descriptor_calculation.CalcDescriptors(mol) for mol in mols_list]

df = pd.DataFrame(RDkit, columns = descriptor_names)

#フラグメントに関する記述子は省略する
df = df.loc[:,:'MolMR']
df.dropna(axis=0,inplace=True)

#標準化
scaler = StandardScaler()
df.loc[:,:] = scaler.fit_transform(df)

クラスタリング(各サンプルの変数の値)

#各行が各変数に対応するように変換
df_T = df.T

# methodのリスト(今回はward法を使う)
method_list = ("average", "centroid", "complete", "median", "single", "ward", "weighted")
method = method_list[5]

plt.figure(figsize=(5,25))
Z = linkage(df_T, method=method, metric="euclidean")
dendrogram(Z, labels=df_T.index, orientation='right',leaf_font_size=10)

plt.savefig(os.getcwd()+'/dendrogram_variance.png',dpi=300)
plt.show()



クラスタリング(相関係数の絶対値の値が近いもの)

上記の方法だと、例えば変数に負の相間がある場合にはそれらは同じクラスターに分類されない。そこで、書く変数の相関係数を求め、その絶対値に応じてクラスタリングした
(注意|この方法は、変数のクラスタリング方法として一般的な手法というわけではありません)

#相関係数の絶対値でクラスタリング
df_corr = df.corr(method='pearson')
df_corr.dropna(how='all',axis=0,inplace=True)
df_corr.dropna(how='all',axis=1,inplace=True)
df_corr = abs(df_corr)

# methodのリスト(今回はcomplete, 最長距離法を使う)
method_list = ("average", "centroid", "complete", "median", "single", "ward", "weighted")
method = method_list[5]

plt.figure(figsize=(5,25))
Z = linkage(df_corr, method=method, metric="euclidean")
dendrogram(Z, labels=df_corr.index, orientation='right',leaf_font_size=10)

plt.savefig(os.getcwd()+'/dendrogram_variance_corr.png',dpi=300)
plt.show()



以上

参考

関連書籍