PHP の統計関数を使う
PHP では、PECL stats 拡張モジュールを導入することで、さまざまな統計関数を利用できます。今回は、このモジュールを試してみます。公式の情報は以下にあります。
なお、このモジュールは DCDFLIB, RANDLIB のラッパーになっています。後述するように、統計関数の使い方にはかなり癖があるのですが、DCDFLIB や RANDLIB を知っていれば簡単かもしれません。
stats 拡張モジュールの導入
まず、stats 拡張モジュールをインストールします。CentOS 6.5 では、pecl コマンド自体は php-pear パッケージで提供されます。また、pecl コマンドでモジュールをビルドする際には phpize が必要になります。phpize は php-devel パッケージで提供されます。
$ sudo yum install php-pear php-devel $ sudo pecl install stats ... Build process completed successfully Installing '/usr/lib64/php/modules/stats.so' install ok: channel://pecl.php.net/stats-1.0.3 configuration option "php_ini" is not set to php.ini location You should add "extension=stats.so" to php.ini
PHP の起動時に拡張モジュールがロードされるように extension の記述を追加します。上記のメッセージにあるように /etc/php.ini に書いてもよいのですが、せっかく /etc/php.d ディレクトリが用意されているので、ファイルを分けて書くことにします。
$ sudo vi /etc/php.d/stats.ini ; Enable stats extension module extension=stats.so
stats 拡張モジュールがロードされることを確認します。
$ php -i | grep stats /etc/php.d/stats.ini, stats
使い方の例: 正規分布の確率密度関数を描く
統計関数の使い方の例として、ありきたりですが、標準正規分布の確率密度関数を描いてみます。
<?php for ($x = -2.0; $x <= 2.0; $x += 0.2) { $p = stats_dens_normal($x, 0, 1); printf("%9.6f\t%f\t%s\n", $x, $p, str_repeat('*', round($p * 100))); }
stats_dens_normal が標準正規分布の確率密度関数を求める関数です。関数名は、おおむね以下のルールで付けられているようです。
関数名 | 内容 |
---|---|
stats_cdf_* | 累積分布関数 |
stats_dens_* | 確率密度関数 |
stats_rand_gen_* | 分布からの乱数生成 |
PHP の統計関数は、公式のドキュメントの説明が不十分なものが多く、たとえば stats_dens_normal についても説明は何もないのですが (下記ページを参照)、幸いなことに $x, $ave, $stdev というパラメータ名から使い方を想像できます。平均 $ave, 標準偏差 $stdev の正規分布の確率密度関数 f($x) の値を返してくれることを期待できそうです。
PHP: stats_dens_normal - Manual
実行結果は次のようになります。よさそうです。
$ php normpdf.php -2.000000 0.053991 ***** -1.800000 0.078950 ******** -1.600000 0.110921 *********** -1.400000 0.149727 *************** -1.200000 0.194186 ******************* -1.000000 0.241971 ************************ -0.800000 0.289692 ***************************** -0.600000 0.333225 ********************************* -0.400000 0.368270 ************************************* -0.200000 0.391043 *************************************** -0.000000 0.398942 **************************************** 0.200000 0.391043 *************************************** 0.400000 0.368270 ************************************* 0.600000 0.333225 ********************************* 0.800000 0.289692 ***************************** 1.000000 0.241971 ************************ 1.200000 0.194186 ******************* 1.400000 0.149727 *************** 1.600000 0.110921 *********** 1.800000 0.078950 ******** 2.000000 0.053991 *****
使い方の例: 正規分布の累積分布関数を描く
次の例として、累積分布関数を描いてみます。関数名は stats_cdf_normal だろうと想像して公式のドキュメントを調べても、この関数は見つかりません。これは、ソースコード中のドキュメントコメントが誤っているためで、実は stats_cdf_normal 関数はちゃんと存在しています。ドキュメントコメントの誤りについては、下記で報告されています。このうち stats_dens_uniform は修正されていましたが、そのほかは現在でも未修正でした。
PHP :: Bug #57832 :: name mismatches in statistics.c
さて、stats_cdf_normal 関数が存在していることはわかったので、先ほどのプログラムの stats_dens_normal を stats_cdf_normal に変えてみます。ところが、単純に関数を置き換えて実行すると以下のようなエラーが出てしまいます。どうやら、確率密度関数と累積分布関数では使い方が異なるようです。
$ sed 's/stats_dens_normal/stats_cdf_normal/' normpdf.php >normcdf.php $ php normcdf.php PHP Warning: stats_cdf_normal() expects exactly 4 parameters, 3 given in /.../normcdf.php on line 3
ここで種明かしのようになりますが、結局のところ PHP の統計関数の使い方については、ソースコードを読むのが一番簡単です。ソースコードを stats_cdf_normal で検索すると、400 行目に関数のエントリが見つかります。その手前に (誤った) ドキュメントコメントが書かれていますが、それよりもさらに上を見ると、とても丁寧な説明が書かれています。
PHP: Contents of /pecl/stats/trunk/php_stats.c
stats_cdf_normal 関数は 4 引数を受け取る関数で、末尾の第 4 引数 $which によって「何を求めるか」を指示します。$which の値によって、第 1 引数から第 3 引数の意味が変わります。具体的には、累積分布関数を F(x) として、以下のような関係になります。
which (第 4 引数) | 戻り値 | 第 1 引数 | 第 2 引数 | 第 3 引数 |
---|---|---|---|---|
1 | F(x) | x | 平均 | 標準偏差 |
2 | x | F(x) | 平均 | 標準偏差 |
3 | 平均 | F(x) | x | 標準偏差 |
4 | 標準偏差 | F(x) | x | 平均 |
このようにまとめてみると、今回は累積分布関数を描こうとしていたので、$which に 1 を指定すればよいことがわかります。以下のようなコードになります。
<?php for ($x = -2.0; $x <= 2.0; $x += 0.2) { $which = 1; $p = stats_cdf_normal($x, 0, 1, $which); printf("%9.6f\t%f\t%s\n", $x, $p, str_repeat('*', round($p * 100))); }
実行結果は以下のようになります。
$ php normcdf.php -2.000000 0.022750 ** -1.800000 0.035930 **** -1.600000 0.054799 ***** -1.400000 0.080757 ******** -1.200000 0.115070 ************ -1.000000 0.158655 **************** -0.800000 0.211855 ********************* -0.600000 0.274253 *************************** -0.400000 0.344578 ********************************** -0.200000 0.420740 ****************************************** -0.000000 0.500000 ************************************************** 0.200000 0.579260 ********************************************************** 0.400000 0.655422 ****************************************************************** 0.600000 0.725747 ************************************************************************* 0.800000 0.788145 ******************************************************************************* 1.000000 0.841345 ************************************************************************************ 1.200000 0.884930 **************************************************************************************** 1.400000 0.919243 ******************************************************************************************** 1.600000 0.945201 *********************************************************************************************** 1.800000 0.964070 ************************************************************************************************ 2.000000 0.977250 **************************************************************************************************