ケモインフォマティクスで学ぶPythonの変数とデータ型

# はじめに

製薬企業の仕事では、化合物の構造を扱うことがよくあります。
自社で合成した新薬候補の化合物やその代謝物、および生体内にもともと存在する内因性の代謝産物（アミノ酸、糖、脂質など）の濃度測定や構造解析をするスキルは重要です。

そこでここでは、生体内に存在する脂質の網羅的解析であるLipidomics（リピドミクス）を題材としてPythonのプログラミングについて解説していきます。
脂質は、様々な構造を持つ分子種が生体内に存在しており、*in silico*で構造を生成できる分子種は100万種を越えます。
こうした分子種の構造を一つ一つ記述したり、分子量や極性などの物性値を算出したりするのは手作業では現実的に難しく、プログラミングが必須になります。

脂質の構造や物性値をプログラミングで扱えるようになれば、新薬候補化合物を対象とするケモインフォマティクスにも応用が利きますので、是非習得してもらえればと思います。

今回は、「変数とデータ型」について解説していきます。
ケモインフォマティクスの実践例を中心に説明していきますので、基本を確認したいという人は以下の記事を読んでからこの記事を読んでみてください。

[製薬企業研究者がPythonの基本的な記述ルールについてまとめてみた](https://qiita.com/yukiya285/items/109e2d26234d80566299)
[製薬企業研究者がPythonにおける変数についてまとめてみた](https://qiita.com/yukiya285/items/d63d5071ca32254b2735)
[製薬企業研究者がPythonで使われる演算子についてまとめてみた](https://qiita.com/yukiya285/items/ac774efe216ecb97def9)

環境構築については以下の記事を読んでみてください。

[製薬企業研究者のためのAnacondaインストール方法](https://qiita.com/yukiya285/items/6bc3bcef00f7d13c94f1)


# 文字列と数値

## 変数の作成と出力

`変数 = 値`とすることで、新しい変数を作成することができます。
また、`print()`を使うことで、かっこ内のオブジェクト（変数の値やプログラムの実行結果など）を出力することができます。
`# `以降の文字列はコメントとして認識され、プログラムの実行範囲からは除外されます。
スクリプトの中にメモを書いたり、エラーが出る部分を実行されないようにしたりするときに使えます。

```python
lipid_class = 'FA' # 文字列
Cn = 16 # 数値
Un = 0 # 数値

print(lipid_class) # 変数「lipid_class」の値を出力
print(Cn) # 変数「Cn」の値を出力
print(Un) # 変数「Un」の値を出力
```

以下に示すように、複数の変数を1行で作成することもできます。
また、`print(オブジェクト1, オブジェクト2)`とすることで、`オブジェクト1 （半角スペース）オブジェクト2`と出力されます。
半角スペースを別の文字や記号にしたい場合は、`sep=`で変更できます。
`sep=''`とすると、`オブジェクト1`と`オブジェクト2`がスペースなしで連結されて出力されます。

```python
Cn, Un = 16, 0 # 「Cn = 16、Un = 0」という意味
print(Cn) # 「16」と出力される
print(Un) # 「0」と出力される
print(Cn, Un) # 「16 0」と出力される
print(Cn, Un, sep='と') # 「16と0」と出力される
```

### 変数名のつけ方と注意点

まず、変数名は基本的に英単語を使い、数字から始まる変数名をつけることはできません（2文字目以降であれば数字を使うことも可能です）。変数にどんな値が格納されているのか一目で分かる変数名にすると良いです。
複数単語になる場合は、`_`（アンダースコア）で区切り、各単語は基本的には全て小文字で書きます。

変数名をつけるときは、あらかじめPythonで定義されているキーワード（予約語）を使わないように注意する必要があります。
予約語は、以下のスクリプトで確認することができます。
（`import`など、細かいところは今のところわからなくても大丈夫です。以下のスクリプトをただコピー＆ペースとして実行して確認してもらえればと思います。）

```python
import keyword
import pprint


pprint.pprint(keyword.kwlist, compact=True)
```

実行結果は以下になります。
以下に含まれるものは、変数名にしないようにしましょう。

```
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue',
 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global',
 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise',
 'return', 'try', 'while', 'with', 'yield']
```

## 文字列に関する注意点とデータ型の確認方法

文字列は、`'`（クォーテーション）で囲む必要があります。
逆に言うと、クォーテーションで囲まれた数字も文字列として扱われます。

```python
Cn_int = 16 # 数値としての「16」
print(type(Cn_int)) # <class 'int'>

Cn_str = '16' # 文字列としての「16」
print(type(Cn_str)) # <class 'str'>
```

`type`を使うことで、かっこ内のオブジェクトのデータ型を確認することができます。

### エスケープシーケンス

クォーテーションの中でクォーテーションを書いたり、改行したりしたい場合のために、特別な文字列（エスケープシーケンス）が用意されています。
以下に例を示します。

```python
print('molecular species: FA 16:0')
print('\'molecular species: FA 16:0\'') # クォーテーションを入れる
print('molecular species: \nFA 16:0') # 改行を入れる
```

上の例では、`\'`は`'`そのものを表しています。なので、文字列を囲むクォーテーションとは別にクォーテーションが出力されます。
また、`\n`は、改行を示しています。なので、`print`による出力結果で`molecular species: `の後に改行が入ります。

### 文字列の結合

ここで、`lipid_class`という変数に格納した`FA`というのは、「fatty acid」すなわち「脂肪酸」の略です。
`lipid_class`というのは、日本語でいうと「脂質クラス」で、脂質のカテゴリーを示します。
また、`Cn`は「number of carbon atoms」すなわち炭素原子の数（炭素鎖の長さ）を、
`Un`は「number (degree)  of unsaturation」すなわち不飽和度（二重結合の数）を示しています。

脂質クラスの中でも、脂肪酸は一番単純な構造で、`Cn`と`Un`を指定すれば、構造がほぼ決まります。
他の脂質クラスの多くは、グリセロールなどの骨格に脂肪酸が結合した化学構造となっていて、骨格部分が脂質クラスを特徴づけるものとなっています。
脂質クラスと炭素原子数、不飽和度を組み合わせることで、脂質の分子種がほぼ決まります。
そこで、`lipid_class`と`Cn`と`Un`を文字列として結合することを考えます。

ちなみに、脂肪酸で炭素原子数が16、二重結合数が0の分子種はパルミチン酸（palmitic acid）になります。
パルミチン酸の化学構造などは、以下のリンク先のページに掲載されていますので、適宜参照してください。
[Palmitic acid (FA 16:0) | LIPID MAPS Structure Database](https://www.lipidmaps.org/data/LMSDRecord.php?LMID=LMFA01010001)

```python
lipid_class = 'FA'
Cn = 16
Un = 0

molecular_species = lipid_class + ' ' + str(Cn) + ':' + str(Un)
print(molecular_species) # 「FA 16:0」と出力される
```

`+`を用いることで、文字列を結合させることができます。
ここで、`' '`は半角スペースです。
また、`str`は「string」の略で、かっこ内のオブジェクトを文字列のデータに変換します。
ここでは、`Cn`と`Un`が数値なので、このままだと文字列として結合させることができないからです。
さらに、リピドミクスの分野では、`Cn`と`Un`を`:`でつなぐのが慣習となっています。

文字列となっている数字を数値型のデータに戻すためには、`int`または`float`を使います。
`int`は「integer」の略で整数を、`float`は小数点つきの数値（浮動小数点数）を指します。

```python
Cn = 16

Cn_str = str(Cn)
Cn_int = int(Cn_str)
print(type(Cn_str)) # <class 'str'>
print(type(Cn_int)) # <class 'int'>


exact_mass = 256.2402 # パルミチン酸の精密質量
exact_mass_str = str(exact_mass)
exact_mass_float = float(exact_mass_str)
print(type(exact_mass_str)) # <class 'str'>
print(type(exact_mass_float)) # <class 'float'>
```

`+`演算子を数値のデータに対して用いる場合と、文字列のデータに対して用いる場合との違いをまとめると、以下のようになります。

```python
Cn = 16
Un = 0

print(Cn + Un) # 数値の「16」
print(type(Cn + Un))

print(str(Cn) + str(Un)) # 文字列の「160」（1と6と0が並んだ文字列）
print(type(str(Cn) + str(Un)))
```

数値の変数同士を足した場合は、普通に足し算が行われますが、文字列の変数同士を足した場合は、文字列の結合になります。
（`Cn`と`Un`を足し算することは、化学としては何の意味もありませんが、ここではプログラムの動作を示すために例として挙げています。）

また、文字列の結合（文字列の中への変数の値の埋め込み）は、以下のように書いても行うことができます。

```python
lipid_class = 'FA'
Cn = 16
Un = 0

molecular_species = '{0} {1}:{2}'.format(lipid_class, Cn, Un)
print(molecular_species) # こちらも「FA 16:0」と出力される
```

クォーテーションの中に`{}`を書いておいて、`format`のかっこ内に変数を並べておき、`{}`内の0番、1番、2番の順番で`format`のかっこ内の左の変数から埋め込まれます。
プログラミングの世界では、1番ではなく、0番から連番が始まることが多いので、プログラミングを始めたての頃は注意が必要です。

さらに、Python 3.6以降では、「f-string」といって、以下のように、より簡便な書き方で文字列に対する変数の埋め込みができるようになりました。

```python
lipid_class = 'FA'
Cn = 16
Un = 0

molecular_species = f'{lipid_class} {Cn}:{Un}'
print(molecular_species)
```

最終的に作りたい文字列を`f'文字列'`としておいて、`{}`の中に変数名を入れておくだけで、`{}`の部分が指定された変数で置き換わります。

### 文字列の置換

`replace`を用いることで、特定の文字列を別の文字列に置換することができます。

```python
molecular_species = 'FA 16:0'

print(molecular_species.replace(':', '_')) # 「:」（コロン）を「_」（アンダースコア）で置き換える
print(molecular_species.replace(' ', '')) # 半角スペースを削除する
```

## 応用：SMILES記法

化合物の構造を記述する方法として、「SMILES (simplified molecular input line entry system) 記法」というものがあります。
以下のように、文字列だけで化学構造を記述することができます。

```python
smiles_pa = 'OC(' + 'C' * (Cn - 1) + ')=O' # 'pa'は'palmitic acid'の略
print(smiles_pa)
```

上のように、SMILES記法では、水素原子（H）を使わずに、化学構造を記述します。
SMILES記法なら、`Cn`の値が変わっても、自動的に分子構造を記述することができます。
`*`は、数値の掛け算だけでなく、同じ文字列を繰り返すときにも使えます。

次に、炭素原子数が18で、二重結合数が2のリノール酸という分子種について考えてみます。
[Linoleic acid (FA 18:2) | LIPID MAPS Structure Database](http://www.lipidmaps.org/data/LMSDRecord.php?LMID=LMFA01030120)

```python
smiles_la = 'OC(CCCCCCC/C=C\C/C=C\CCCCC)=O' # リノール酸（linoleic acid）
```

二重結合は`=`を使って記述します。
`/`や`\`は二重結合が*cis*なのか*trans*なのかを示し、二重結合を形成する炭素原子の前または後ろの記号が異なる向きなら*cis*、同じ向きなら*trans*となります。

```python
smiles_la = 'OC(CCCC/C=C\C/C=C\CCCCCCCC)=O' # リノール酸（linoleic acid）

smiles_la_oxidized = smiles_la.replace('/C=C\C', 'C(O)CC')
print(smiles_la_oxidized)
```
このように、上でも触れた`replace`を用いて、二重結合部分の酸化を表現することができます。
ちなみに、`.replace('/C=C\', 'C(O)C')`としても置換できそうに見えますが、`'/C=C\'`の後ろの部分の`\'`は上でも触れたエスケープシーケンスで、文字列を閉じるためのクォーテーションが文字列中のクォーテーションと認識されてしまい、構文エラーが出てしまいます。
なので、ここでは、右の炭素原子をもう一つ入れて、`.replace('/C=C\C', 'C(O)CC')`としました。


# 真偽値

真偽値（ブール型）は、`True`または`False`のどちらかになるデータ型を指します。
複数の変数が同じかどうかを比較したり、ある条件が成り立つかどうかを調べたりするときに使えます。

```python
palmitic_acid = 'FA 16:0' # パルミチン酸（炭素数16の飽和脂肪酸）
stearic_acid = 'FA 18:0' # ステアリン酸（炭素数18の飽和脂肪酸）

print(molecular_species == palmitic_acid) # True
print(molecular_species == stearic_acid) # False
```

炭素数が16で二重結合数が0の脂肪酸は、「palmitic acid（パルミチン酸）」で、「stearic acid（ステアリン酸）」ではないということになります。


# まとめ

ここでは、Pythonの変数とデータ型について、ケモインフォマティクスで使える実践的な知識を中心に解説しました。
もう一度要点をおさらいしておきましょう。

- `変数名 = 値`とすることで変数を作成できます。
-  文字列は`+`演算子で結合することができます。文字列への変数の埋め込みは、f-stringなども使えます。化合物名を機械的に生成するときなどに使えます。
-  `文字列 * 数字`で指定回数だけ同じ文字列を繰り返すことができます。SMILES記法で炭素数を指定するときなどに使えます。

続いて、Pythonのデータ構造（リスト、辞書など）について、以下の記事で解説しています。

[ケモインフォマティクスで学ぶPythonのデータ構造](https://qiita.com/yukiya285/items/874c9119a9bcf93afbfa)



# 参考資料・リンク

[意外と少ない！？製薬会社でのプログラミングに必要な「最低限」の知識](https://pharma-engineer.com/basic-programming/minimum-information/)