イチゴピューレの化学測定データで遊んでみる（PandasとSeabornでグラフ化）

# はじめに
この記事ではイチゴピューレ（ピュアなものとイチゴ以外の何かが混合されたものがある）を赤外分光法によって測定したデータを用いてグラフをSeabornで描きます（今回は機械学習とかの話はしません）。
データは[983 Mid-infrared (MIR) spectra of fresh fruit purees](http://csr.quadram.ac.uk/wp-content/uploads/MIRFruitPurees.zip)からダウンロードできます。なお、このデータの収集とその分析については元論文"Use of Fourier transform infrared spectroscopy and partial least squares regression for the detection of adulteration of strawberry purees" Holland JK, Kemsley EK, Wilson RH. (1998). Journal of the Science of Food and Agriculture, 76, 263-269.に詳しい説明があるようです（読めていません）。
# 元論文の研究に関連する話
元論文の研究は「バイオインフォマティクス」とか「ケモインフォマティクス」とか「メタボローム解析」と呼ばれている分野に関係するものであり、有名なものとして、ワインの測定データからそのワインの品質を予測する問題・尿の測定データから病変の有無を判別する問題があります。
あまり厳密ではない話なのですが気持ちとしては、「ワインの味は中に入っている物質の種類・量によって決まるので、中に入っている物質を知ることができればワインの味がわかる。」とか「がん患者の体の中での物質の代謝は健康な人のそれとは異なるので、体から出てきた尿に含まれる物質も違ってくる。だから、逆に尿の物質からがん患者なのか健康な人なのかわかるはずだ。」みたいな話です。
# 少しだけ化学の話
あまり興味のある人はいないかなと思うのですが、測定値の意味を理解するためにざっくり説明します。
今回利用するデータを取得するためにMid-IR Spectroscopyという手法を用いています。これは物質ごとに光の吸収特性の違うことを利用した測定方法です。イチゴピューレの場合、中に入っている物質がピュアなものとピュアでないもので異なるため、結果として光の吸収のされ方が違ってきて測定値に差が出てきます。今回のデータではWavenumbersという列があるのですが、これは「波数」と呼ばれているもので、波長の逆数です。
# 何をするのか
多くのサンプルについての測定結果があるため、ピュアなものとピュアでないものの平均を取り、その差があるのか直感的にわかるようにグラフ化することを目指します。今回はデータの読み込み～加工・集計、グラフの描画までを行いますが、やっていることはだいたいデータの加工です。以下の手順で進めます。
1. データの読み込み～データの加工（元のCSVが処理しづらい形なので良い感じに）
2. データの集計（ピュアなものと混合されたものについて各波長の平均値を算出）
3. 集計結果をグラフ化
# 利用するライブラリなど
利用するものは以下の通りです。Windows10 Pro上のAnacondaでJupyterLabを利用して行っていきます。

- Jupyter Lab（Jupyter NotebookでもOK）
- os（ファイルを保管しているところに移動するために利用）
- re（データを加工するために利用）
- Pandas（CSVの読み込み・加工に利用）
- Seaborn（グラフを書くために利用）

# 実際のデータ処理
今回の処理はJupyterLabで行っていきます。
## 用意
Anaconda Promptを開いて、 

```
jupyter lab
```
でJupyterLabをブラウザで開けます。Jupyter Notebookでも良いかなと思うのですが、私はJupyterLabの方が使いやすい気がするので最近はJupyterLabを使っています。以下のようにして新しいNotebookを作ります。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/0aa5f569-3909-ef1e-3eb9-eb96b623d2fc.png)

Notebookを作成したら以下のように入力してCtrl+Enterで実行します。

```python:
import os
import re
import pandas as pd
import seaborn as sns
```

まず、必要なライブラリをimportしました。
## データの読み込み～データの加工
### CSVの読み込み
[ダウンロード](http://csr.quadram.ac.uk/wp-content/uploads/MIRFruitPurees.zip)して適当なフォルダに保存したCSVをPandasで読み込みます。

```python:
os.chdir('C:\\Users\\MKX\\Desktop\\MIRFruitPurees')
```
CSVを保存したフォルダに移動します（今回はデスクトップにフォルダを用意してその中にCSVを保存しています）。

```python:
mir_data = pd.read_csv('MIR_Fruit_purees.csv')
mir_data.head()
```
CSVを読み込んで先頭5行を表示してみます。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/27f9fee9-8064-6da1-421f-22657c60c493.png)

思わず「あ～～～やだなあ」と言ってしまう感じのデータの持ち方をしているので、pd.meltで処理しやすい形に整形しています。
### データの整形
以下のようにすることで処理しやすい形に整形することができます。

```python:
mir_data = pd.melt(mir_data, id_vars=['Wavenumbers'], value_vars = mir_data.columns.values[1:])  # 縦持ちに整形
mir_data.head()
```
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/ae818873-23b8-6349-149c-e6dc3d24b0a9.png)

良い感じに変形できました。これで後の処理が楽になります。

### 一度グラフを描いてみる
variableの列がNON-Strawberry.6のものについてSeabornでグラフを描いてみます。

```python:
sns.lineplot(x='Wavenumbers',y='value', hue='variable', data = mir_data[mir_data['variable']=='NON-Strawberry.6'])
```
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/9e3706c7-221c-aa12-adb7-f0240fb144fc.png)

それっぽいグラフができました。

## データの集計
ここではピュアなものとピュアでないものについて平均的にどのように違いがあるのかをグラフで表現することを目指します。
### 集計用の列を追加する
このままでは処理しづらいので集計時に便利なように一列追加します。

```python:
mir_data['Strawberry?'] = mir_data['variable']  # 処理しやすくするためにStrawberryとNON-Strawberryを区別するための列を用意
mir_data.tail()
```
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/90cf5d7b-65b2-3131-96e0-dc2ca541ad06.png)

このStrawberry?列のNON-Strawberry.xxx（とStrawberry.xxx）の.xxxを取り除く処理を次に行います。まず関数を定義して、それを列全体に適用するという方法でこれを行います。
まずは関数を定義します。

```python:
# NON-Strawberry.10の.10はいらないので処理するための関数
def remove_dot_and_num(x):
    return re.sub('.\d+', '', x)
```

うまくいくのか試してみます。

```python:
remove_dot_and_num('aaaa.123')
```
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/6e77e78e-d47d-5e04-d7e7-f8b87bdabc4d.png)

確かにうまく取り除けました。この関数をStrawberry?の列に対してpd.Series.mapを使って適用します。

```python:
mir_data['Strawberry?'] = mir_data['Strawberry?'].map(remove_dot_and_num)  # 新しく作ったStrawberry?列全体に関数を適用
mir_data.tail()
```
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/a45a646f-f6be-0a10-6ea4-c58b807043af.png)
良い感じに列全体に適用できました。
### 平均値の計算
Wavenumbers・Strawberry?ごとに平均値を計算します。

```python:
mean_by_wn_straw = mir_data.groupby(['Wavenumbers', 'Strawberry?'],as_index=False).mean()  # Wavenumbers（波数）・Strawberry?ごとに平均値を計算
mean_by_wn_straw.head(10)
```
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/587b3729-8147-c387-c932-4d465428c2e9.png)

ここでas_index=Falseにしておかないと以下のようになり、Seabornでうまくグラフ化できないようになってしまうので注意が必要です。
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/038fe733-1556-cbea-90f3-6947455cc45e.png)

## 集計結果をグラフ化
グラフを作ります。

```python:
sns.lineplot(data = mean_by_wn_straw, x = 'Wavenumbers', y = 'value', hue = 'Strawberry?')
```
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213259/da5cb19f-859a-65e7-a0d4-089573e8ac74.png)

1200 cm<sup>-1</sup>から1250 cm<sup>-1</sup>あたりと1600 cm<sup>-1</sup>周辺・1750 cm<sup>-1</sup>周辺に差のある気がします。この波数に注目すればピュアなものとピュアでないものを分けられそうです。この波数に関係する物質がピュアなものとピュアでないもので含まれる量に違いがあるのでしょうか？

# 感想・今後の展望
データを分析しやすい形に変えるところで疲れてしまったので今回はここまでです。元論文ではPLS回帰でピュアなものとピュアでないイチゴピューレを判別しています。データをガチャガチャして良い感じに判別できないかなど遊んでみようと思います。
# 参考文献など
参考文献・役に立ちそうな情報をまとめておきます。
## データの出典元の論文
"Use of Fourier transform infrared spectroscopy and partial least squares regression for the detection of adulteration of strawberry purees" Holland JK, Kemsley EK, Wilson RH. (1998). Journal of the Science of Food and Agriculture, 76, 263-269.
## データ処理・グラフ化の操作について
[Python, pandas, melt-ねこゆきのメモ](http://nekoyukimmm.hatenablog.com/entry/2015/04/02/115045)
pd.meltの使い方について参考にしました。
[Pandas の groupby の使い方-Qiita](https://qiita.com/propella/items/a9a32b878c77222630ae#簡単な-groupby-の使い方)
as_index=Falseについて参考にしました。

## 役に立ちそうな情報
[Spectral Features Characterizing Rice Wine “Sake” Variety Using Mid-Infrared Spectroscopy](https://www.jstage.jst.go.jp/article/jsfe/16/4/16_279/_pdf/-char/ja)
日本酒を赤外分光法で分析しようという話についてです。
[Core Science Resources at QI](https://csr.quadram.ac.uk)
いくつかの食品関連のデータセットがあります。今回のデータもここからダウンロードしています。