C++で統計解析
先月開催されたJapan.R 2013の懇親会で,「C++で統計解析を行うための良いライブラリは?」という話がありました.
統計解析と一口に言っても結構広いので,ここでは以下の4つのカテゴリ
- 記述統計量(最大値,最小値,平均値,分散等)
- 統計的検定(t検定,χ2乗検定等)
- 多変量解析(線形回帰,一般化線形モデル,判別分析,主成分分析,因子分析等)
- 機械学習(サポートベクタマシン,ランダムフォレスト等)
に分けてライブラリがサポートする機能を整理してみると,下表のようになります*1.ここでは,Scytheなどの数値計算用のライブラリ,Shogun, Vowpal Wabbitなどの機械学習に特化したライブラリは対象外としています.他にもこんなライブラリがあるよ!という方は是非教えてください.
ライブラリ | 記述統計量 | 統計的検定 | 多変量解析 | 機械学習 |
---|---|---|---|---|
Boost.Accumulators | ○ |
× |
× |
× |
Apophenia | ○ |
○ |
△ |
× |
ROOT | △ |
△ |
△ |
△ |
GSL | △ |
×(?) |
△ |
×(?) |
ALGLIB | ○ |
○ |
○ |
△ |
○:多くの手法を提供 △:少数の手法を提供 ×:非提供
機能の網羅性という観点からはALGLIBが良さそうなので,本記事ではこのライブラリについて調べてみましょう.
ALGLIBとは
ALGLIBは,GPLライセンスのもとでOSSとして提供される数値計算およびデータ処理のためのソフトウェアです.C++, C#, Python, VBAなど多くのプログラミング言語から呼び出すことができます.商用版もあり,マルチスレッドIntel Math Kernel Libraryを用いた最適化・高速化などに対応しています.
以下のような機能を提供しています.
- 常微分方程式の数値計算法
- 線形方程式・非線形方程式の求解
- 行列・ベクトル演算
- 固有値・固有ベクトルの計算法
- 数値積分
- 補間・フィッティング
- 最適化
- FFT, 畳み込み, 相互相関
- 統計: 一般的なアルゴリズム
分布(F分布, χ2乗分布,2項分布,Poisson分布,Studentのt分布,正規分布,誤差関数),記述統計量(平均値,中央値,分散,標準偏差,歪度,尖度,分位点) - 仮説検定
Studentのt検定,F検定,χ2乗検定,符号検定,Wilcoxonの符号順位検定,Mann–WhitneyのU検定,Jarque–Bera検定,相関係数の有意性検定 - データ解析: 分類,回帰,その他のアルゴリズム
線形回帰,多変量ロジスティック回帰分析,ニューラルネットワーク,ニューラルネットワークアンサンブル,ランダムフォレスト,線形判別分析,主成分分析,クラスタリング - 特別な関数
- その他のアルゴリズム
ダウンロードと解凍
以下のコマンドによりファイルをダウンロードし,解凍します.
$ wget http://www.alglib.net/translator/re/alglib-3.8.2.cpp.zip $ unzip alglib-3.8.2.cpp.zip
cppというディレクトリが作成されます.
$ ls cpp
ALGLIBが提供する機能は,cpp/srcディレクトリに格納されているヘッダファイルとcppファイルに記述されています.
$ ls cpp/src/ alglibinternal.cpp dataanalysis.h interpolation.cpp solvers.h alglibinternal.h diffequations.cpp interpolation.h specialfunctions.cpp alglibmisc.cpp diffequations.h linalg.cpp specialfunctions.h alglibmisc.h fasttransforms.cpp linalg.h statistics.cpp ap.cpp fasttransforms.h optimization.cpp statistics.h ap.h integration.cpp optimization.h stdafx.h dataanalysis.cpp integration.h solvers.cpp
データ構造
ALGLIBでは,以下のようなデータ構造が提供されています.
使用例1) 相関係数の算出
まずはサンプルを参考に,との間の相関係数を算出してみましょう.
#include <iostream> #include "statistics.h" using namespace std; using namespace alglib; int main() { // ALGLIBを用いた相関係数の算出 real_1d_array x = "[0,1,4,9,16,25,36,49,64,81]"; real_1d_array y = "[0,1,2,3,4,5,6,7,8,9]"; double v; cout.precision(8); // 共分散 v = cov2(x, y); cout << "共分散: " << double(v) << endl; // Pearsonの相関係数 v = pearsoncorr2(x, y); cout << "Pearsonの相関係数: " << double(v) << endl; // Spearmanの相関係数 v = spearmancorr2(x, y); cout << "Spearmanの相関係数: " << double(v) << endl; return 0; }
real_1d_arrayは1次元の倍精度浮動小数点の配列です.このデータ構造に,カンマ区切りの値を"[]"で囲んで文字列として代入しています.
srcディレクトリ内のすべてのヘッダファイルとcppファイル,および上記のソースコードのファイル(ここでは"test_cor.cpp"とします)を同じディレクトリに格納し,以下を実行します.
$ g++ -o test_cor *.cpp $ ./test_cor 共分散: 82.5 Pearsonの相関係数: 0.96269074 Spearmanの相関係数: 1
使用例2) 線形回帰
線形回帰は以下のように実行します(参照ページ).
#include <iostream> #include <vector> #include "dataanalysis.h" using namespace alglib; using namespace std; int main() { // ALGLIBを用いた線形回帰 // データセットの作成 vector<double> xrange; vector<double> yrange; xrange.push_back(1.0); xrange.push_back(2.3); xrange.push_back(3.1); xrange.push_back(4.8); xrange.push_back(5.6); xrange.push_back(6.3); yrange.push_back(2.6); yrange.push_back(2.8); yrange.push_back(3.1); yrange.push_back(4.7); yrange.push_back(5.1); yrange.push_back(5.3); if (!xrange.empty() && !yrange.empty()) { // real_2d_arrayへのデータの格納 int npoints = min(xrange.size(), yrange.size());//points real_2d_array xy; xy.setlength(npoints, npoints); for (int i = 0; i < npoints; i++) { xy(i, 0) = xrange[i]; xy(i, 1) = yrange[i]; } // 線形回帰の実行 ae_int_t nvars = 1; ae_int_t info = 0; linearmodel lm; lrreport ar; lrbuild(xy, npoints, nvars, info, lm, ar); real_1d_array v; lrunpack(lm, v, nvars); // 回帰係数の出力 // y = mx + b: // m (slope) : 0.5842 // b (y - int) : 1.6842 cout.precision(8); if (nvars > 0) { cout << "m: " << v(0) << " b: " << v(1) << endl; } } return 0; }
real_2d_arrayにデータを格納して,lrbuild関数で線形回帰を実行し,lrunpack関数で回帰結果を取得しています.
コンパイルして実行します.
$ g++ -o test_lsfit *.cpp $ ./test_lsfit m: 0.58418428 b: 1.6842239
使用例3) ランダムフォレスト
ALGLIBでは,Breiman(2001)のランダムフォレストのアルゴリズムを発展させたランダム決定フォレスト(Random Decision Forest)が実装されています.
インタフェースを調査中.分かり次第,書きます!