Pubchemからexprimental propertiesを抽出する方法

## はじめに
Pubchemという化合物のデータがたくさん載っているサイトがあります。検索結果一覧をCSVでダウンロードできたりして便利です。
さて、化合物固有のページには実験値の情報はありますが、この一括ダウンロードしたCSVには融点、沸点といった実験値が含まれていません。一つ一つページを手作業で確認するのは面倒なのでなんとかならないでしょうか？

https://pubchem.ncbi.nlm.nih.gov/

### csvの中身
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/0370e7d7-0de2-3370-db61-44ab55133ff0.png)
csvには識別子、名称、構造および自明なパラメータのみが含まれます。Pubchemから情報を取得するためのライブラリ、pubchempyもありますが、実験値の取得はサポート外です。

### 実験値は固有のページにある

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/12eea776-ec52-58b3-bf97-9c6f6d4e149e.png)
化合物固有のページには、実験値を含む物理パラメータが含まれます。


## シナリオ
今回はデータのある2153化合物の引火点を取得してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/f0bfd0c3-1c9f-e904-9a0d-298c5ec0e76a.png)

### 事前準備
まずcsvをダウンロードして、不必要な列は省いておきます。少なくともCID列とSMILESと名前列だけは残しておくのが良いと思います。
一応言っておくと、1列目のCIDはPubChem上で化合物に与えられている固有の識別番号です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/6bffd366-dacb-f96e-e500-203fcecc92fc.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/4a1745db-d836-533e-74d4-897440b318c6.png)

## 手順

### 方針
まず化合物固有のページに問い合わせをして、引火点の情報(文字列)を抽出する。JSONエンドポイントがあり、プログラムで扱いやすい形式のレスポンスが返ってきます。
- 華氏温度(F)の場合→摂氏温度に直して数値を返す
- 摂氏温度(C)の場合→数値を返す
- その他→返り値をそのまま返す


### コード
```py:引火点問い合わせる関数

def extract_number(s):# 先頭の数値を抽出する処理
    import re
    match = re.match(r'^-?\d+', s)
    if match:
        return int(match.group())
    else:
        return None

        
def cid_flashpoint_degc(CID): #CIDから引火点を取得する
  import requests
  coumpund_data_url = 'https://pubchem.ncbi.nlm.nih.gov/rest/pug_view/data/compound/{}/JSON/'
  compound_info = requests.get(coumpund_data_url.format(CID))

  for section in compound_info.json()['Record']['Section']:
      if section['TOCHeading']=="Chemical and Physical Properties":
        for sub_section in section['Section']:
            if sub_section['TOCHeading'] == 'Experimental Properties':
                for sub_sub_section in sub_section['Section']:
                    if sub_sub_section['TOCHeading']=="Flash Point":#ここで取得したい物性を入力
                        fp_str=sub_sub_section['Information'][0]['Value']['StringWithMarkup'][0]['String']
                        #返り値がセ氏温度になるように調整
                        if extract_number(fp_str) == None:
                          return fp_str
                        elif ' °C' in fp_str:
                          return extract_number(fp_str)
                        elif ' °F' in fp_str:
                          print(fp_str)
                          return round((extract_number(fp_str)-32)*5/9,1)
                        else:
                          return fp_str
                        break
                return "No data"

```



### 使用例

```py:
import pandas as pd
df = pd.read_csv('compounds.csv', sep=',',skiprows=1, names = ["CID","Name", "Synonym", "MW","SMILES","IUPAC","Charge","covalentunit"]) #csvをまず読み込む
df["flashpoint"]=df["CID"].apply(cid_flashpoint_degc)
df.to_csv('fp.csv')#csv出力
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/85069163-8a4b-a8c8-9950-fe845fe708ca.png)
といった感じで、物性値を自動的に取得できるようにしました。また、いくつかの化合物では但し書きがあったり、範囲で書かれていたりと表記揺れもあることがわかりました。
今回はFlash Point を取得していますが、コードを少しいじればほかの物性も取得できます。

## まとめ
- 実験値を取得するには、requestsでJSONエンドポイントに問い合わせる
- 固有のCIDを使って問い合わせて、レスポンスから所望の物性値を掘り出す
- 一括ダウンロードしたcsvのCID列を使用すると一気に取得可能になる


### 参考にしたページ
https://github.com/mcs07/PubChemPy/issues/16