RRUFFのラマンデータで遊ぶ の履歴(No.8)


RRUFFのラマンデータで遊ぶ(20251212作成:最終更新20251229)

rruff_Raman_search_anorthite_example.png
天然anorthiteの測定ラマンスペクトルで検索して出てきたRRUFFのスペクトルを比較しているところ

前書き

 RRUFFはアリゾナ大学のDowns教授らが作成している主に鉱物のラマンスペクトルのオープンデータベースで、同試料の組成分析、IRスペクトルや粉末XRDパターンも公開されています。最近リニューアルされました。このサイトでは鉱物名や化学組成で検索して、出てきた試料のラマンスペクトル等を見ることができますが、手持ちの観察スペクトルデータやピーク位置(ラマンシフト)を使っての検索機能まではありません。ラマンスペクトルのデータベース検索については、別途CrystalSleuthというプログラムが同じサイトで古くから公開されています(現在はOther databasesのSoftwareのところ)。ただしCrystalSleuthはWindows専用で、また2008年で更新が止まっていて、付属データベースもそのころの古いままのようです。さらに私はMacユーザーなので利用しづらい問題もあります。そのため簡易に検索できるようなプログラムを自作することを以前から考えてはいたのですが、この機会に作ってみることにしました。また最終的には自分の持っているスペクトルデータも追加して、合わせて利用できるようにしたいと思ってます。

RRUFFラマンデータ

 RRUFFのラマンスペクトル集はRRUFFのサイトから自由にダウンロードすることができます。いくつかのデータセットがありますが、私は最もサイズの大きいexcellent_unoriented.zipをダウンロードしました。解凍してみると2025/12/03の時点で11,413点のファイル(テキストファイル)がありました。excellent_unorientedのファイルを詳しく見ると、測定したデータ(Data_RAW)と処理したデータ(Data_Processed)があるので、実際に検索に使うスペクトルとしてはその約半分となります。このデータセットの相対波数範囲は100くらいから1300 cm-1くらい(ダイヤモンドやグラファイトなどはもう少し高い波数まで)になります。4000 cm-1くらいまでの広い波数範囲が欲しい場合はLR-Raman.zipの方をダウンロードしてください。
 ファイルをいくらか読んでみると、フォーマットは大体は統一されているのですが、全く同じではないので、読み込む時に注意が必要なので、以下に注意する点をまとめました。

簡易検索プログラムの作成方針

 プログラムはpythonで作成し、GUIにはTkinterを使うのですが、以下の方針で作ることにしました。

index.txtファイルの作成

 最初にRRUFFのラマンデータファイルを開いてプロットして、平滑化処理やピーク検出を試すテストプログラムを作成しました。それを使っていくらかのファイルを処理して分かったことは、find_peaks()関数によるピーク検出はバックグラウンド(傾き)があるスペクトルではあまりうまくいきません(ピーク自体は弱くてもバックグラウンドが高いと拾われる)。そういう意味でもバックグラウンド処理済みのProcessedを使うことになります。また検索時のプログラムの自分のスペクトルの前処理でもバックグラウンド除去が必要です。
 Savitzky-Golay法で平滑化した方がより正しいピーク検出が行われるようでした。しかし平滑化は場合によっては元のスペクトルを大きく変化させてしまうことがあります。そのために大きく変化した場合(最大ピーク強度が半分以下になる)はパラメータを変えて再度計算しなおすようにしてます。ピーク検出では検出感度のパラメータを自動で調整して、8個ピークが得られるようにしてます。本当のピークではないものを拾ったり、元々ピーク数が8個もない鉱物もあるため、index.txtの一部は正確でない場合もありますが、そこはあまり大事にはならないだろうと考えてます。この辺りをもう少しrefineするには自分でピーク検出部分を書く必要がありそうです。
 強度情報は入れてませんが、強度の順番にindex.txtファイルに入れているので、それを定性的な強度情報として検索で利用してます。
 Processedを全部処理するプログラムを作成して、それを実行しました。結構速くて1分以内で終了します。index.txtのファイルサイズは815 kb程度となりました。見ると5779行あります。RAWデータを無視しているので、ファイル数のほぼ半数ですが、対応するRAW自体がないものもあるので、半数よりは少し多くなってます。また、ガラススペクトルに関して5つほどピーク検出がうまくいってなくてその分少なくなってます。
 index.txtファイルは先頭8つがピーク位置を高いものから低いものの順番で並べて、最後にそのファイル名を入れてあります。ファイル名は後でオリジナルのファイルにアクセスするためと、ファイル名から鉱物名を拾うためです。なおピーク位置はピーク関数を使ってfitはしてなくてfind_peaks関数で得られたものをそのまま使ってます。ピーク位置は校正の方法などに依存するので実際的には使った装置が違えばある程度のずれが存在すること、鉱物の場合は固溶体が多く、ピーク位置は組成でかなり変わりうるので、同定目的では非常に正確なピーク位置を求める必要性はないと考えるからです(その分、検索時には幅を広げて検索する必要があります)。

index.txtファイルの検索プログラムの作成

 続いて検索するプログラムを作成しました。同定したいスペクトルを読んでプロットし、平滑化、必要ならバックグラウンドを引く処理をして8個ピーク検出して、それをlistbox1に入れます。そのリストとindex.txtを比較して、一致度がいいものをlistbox2にリストアップします。それらを実行するにはプログラムのwinodwで、ボタンを上から順番にクリックすることで達成できます。最終的にリストアップされたものを選択して、スペクトルとして表示して、同定したいスペクトルと一致しているかをユーザー自身が判断することで同定を行います。
 実測スペクトルによってはピークが1つ(ダイヤモンド)とか2つ(グラファイト)しかない場合があります。そういう場合には無理矢理8個拾ってきた位置で検索すると余分なものまで候補として拾ってきます。また宇宙線由来のピークやレイリー散乱線をピークとして拾ってくる場合もあります。そこでlistbox1の8個のピークで検索で使わないピークをユーザーが選択できるようにしました(複数選択可)。そうやって不要なピークを除外して検索するとより正しい候補が得られます。
 今の所、一致度(gof)には単純な指標を使ってます。toleranceで指定した値の範囲内にあるindex.txtにあるピークを一致したとして、強度の高い順に8から1のポイントを与えて、その合計ポイントを計算しているだけです。ラマンの強度は方位にもよるので強度の強弱は必ずしも一定ではありませんが、意外にもこの単純な指標で正しい候補が得られてます。ただし正解ではない候補のスペクトルと比べてみると全然似てないスペクトルの場合が多いので、逆に候補側の強度が高いものからのピークが存在するかどうかも同様に調べて一致度に加えるように直しました。これがあると候補の確度が上がります。ピーク位置のずれをもう少し複雑な関数にしてもいいのですが、測定データが校正されていない場合や固溶体でピーク位置がズレるなどもあるので、単純な指標でも十分なようです。
 バックグラウンド除去には移動平均を利用する方法を使いました。これはS.Bruckner (J.Appl.Cryst.33,977-979,2000)で提案されている方法で、こちらで紹介されていてpythonのサンプルコードも公開されてます。これを実行しておくとピークの検出がより正確になります。
 自分で測定したデータ数十個でテストしてみましたが、ほとんどの場合は出てきた候補の中に正解が含まれていて同定できてました。うまくいかないケースも数件ありましたが、それはデータベースにない、データベースにあるスペクトルがよくない、測定スペクトルがよくない(ブロードでピーク数が少ない)などが理由でした。
 面白いことに石英の測定スペクトルを使って検索したところ、石英が候補リストに出てくるのは当然なのですが、それ以外でredmonditeも候補リストに出てきました。そこでRRUFFのredmonditeのスペクトルを見てみたところ、石英のスペクトルと完全に一致しました。これはRRUFFに対応を報告済みです(既に修正されている)。さらにもう1件、おかしいものを見つけます。
 一応完成したのですが、候補スペクトルに対してコサイン類似度を計算することで候補を絞れないかを試してみる予定です(実はピークリストに対してコサイン類似度とユークリッド距離を試しましたが、あまり有効ではないようです。listbox2の先頭の数字はコサイン類似度です。)。また自分の持っているラマンデータも検索に使えるようにしたいのですが、その前に使うスペクトルの吟味や情報追加などが必要で少しづつ処理するしかなさそうです。

作ったプログラムの実行例

 まずはプログラムのGUI windowが出てきます。全然洗練されてませんが、基本的には上からボタンをクリックしていけば処理が進みます。赤くなっているボタンが次の処理を示してます。結果はプロットされるので、あまりうまくない時はパラメータを変えて、再度ボタンをクリックすると改善されるはずです。

rruff_Raman_search_screenshot-1.png

 まずはLoadボタンをクリックして、データを読み込みます。例は隕石中の鉱物のラマンスペクトルです。読み込むとMatPlotLibを使ってスペクトルを表示します。

rruff_Raman_search_screenshot-2.png

 次にSmoothボタンをクリックすると平滑化したスペクトルが表示されます。あまりスペクトルの変形がひどい時はwindowの値を小さくして再度ボタンをクリックします。

rruff_Raman_search_screenshot-3.png

 バックグラウンドがある場合はbackgroundボタンをクリックすると、バックグラウンドを引いたスペクトルが表示されます。

rruff_Raman_search_screenshot-4.png

 次にピーク検出を行います。パラメータは普通はそのままで問題ないはずですが、近接する2つのピークで片側が検出できてない場合はDistanceを小さくします。find peaksボタンをクリックすると、スペクトルとピークを検出した位置が示されます。また、下のリストボックスに検出したピーク位置のリストが表示されます。この場合はバックグラウンドを引いたスペクトルでなくsmoothingしただけのスペクトルが表示されます。

rruff_Raman_search_screenshot-5.png
rruff_Raman_search_screenshot-6.png

 リストボックスのピークリストを吟味して、本来のピークでないものがあった場合(例えば宇宙線由来ピーク)はリストボックスのその行をクリックすると選択されます。選択されたものは検索で使いません。それでSearch indexボタンをクリックすると検索が始まって、一致のよい候補を一番下のリストボックスに表示します。より多くの候補を見たい場合はthresholdを小さくしてください。測定データが波数校正してない場合はtoleranceを少し大きくした方がいいかもしれません。なお、RRUFFのデータは約50から100 cm-1以下の低波数データがないので、私のスペクトルではレイリー散乱やantistokes側を含むものが多いのですが、50 cm-1以下は使わないように、プロットでも使わないようにしてます。

rruff_Raman_search_screenshot-7.png

 候補のリストボックスから見たいものを選んでPlotボタンをクリックするとそのスペクトルと測定されたスペクトルが同時に表示されるので、2つが一致しているかどうかを判断できます。また隣のOpenボタンをクリックするとテキストエディタでデータファイルが開きます(なおこれ直近で付けたので上の図ではOpenボタンがまだありません)。その試料の細かい情報がデータファイルのヘッダ部分にあります。この例の場合は候補には主にenstatiteがリストされており、そのスペクトルをプロットすると測定スペクトルとよく一致していることが分かりますので、enstatiteと同定できました。

rruff_Raman_search_screenshot-8.png

 最新版では鉱物名で検索できるようにしました。その結果はリストボックスに入るので、先ほどと同じように1つ選んで、Plotボタンをクリックするとそのスペクトルと比較することができます。鉱物名で検索だけ行う場合は観測スペクトルを読み込んで、最低smoothingだけしておく必要があります(比較でsmoothingしているスペクトルを使っている関係で)。

rruff_Raman_search_screenshot-10.png

 この例の場合はenstatiteなので、orthoenstatiteかclinoenstatiteかどちらかの可能性があります。この例の場合はorthoenstatiteと同定しました。

pythonコードのダウンロード

 参考のためにコードを公開してます。クリックするとファイル自体が開いてしまうので(その場合、セーブしてください)、リンク上で右クリックでダウンロードするを選んでください。また実際に使うためにはpythonライブラリの追加、ファイルのディレクトリをPCに合わせて変更するなどが必要になります。実際Windows PCに入れて動かしてみたところ、パス関連でエラーがでます。pathlibを入れて対応しましたが、現在のところ下のプログラムにはまだ反映させてません。フォントサイズも調整が必要そうでした。