Perl入門ゼミ

テキスト処理、Linuxサーバー管理、Web開発ならPerl
  1. Perl
  2. モジュール
  3. PDL

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";
Qiitaで
「3分間Perlテキストクッキング」
という連載を始めました。
テキスト処理を題材にして、3分くらいで読める分量で、書いていきます。
文字コード、テキストデータ、コンピュータにおけるテキストの扱いなど、ソフトウェアの基礎の話題も
3分間Perlテキストクッキング