PDLにおける多次元データの表現
これまでは1次元のデータだけを扱ってきましたが、PDLで多次元データを表現する方法を解説したいと思います。
多次元データの表現
多次元データを表現するには、pdl関数を使って次のようにします。
use PDL; my $data = pdl [ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12] ];
最初に次元とランクと呼ばれる概念を覚えましょう。視覚的に理解したほうがわかりやすいので図示します。
1次元 ランク1 ランク2 ランク3 2次元 ランク1 [1, 2, 3], ランク2 [4, 5, 6], ランク3 [7, 8, 9], ランク4 [10, 11, 12]
これまでやってきた1次元データだと考えましょう。
1次元 ランク1 ランク2 ランク3 [1, 2, 3],
要素の取得と設定
多次元データの要素の取得方法と設定方法を覚えましょう。要素の取得と設定にはナイススライス記法を使います。1次元目のランク,2次元目のランクの順で指定して、添え字は0から始まります。
use PDL; use PDL::NiceSlice; # データ my $data = pdl [ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12] ]; # 要素をPDL変数として取得(1次元2ランク-2次元3ランク) my $data_1_2 = $data(1, 2); # 要素の値そのものを取得 my $data_1_2_raw = $data->at(1, 2); # 要素を設定。 $data(1, 2) .= 20;
複数の要素の取得、複数の要素の設定
PDL変数に対して複数の要素を取得したり、設定することもできます。以下の例では1次元目の2ランクから3ランク, 2次元の3ランクを取得します。
# 複数の要素の取得(1次元2~3ランク, 2次元3ランク) my $data_sliced1 = $data(1:2, 2);
複数の要素を設定するには次のようにします。
# 複数の要素の設定(1次元2~3ランク, 2次元3ランク) $data(1:2, 2) .= pdl [21, 22];
もちろん1次元目だけでなく、2次元目の複数の要素を取得を行うこともできます。
# 複数の要素の取得(1次元3ランク, 2次元1-2ランク) my $data_sliced2 = $data(2, 0:1);
2次元目の複数の要素を設定するには次のようにします。
# 複数の要素の設定(1次元3ランク, 2次元1~2ランク) $data(2, 0:1) .= pdl [ [30], [31] ];
複数次元の複数ランクの取得・設定も同じようにして行うことができます。
# 複数の要素の取得(1次元2~3ランク, 2次元1~2ランク) my $data_sliced3 = $data(1:2, 0:1); # 複数の要素の設定(1次元2~3ランク, 2次元1~2ランク) $data(1:2, 0:1) .= pdl [ [40, 41], [42, 43] ];
サンプル
実行できるサンプルです。
use strict; use warnings; use PDL; use PDL::NiceSlice; # データ my $data = pdl [ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12] ]; # 要素をPDL変数として取得(1次元2ランク,2次元3ランク) my $data_1_2 = $data(1, 2); # 要素の値そのものを取得 my $data_1_2_raw = $data->at(1, 2); print "$data_1_2\n"; print "$data_1_2_raw\n"; # 要素を設定。 $data(1, 2) .= 20; print "$data\n"; # 複数の要素の取得(1次元2から3ランク,2次元2ランク) my $data_sliced1 = $data(1:2, 1); print "$data_sliced1\n"; # 複数の要素の設定(1次元2~3ランク,2次元3ランク) $data(1:2, 2) .= pdl [21, 22]; print "$data\n"; # 複数の要素の取得(1次元3ランク, 2次元1-2ランク) my $data_sliced2 = $data(2, 0:1); print "$data_sliced2\n"; # 複数の要素の設定(1次元3ランク, 2次元1-2ランク) $data(2, 0:1) .= pdl [ [30], [31] ]; print "$data\n"; # 複数の要素の取得(1次元2~3ランク, 2次元1~2ランク) my $data_sliced3 = $data(1:2, 0:1); print "$data_sliced3\n"; # 複数の要素の設定(1次元2~3ランク, 2次元1~2ランク) $data(1:2, 0:1) .= pdl [ [40, 41], [42, 43] ]; print "$data";
データの初期化
PDLはさまざまなデータの初期化の機能を持っています。データを初期化する方法を紹介します。
0で初期化
複数次元のランク数を指定して0で初期化するにはzerosメソッドを使用します。zerosはPDL::Coreで定義されています。
use PDL; # 0で初期化(1次元は2ランク, 2次元は3ランク) my $data_zeros = pdl->sequence(2, 3);
1で初期化
複数次元のランク数を指定して1で初期化するにはonesメソッドを使用します。onesはPDL::Coreで定義されています。
# 1で初期化(1次元は2ランク, 2次元は3ランク) my $data_ones = pdl->ones(2, 3); print "$data_ones\n";
nullで初期化
PDLではnullという値が定義されています。nullで初期化するにはnullメソッドを使用します。nullははPDL::Coreで定義されています。
# nullで初期化 my $data_null = pdl->null;
1~nまでで初期化
0~n-1までの値で初期化するにはsequenceメソッドを使用します。sequenceはPDL::Basicで定義されています。
# 0~19で初期化 my $data_seq = pdl->sequence(20);
複数の次元を指定することもできます。
# 0~14で初期化(1次元3ランク, 2次元5ランク) my $data_seq2 = pdl->sequence(3, 5);
サンプル
実行できるサンプルです。
use PDL; # 0で初期化(1次元は2ランク, 2次元は3ランク) my $data_zeros = pdl->zeros(2, 3); print "$data_zeros\n"; # 1で初期化(1次元は2ランク, 2次元は3ランク) my $data_ones = pdl->ones(2, 3); print "$data_ones\n"; # nullで初期化 my $data_null = pdl->null; print "$data_null\n"; # 0~19で初期化 my $data_seq = pdl->sequence(20); print "$data_seq\n"; # 0~14で初期化(1次元3ランク, 2次元5ランク) my $data_seq2 = pdl->sequence(3, 5); print "$data_seq2\n";
複数要素をまとめて演算する
PDLでは複数の要素をまとめて演算することができます。以下のデータを見てください。
use PDL; my $data = pdl [ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12] ];
1次元のランクを減らす和の演算
まず1次元のランクを減らす和の演算を行ってみましょう。上記のデータが次のようになるイメージです。
[6] [15] [24] [33]
和を求めるにはsumoverメソッドを使用します。someoverはPDL::Ufuncにおいて実装されています。
# 1次元のランクを減らす和の演算 my $data_sumover1 = $data->sumover;
sumoverメソッドは含まれる値が整数型の時に利用してください。浮動小数点の場合は代わりにdsomeoverを使ってください。
ランクを減らす演算を行うと、次元はひとつ減り次のようなデータになります。
[6, 15, 24, 33]
2次元のランクを減らす和の演算
上記の例では1次元のランクを減らす和の演算を行いました。次は2次元のランクを減らす和の演算を行ってみましょう。この演算を行うには、xchgメソッドで1次元と2次元の位置の交換を行ってから、someover関数を使用します。
# 2次元のランクを減らす和の演算 my $data_sumover2 = $data->xchg(0, 1)->sumover;
次のようなデータを取得できます。
[22 26 30]
また次元の位置を移動させるメソッドにはxchgの他にmv, reorderがあるので調べてみましょう。
次元を減らす他の演算を行うメソッド
sumover以外にもPDL::Ufuncでは、同じタイプの演算を行うメソッドが定義されています。
演算 | メソッド |
平均 | average, daverage |
中央値 | medover, medoddover |
最頻値 | modeover |
積 | prodover, dprodover |
積の累積 | cumuprodover, dcumuprodover |
合計の累積 | cumusumover, dcumusumover |
and演算 | andover |
or演算 | orover |
ビットワイズアンド演算 | bandover |
ビットワイズオアー演算 | borover |
サンプル
実行できるサンプルです。
use strict; use warnings; use PDL; my $data = pdl [ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12] ]; # 1次元のランクを減らす和の演算 my $data_sumover1 = $data->sumover; print "$data_sumover\n"; # 2次元のランクを減らす和の演算 my $data_sumover2 = $data->xchg(0, 1)->sumover; print "$data_sumover2\n";