【C++】スムージングとベースライン推定のためのライブラリ「sablib」を公開しました

C++,Eigen,sablib,スペクトル,バックグラウンド,ベースライン,信号処理,化学

はじめに

これまで当ブログでは、ノイズを含むデータの平滑化やバックグラウンド(ベースライン)を推定するための各種アルゴリズムを紹介し、C++やPythonで実装してきました。

  • Savitzky-Golay法 スペクトルデータのスムージングに広く使われる定番手法
  • Whittaker Smoother ペナルティ付き最小二乗法を用いた強力なスムージング手法
  • 単純移動平均法: 単純移動平均を繰り返すことでベースラインを推定する手法
  • AsLS法: Whittaker Smootherを応用したベースライン推定手法
  • airPLS法 / arPLS法 AsLS法を改良した、より精度の高いベースライン推定手法

これらの手法は、分析化学のデータ処理(スペクトル解析など)において欠かすことができません。ただ、自分で調べてみた範囲ではC++で使えるものは多くないことから、せっかく公開したのなら、まとめてライブラリにしてしまおうと考えました。そうにして作成したものが今回紹介する「sablib」です。

sablibとは

sablibは、C++で使えるスムージングとベースライン推定のアルゴリズムをまとめたライブラリです。線形代数ライブラリ Eigen を使用しており、疎行列を活用することで大量のデータも高速に処理できます。ブログ記事で紹介したコードをベースにしていますが、コードを見直して書き直したところも多いです。なお、ブログで未紹介のアルゴリズムも一部収録しています。

必要環境

  • C++17以上に対応したコンパイラ
  • Eigen 3.4.0以上
  • CMake 3.10以上

主な機能

sablibは大きく分けて「平滑化」と「ベースライン推定」の2つの機能を提供します。

1. 平滑化 (Smoothing)

  • Savitzky-Golay法
  • Whittaker Smoother
  • P-Spline: ペナルティ付きBスプライン
  • 移動平均: 単純移動平均(SMA)および加重移動平均(WMA)

2. ベースライン推定 (Baseline Estimation)

  • 古典的手法: 直線・多項式フィッティングや3次スプライン
  • 単純移動平均法
  • AsLS法
  • airPLS法
  • arPLS法
  • BEADS法(Baseline Estimation And Denoising using Sparsity): ノイズ除去とベースライン推定を同時にできるアルゴリズム

使い方

sablibのビルド

リポジトリからクローンします。

git clone https://github.com/Izadori/sablib.git

CMakeを使ってビルドします。

cd sablib
mkdir build
cd build
cmake ..
cmake --build .

もしEigen3が見つからない場合は、cmake .. -DCMAKE_PREFIX_PATH="/path/to/Eigen3"としてみてください。

導入方法

CMakeプロジェクトであれば、以下のようにして簡単に追加できます。

find_package(Eigen3 REQUIRED) # Eigen 3.4.0以上が必要です
set(SABLIB_DIR "/path/to/sablib")
include_directories(${SABLIB_DIR})
find_library(SABLIB_LIB NAMES sablib libsablib PATHS "${SABLIB_DIR}/build")
target_link_libraries(my_app PRIVATE ${SABLIB_LIB} Eigen3::Eigen)

コード例(arPLS法によるベースライン推定)

#include <vector>
#include "sablib/sablib.h"

int main()
{
    std::vector<double> signal = { /* 観測データ */ };

    // arPLSアルゴリズムでベースラインを推定
    // 引数: 信号, 平滑化パラメータlambda
    double lambda = 1e5;
    std::vector<double> baseline = sablib::BaselineArPLS(signal, lambda);

    // 補正後の信号を取得
    std::vector<double> corrected(signal.size());
    for(size_t i = 0; i < signal.size(); ++i) {
        corrected[i] = signal[i] - baseline[i];
    }

    return 0;
}

おわりに

sablibは、まだまだ発展途上のツールです。今後もアルゴリズムの追加や修正などを行っていきます。また、sablibに搭載したアルゴリズムについても当ブログ上で紹介していく予定です。

バグレポートや機能要望、プルリクエストなどは大歓迎です。もし興味を持っていただけたら、ぜひGitHubでスターを付けていただけると励みになります。