Morganフィンガープリントの作成

# はじめに
今回はサンプルとして適当に作った10個の化合物に対してMorganフィンガープリントを作成していきます。また、作ったデータセットに対して機械学習のインプットデータにすることを念頭に置いて全てが0の列の削除などのデータの前処理を行っていきます。

## 環境
- rdkit    2022.3.4
- pandas   1.2.5
- ipython  7.31.1

# データの読み込み
```python
# ライブラリーのインポート
import pandas as pd
import numpy as np
from IPython.display import SVG
from rdkit.Chem import AllChem, Draw, Descriptors, PandasTools
from rdkit.Chem import AllChem
from rdkit import Chem
```

以下のような化合物のSMILESが10個記載されたcsvファイルを今回はデータとして読み込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/d2cf3a1c-e1ea-fa08-ce8c-2e11a728dfad.png)

```python
# データ読み込み
df = pd.read_csv("sample_data.csv", index_col=0)
df
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/63f6a67a-2298-9089-e0fa-02e3c9383184.png)

SMILESからMolオブジェクトを生成します（分子式の描画）

```python
# SMILES→構造可視化
PandasTools.AddMoleculeColumnToFrame(df, "SMILES")
df
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/f46e710a-aa46-3783-db12-c71dbfc1ce6a.png)

```python
# エクセルに保存（エラー回避のため欠損値は0埋めしておく）
PandasTools.SaveXlsxFromFrame(df.fillna(0), "sample_data_withMol.xlsx", size=(150, 150))
```

# Morganフィンガープリントの確認
どのようにMorganフィンガープリントが生成されるのか、ここではデータフレームの4番目の分子を例にとって確認してみましょう。

```python
# 検討する分子の表示
m = Chem.MolFromSmiles(df["SMILES"][3])
m
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/1d4765d4-9636-7c14-a4b0-b4bac8e20a69.png)

```python
# ビット数を定義
nBits=2048
# ビット情報を保持するための空の辞書を作っておく
bi = {} 
# 半径2, ビット数2048（デフォルト）でフィンガープリントを作成
fp = AllChem.GetMorganFingerprintAsBitVect(m,2,nBits=nBits, bitInfo=bi)
# フィンガープリントの表示
list(fp.GetOnBits())
```

```:出力
[1,
 69,
 204,
 228,
 268,
 273,
 283,
 304,
 389,
 486,
 650,
 658,
 695,
 745,
 807,
 874,
 940,
 1057,
 1088,
 1152,
 1199,
 1380,
 1385,
 1423,
 1665,
 1750,
 1873,
 1917,
 1985]
```

ここでフィンガープリントを1つ可視化してみましょう。
```python
# リストの3番目のフィンガープリントを可視化する
img = Draw.DrawMorganBit(m, list(fp.GetOnBits())[2], bi)
img
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/78e08e12-e07b-8c7f-9957-8556390313aa.png)


# 複数の分子に対してMorganフィンガープリントを作成していく
```python
# ビットを表現するデータフレームの作成
df_bits = pd.DataFrame(index = df.index, columns=np.arange(1,nBits+1))
df_bits

for i in range(len(df)): 
    m = Chem.MolFromSmiles(df["SMILES"][i])
    fp = AllChem.GetMorganFingerprintAsBitVect(m,2,nBits=nBits)
    # フィンガープリントが存在するビット数を"1"で埋める
    for j in list(fp.GetOnBits()):
        df_bits.iloc[i,j-1] = 1
    
df_bits
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/3dc57e4b-4ff4-4263-e22b-27c8a7a0c0eb.png)

```python
# NaNを0に変換する
df_bits = df_bits.fillna(0)
df_bits
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/6ce89da1-3db8-793e-ac88-d272ccbae4bc.png)

```python
# もともとのデータフレームとフィンガープリントの情報が入ったデータフレームを結合する
# 最初に読み込んだデータフレームには分子式が描画されているので、もう一度データを読み込み
df = pd.read_csv("sample_data.csv", index_col=0)
df_add = pd.concat([df, df_bits], axis=1)
df_add
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/5e86a260-2e37-023e-468b-65a6b2d63d6c.png)


```python
# データの保存
df_add.to_csv("sample_data_withfp.csv")
```

# データフレームの前処理
機械学習の用いるデータセットは一般的に前処理の段階で全て0や1もしくは同じ数値を持った列を除きます。そのような操作を実行していきます。

```python
# 全て0の列を削除
def remove_all_zero_col(df):
    df = df.copy()
    for col in df.columns:
        if (df[col] == 0).all():
            df.drop(col, axis=1, inplace=True)
    return df

df2 = remove_all_zero_col(df_add)
df2
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/3e21941a-b0e5-cc1e-996c-af985a18e364.png)


```python
# 全ての化合物に共通するビット数1873のフィンガープリントを確認
img_1873 = Draw.DrawMorganBit(m, 1873, bi)
img_1873
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/4d29c847-4217-8c1a-94f1-fbe0c052aec3.png)

```python
# 全て1の列を削除
def remove_all_one_col(df):
    df = df.copy()
    for col in df.columns:
        if (df[col] == 1).all():
            df.drop(col, axis=1, inplace=True)
    return df

df3 = remove_all_one_col(df2)
df3
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/7b3e7457-e7fa-2c50-cb5c-d4d43130910e.png)

```python
# この段階で保存
df3.to_csv("before.csv")
```

また機械学習では全て同じ値の説明変数は1つしか要らないので、説明変数が全て重複している列を取り除いていく。（行の重複を削除する方法を参考にする。列の重複を削除する方法は分かりませんでした。どなたかご存じであればコメントいただければ幸いです。）


まずは転置して行と列を入れ替えます。
```python
df3.T
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/0e4087df-de83-265f-1a6c-50bc8f2d98b1.png)

重複している行を確認します。
```python
df3.T.duplicated()
```

```:出力
df3.T.duplicated()
```

重複している行を削除します。

```python
df4 = df3.T.drop_duplicates()
df4
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/1ecb4caf-46f2-12e5-b37b-1ca394a0469f.png)

再度転置して、もともと行だったデータを行に、もともと列だったデータを列に変換します。

```python
new_df = df4.T
new_df
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057114/0321e1b1-e292-3add-dcb6-dfb7aa155cce.png)

これにてデータの前処理は終了です。このデータフレームを用いて機械学習の予測モデルの構築などが出来そうです。

```python
# 最終的なデータセットを保存
new_df.to_csv("after.csv")
```

## 参考
- [RDKitでフィンガープリントの可視化](https://future-chem.com/rdkit-fp-visualize/)
- [Fingerprintの可視化について](https://datadriven-rnd.com/2021-02-09-225503/)
- [RDKitで分子のDescriptorを表示](https://zenn.dev/poclabweb/books/chemoinfomatics_beginner/viewer/lesson04_02_2_rdkit)
- [Python】表データの重複確認と重複を削除する方法](https://prograshi.com/language/python/python-pandas-dataframe-duplicate/)
- [【Python】pandasで全て0の列と行、一つでも０の列と行を削除する](https://laid-back-scientist.com/pandas-remove0)