2014/05/27(火)Perl Data Language 基礎編 #07 「多次元ピドルから配列リファレンスへの変換、ベクトル走査、atとsclrの違い、topdl」

スライスの前にまとめておくべきことがあったのでまとめておきましょう。

atとsclrの違いは、sclrは何次元のピドルでもとにかく最初の値を返すこと。atだと場所の指定と次元が食い違うと死にます。

topdlはPDLを使ったモジュールで使えそうな関数。デフォルトではエクスポートされない点だけ注意。

とりあえずコードと実行結果を見るのが確実で手っ取り早い、というわけでいつも通りコードと実行結果を載っけます。

#!/usr/bin/env perl

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

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

say "unpdl で多次元ピドルを配列リファレンスへ:";
my $arrayref = $piddle->unpdl;
say p $arrayref;
print @{ $arrayref->[0] };
print @{ $arrayref->[1] };
print "\n\n";

my $vector = pdl [ 7,8,9 ];

say "listindices メソッドで走査:";
for my $i ($vector->listindices)
{
    say $vector->at($i);
}
print "\n";

say "list メソッドで走査:";
for my $elem ($vector->list)
{
    say $elem;
}
print "\n";

say "at(0,0)";
say $piddle->at(0,0);
print "\n";

say "at(0)";
eval { $piddle->at(0) };
say "エラー発生" if $@;
print "\n";

say "sclr";
say $piddle->sclr;
PDL->sclr({ Check => 'warn' });
say $piddle->sclr;
PDL->sclr({ Check => 'barf' });
eval { $piddle->sclr };
say "エラー発生" if $@;
PDL->sclr({ Check => 0 });
say $piddle->sclr . "(Check => 0 なのでエラーは発生しなくなる)";
print "\n";

say "topdl(pdlであることを確実にする)";
say p PDL::Core::topdl 7;
say p PDL::Core::topdl $piddle;
say p pdl $piddle;

実行結果↓

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

unpdl で多次元ピドルを配列リファレンスへ:
 [
    [0] [
        [0] 1,
        [1] 2,
        [2] 3
    ],
    [1] [
        [0] 4,
        [1] 5,
        [2] 6
    ]
]
123456

listindices メソッドで走査:
7
8
9

list メソッドで走査:
7
8
9

at(0,0)
1

at(0)
エラー発生

sclr
1
multielement piddle in 'sclr' call at unpdl.pl line 47.
1
エラー発生
1(Check => 0 なのでエラーは発生しなくなる)

topdl(pdlであることを確実にする)
PDL {
    Data     : 7
    Type     : double
    Shape    : Empty[0]
    Nelem    : 1
    Min      : 7
    Max      : 7
    Badflag  : No
    Has Bads : No
}
PDL {
    Data     : [
                [1 2 3]
                [4 5 6]
               ]
    Type     : double
    Shape    : [3 2]
    Nelem    : 6
    Min      : 1
    Max      : 6
    Badflag  : No
    Has Bads : No
}
PDL {
    Data     : [
                [1 2 3]
                [4 5 6]
               ]
    Type     : double
    Shape    : [3 2]
    Nelem    : 6
    Min      : 1
    Max      : 6
    Badflag  : No
    Has Bads : No
}

ピドルを渡すときのpdlとtopdlの違いが実行結果からは分からないのでベンチマークをとってみました。pdlにピドルを渡すと新たなコピーが作られるのに対してtopdlはリファレンスを返すので、その分だけ少し速いという結果になっていると考えられます。

#!/usr/bin/env perl

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

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

Benchmark::cmpthese(-1, {
      'pdl' => sub {   pdl $piddle },
    'topdl' => sub { topdl $piddle },
});

ベンチマークの結果↓

         Rate   pdl topdl
pdl   19997/s    --  -15%
topdl 23643/s   18%    --

2014/05/27(火)Perl Data Language 基礎編 #06 「PDLの資料」

PDLの資料

このへんが良い感じです。

日本語だと

ぐらいしか資料がないので、現在のところ英語が読めないとまともに使えない状況です。

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]
]