2014/05/26(月)Perl Data Language 基礎編 #05 「PDLとPerlの変数間のやりとり、null、バッド値の伝染、PDL生成のベンチマーク」

まだデータフローの説明、グラフ描画の説明もあるので#10ぐらいまで統計に入れないかも。

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw/say/;
use PDL;
use DDP filters => { -external => [ 'PDL' ] };

my $a = pdl [ [1,2,3], [4,5,6] ];
say $a;
print "\n";

say "PDL から Perl のリストに変換:";
my @b = $a->list;
say @b;
print "\n";

say "PDL から Perl のスカラーに変換(at(4)):";
say PDL->new([8,7,3,9,1,6,8])->at(4);
print "\n";

say "Perl のリストから PDL へ:";
my $c = pdl @b;
say $c;
print "\n";

say "PDL の null";
# どんな次元にも拡張するプレースホルダー
# ライトバック戻り値として関数に渡す場合に有効
# たぶん破壊的な関数を作るような場合のこと
my $null = PDL->null;
say p $null;
say "ピドルはnullです" if $null->isnull;
say "ピドルは空です"   if $null->isempty;
print "\n";

say "バッド値を伝染させる:";
# バッド値に関しては、#02を参照
my $hasbad = pdl 'bad';
my $d = PDL->null;
say "hasbad にバッド値あり" if $hasbad->badflag;
say "d      にバッド値なし" unless $d->badflag;
say '$d = $hasbad + 3';
$d = $hasbad + 3;
say "d      にバッド値あり" if $d->badflag;

実行結果↓

[
 [1 2 3]
 [4 5 6]
]


PDL から Perl のリストに変換:
123456

PDL から Perl のスカラーに変換(at(4)):
1

Perl のリストから PDL へ:
[1 2 3 4 5 6]

PDL の null
PDL {
    Data     : Null
    Type     : unsigned char
    Shape    : [0]
    Nelem    : 0
    Min      : 0
    Max      : 0
    Badflag  : No
    Has Bads : No
}
ピドルはnullです
ピドルは空です

バッド値を伝染させる:
hasbad にバッド値あり
d      にバッド値なし
$d = $hasbad + 3
d      にバッド値あり

PDLの生成で普通の配列で渡すか配列のリファレンスで渡すかでスピードが変わるか気になったのでPDL生成のベンチマークをとりました。配列のリファレンスで渡したほうがやや速いですな。

#!/usr/bin/env perl

use strict;
use warnings;
use Benchmark;
use PDL;

my @array = 1 .. 10;

Benchmark::cmpthese(-1, {
    '@array'    => sub { pdl @array  },
    '\@array'   => sub { pdl \@array },
});

ベンチマークの結果↓

           Rate  @array \@array
@array  43115/s      --    -21%
\@array 54613/s     27%      --

2014/05/26(月)Perl Data Language 基礎編 #04 「PDLの定数」

まだPDLに関してまとめるべきことがありまくりです。今回は定数。名前が被りそうなので、常に「PDL::Constants::」をつけておくのが無難かと思います。

ドキュメントは↓
https://metacpan.org/pod/PDL::Constants

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw/say/;
use PDL::Constants ();

say "  円周率:" . PDL::Constants::PI;
say "ネイピア数:" . PDL::Constants::E;
say "   虚数:" . PDL::Constants::I;
say "1ラジアン:" . PDL::Constants::DEGRAD;

print "\n";

say "i*i:"          . PDL::Constants::I * PDL::Constants::I;
say "i^2:"          . PDL::Constants::I ** 2;
say "パイラジアン:" . PDL::Constants::PI * PDL::Constants::DEGRAD;

実行結果↓

  円周率:3.14159265358979
ネイピア数:2.71828182845905
   虚数:0 +1i
1ラジアン:57.2957795130823

i*i:-1 +0i
i^2:-1 +1.22461e-16i
パイラジアン:180

次回は行列スライスをまとめようかな(?)

2014/05/26(月)Perl Data Language 基礎編 #03 「PDLの初歩的なメソッド」

コードに無駄があったのと、転置行列を追加したので再投稿です。

ドキュメントは以下の通り。

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw/say/;
use PDL;
use DDP filters => { -external => [ 'PDL' ] };

my $a = pdl [ 8, 7, 3, 9, 1, 6, 8 ];

my $b = pdl [
    [ 2, 3, 2 ],
    [ 4, 5, 6 ],
    [ 1, 2, 1 ],
];

say "最小値";
say $a->min;
say $b->min;
print "\n";

say "最大値";
say $a->max;
say $b->max;
print "\n";

say "平均";
say $a->avg;
say $b->avg;
print "\n";

say "最頻値";
say $a->mode;
say $b->mode;
say PDL->new([4,4,2,3,3])->mode;
print "\n";

say "メディアン";
say $a->median;
say $b->median;
print "\n";

say "ランダム";
say PDL->random(3, 4);
print "\n";

say "単位行列";
say identity(3, 3);
print "\n";

say "逆行列";
say inv( PDL->new([[4,2],[1,3]]) );
print "\n";

say "転置行列";
say transpose($a);
print "\n";

say "ゼロ行列";
say PDL->zeros(3, 1);
print "\n";

say "クイックソート";
say $a->qsort;
say $b->qsort;
print "\n";

実行結果↓

最小値
1
1

最大値
9
6

平均
6
2.88888888888889

最頻値
8
2
3

メディアン
7
2

ランダム

[
 [0.27851303 0.36231595 0.40859514]
 [0.33323768 0.29340034 0.67641457]
 [0.69607193 0.39091348  0.3260092]
 [0.61342505 0.94111466 0.22114707]
]


単位行列

[
 [1 0 0]
 [0 1 0]
 [0 0 1]
]


逆行列

[
 [ 0.3 -0.2]
 [-0.1  0.4]
]


転置行列

[
 [8]
 [7]
 [3]
 [9]
 [1]
 [6]
 [8]
]


ゼロ行列

[
 [0 0 0]
]


クイックソート
[1 3 6 7 8 8 9]

[
 [2 2 3]
 [4 5 6]
 [1 1 2]
]

2014/05/25(日)Perl Data Language 基礎編 #02 「行列の演算とバッド値」

PDLの関数を見る前に行列の演算です。

ドキュメントは以下の通り。

  • PDL::Core(メソッド、型変換のための関数、PDLの生成、型変換、スレッドなど)
  • PDL::BadValues(PDLにおけるバッド値サポートの議論)

バッド値は欠損値に使うのが良さそう。バッド値があるとバッドフラグがついて、さらにバッドフラグがついたピドル(PDLの変数のこと)で演算したりするとバッドフラグが伝染するみたい。ちなみに他の文字列(nyan)はバッド値がつくのか疑問に思ったので試したけど、ちゃんと'bad'や'BAD'と区別してバッドフラグはつかないようになっている模様。

他の注意点は行列同士の積は「x」を使うことぐらい。

統計についてまとめていく前にコア関数をまとめて、主要なドキュメントをまとめて、グラフ描画についてまとめます。

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw/say/;
use PDL;
use DDP filters => { -external => [ 'PDL' ] };

my $a = pdl [
    [ 1, 2 ],
    [ 3, 4 ]
];

my $b = pdl [
    [ 5 ],
    [ 6 ]
];

say "$a: $a";
say "$b: $b";

say "$a x $b";
say $a x $b; # 行列の積は*でなくてxを使う

my $d = $a;
$d = $d ** 3; # 3乗

say "$d($a^3): $d";
say "$a: $a"; # $a には影響しない

my $e = pdl [
    [ 'inf',    2    ],
    [ 'nan', ' -inf' ]
];

my $f = pdl [
    [ '-inf',  'bad'   ],
    [  3    ,  'nyan' ]
];

say "$e: $e";
say "$f: $f";

say "$e + $f:";
say $e + $f;

say "バッドフラグ";
say PDL->new(3)->badflag;
say PDL->new('bad')->badflag;
eval { PDL->new('nyan')->badflag; };
print $@ if $@;
my $g = pdl [ 'nyan' ];
say $g->badflag;
say p $g;

実行結果↓

$a: 
[
 [1 2]
 [3 4]
]

$b: 
[
 [5]
 [6]
]

$a x $b

[
 [17]
 [39]
]

$d($a^3): 
[
 [ 1  8]
 [27 64]
]

$a: 
[
 [1 2]
 [3 4]
]

$e: 
[
 [ inf    2]
 [ nan -inf]
]

$f: 
[
 [-inf    0]
 [   3    0]
]

$e + $f:

[
 [-nan    2]
 [ nan -inf]
]

バッドフラグ
0
1
PDL::Core::new_pdl_from_string: found disallowed character(s) 'nyan' in nyan at core.pl line 50.
0
PDL {
    Data     : [0]
    Type     : double
    Shape    : [1]
    Nelem    : 1
    Min      : 0
    Max      : 0
    Badflag  : No
    Has Bads : No
}

2014/05/25(日)Perl Data Language 基礎編 #01 「PDLのインストール」

統計検定に向けて「Perlで統計」をまとめていきます。(の予定でしたが、思いのほかPDLが大きいライブラリだったのでまずはPDLをまとめていきます)

PDL(Perl Data Language)は、科学技術計算とその結果の描画のためのPerl拡張です。PDLは速くて、IDL(科学技術計算でよく使われるデータ分析用プログラミング言語)やMATLABと匹敵するか、それらより速い(often outperforming)です。PDLによって、画像などの多次元データも効率よく格納できて素早く操作できます。$a = $b + $c で $b と $c が大きいデータ集合 (たとえば 2048x2048 画像) でもほんの一瞬で結果を得られます。PDL変数(piddleと呼ばれる)は基本的なデータ型の広範囲をサポートし、たとえば $x は何次元のデータでも入ります(おそらくメモリが許す限り)。@x に格納しない理由は、「メモリ」と「スピード」のためです。(ドキュメントより)

インストールは以下の通り。

cpanm Data::Printer
cpanm Data::Printer::Filter::PDL

今回はとりあえず動かすところま'で。

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw/say/;
use PDL;
use DDP filters => { -external => [ 'PDL' ] };

my $piddle = pdl [1,0,0,1];
say $piddle;

say "Data::Printer::Filter::PDL で表示:";
p $piddle;
print "\n";

print "要素数:" . $piddle->nelem . "\n";
say $piddle->info("メモリ消費量:%M");

print "\n";


my $piddle2 = pdl [ [ 1 .. 3 ], [ 3 .. 5 ] ];
say $piddle2;

say "Data::Printer::Filter::PDL で表示:";
p $piddle2;
print "\n";

print "要素数:" . $piddle2->nelem . "\n";
say $piddle2->info("メモリ消費量:%M");

実行結果:
pdl

次回はPDLの関数を見て、次々回でモジュールまとめていく感じでいこうかな。

追記!割りとガチで使う場合は GSL(GNU Scientific Library)をインストールしておきましょう。パッケージ管理システムがAPTの場合は「sudo apt-get install libgsl0-dev」でOK!GSLのインストールより先にPDLをインストールしてしまった場合は、「cpanm PDL --reinstall」でPDLを再インストールしましょう。