任意の数のピークがあるスペクトルに対して簡単にフィッティングできる Python ライブラリを作った

# 理系の 1-3 年生の頃によくやる実験の例の作業についてなんやが

X線構造解析や未知の核種からの線スペクトルを解析して核種を特定する実験などなど。
ガウス関数フィッティングをしなければいけない機会に出くわすことは必至です。
もちろん y でソートして y の最大値、つまりピークトップの y を強度, x を波長などとすれば簡単なのだが、ピークがデルタ関数ではない以上、良くないでしょう。

スペクトルに現れているピークが明らかに1本であれば、それほど頑張らずにガウス関数フィッティングもできますが、いろんな線源の重ね合わせによるスペクトルの場合、重ね合わせの数だけガウス関数でフィティングする必要があります。そして、同種の実験データが >数十 ある場合、それぞれのデータを見て手作業でフィッティングしていくのは地獄の所業じゃ！

そこで、<b>スペクトルを描画して、ピークをマウスでドラッグないしクリックでピークの位置のおおよその位置を教えて、任意の数のガウス関数フィッティングができる Python ライブラリを作りました。(~~現在も更新中です~~)

GitHub repository: [passive-radio/peak_fitter_auto](https://github.com/passive-radio/peak_fitter_auto)

特徴は上のリポジトリーページからも見ることができますが、おそらく簡単にフィッティングできるツールか何かないかなと既にタブを数十も開いている状況だと思いますので、以下でこのライブラリの特徴と何が出来るかを紹介します。


# Peak Fitter Auto の特徴

- スペクトルを読み込んで描画。ウィンドウ上でマウスドラッグやクリックでフィッティングしたいピークの場所を教えてフィッティングさせる
- x,y の ascii フォーマットファイルになっていなくても大丈夫。画像データ(回折実験の撮像など)からもフィッティングできる
- フィッティングの結果をスペクトルの上に描画する
- ピークの位置、高さ、バックグラウンド、幅を取得

学部4年生の実験(卒論研究)レベルからは、実験装置についてくるメーカー製のソフトウェアや研究室で使っている自前の解析ソフトウェアの出番になってくると思うので使わなくなると思いますが、1~3年生の実験解析に対しては煩雑な作業を簡単に行えるツールになっていると思います。

## 対応しているスペクトルデータのフォーマット

x | y
--- | ---
some header contents |
... |
0 | 1
1 | 13
2 | 30
3 | 43
4 | 31
5 | 11
...|...
some fotter contents |
... |

こんな感じであれば大丈夫です。実験装置から吐き出されるデータにはヘッダー、フッターがついているものや、違う列に付属情報の載ったものもありますが、その場合はヘッダーの行数や x,y の列を指定して下さい。

![sample.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1419783/f24e9a33-7f25-c046-4704-07510b4693c8.jpeg)

<center><small>こういうデータでもOK</small></center>

# 実際のフィッティングの様子

example_usage.py ではサンプルデータを用いて実際にフィッティングを行います。フィッティングしたいファイルを指定して実行すると、以下のような画面が出力されます。
![2021-12-21 21_04_44-Figure 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1419783/80d1ac44-5ff2-f855-ad45-c25542f4ff17.png)

マウスドラッグでピークを囲うように指定します。左右がズレたと思えば再度マウスドラッグで指定できます。<b>~~荒く場所を教えてあげればフィッティングしてくれるのでだいたいでOKです。~~</b>
<b>追記: 荒くて良いですが、おおよそピークの半値幅をとるように選択すると間違いがないです。</b>
選択ができたと思えば右クリックして確定、さらにピークがあればマウスドラッグで選択、右クリック確定を繰り返します。

![2021-12-21 21_05_08-Figure 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1419783/32b94e66-6e9a-4245-00c2-0b26fef1368d.png)

選択が終了すればウィンドウを閉じます。すると、フィッティング結果をプロットした画像が出力されます。
コマンドライン上には各ピークの位置、強度、幅、バックグラウンドが出力されます。

![2021-12-21 21_05_28-Figure 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1419783/bec7a203-104e-8d66-7dee-dfbca0306a19.png)

また、念の為ガウス関数以外にも1変数n次多項式近似もできるようになっています。使う場面はないのだけど。

# 実用的な使い方

GitHub のリポジトリにある example_usage.py では、各ピークの情報を保存するコードも書いています。
選択した数だけピークにフィッティングを行う 関数 click_guess, drag_guess は、ピークの位置情報や幅、グラウンドの高さを Pandas DataFrame 形式で返します。

なので、os や glob モジュールを組み合わせれば、スペクトルデータのあるディレクトリを指定して、ディレクトリ内のスペクトルが載っている全 csv ファイルに対して、連続で解析することもできると思います。DataFrame で返ってくるので csv ファイルに保存して後からピークを一覧で確認することもできます。
スペクトルデータの csv ファイル名を実験のセットアップパラメーターなどにしておけば、各スペクトルのファイル名をパースして、ピークを保存する csv のカラムにパラメータも記述できるでしょう。
ここまで出来ればデータ解析はだいぶ簡単になりますよね。そして、測定中に「いや、こんなに沢山データとっても解析大変になるだけじゃん」と言われても、「あっ。。。」って頷かせられますね！

あっもちろんレポートなどで使う際は、ライセンスを表記することは日頃から気をつけておきましょう。

## 多数の実験データに対して解析を行うには

このライブラリが行うのは、あくまでスペクトルデータが与えられたときに任意の数のピークを見つけてフィッティングするだけ。連番データとかに対して自動でフィッティングを実行するには、別途少しのコーディングが必要になります。実装は難しくないでっせ。

## ライブラリの今後

<b>追記 2022/03/28</b>
このライブラリから派生して、 Wavelet を用いてスペクトルのピーク検知をする新しいプロジェクトができました。 See the GitHub repository [here](https://github.com/passive-radio/find-peaks.git)

Wavelet 変換で行う畳み込み積分を畳み込みニューラルネットワークの畳み込み層に適応させ、トレーニング可能なピーク検知モデルを作成することが目標です。従来のピーク検知方法に比べより高精度なピーク検知ができるようになることが期待されます。
(まだ、CNN に適応できてはいない)

## さいごに

お困りごとにドンピシャ刺さっていて、ぜひ試してみてね！
くそコードなので、PR する気力も湧かんわ状態かとは思いますが、なにか反応あると嬉しいです。
GitHub repository: [passive-radio/find-peaks](https://github.com/passive-radio/find-peaks)