LoginSignup
3
1

More than 1 year has passed since last update.

多次元配列について

Last updated at Posted at 2021-08-16

3.3ではNumpyを使って多次元配列の計算を行います。

3.3.1 多次元配列

多次元配列は簡単にいうと『数字の集合』です。
具体的には以下のようなものがあります。

  • 数字が
    • ただそこに存在している(0次元配列)
    • 一列に並んだものや長方形状に並んだもの(1、2次元配列)
    • N次元状に並んでいるもの(3次元以上)

多次元配列.png

3次元配列.png

それではNumpyを使って多次元配列を作成していきましょう。

1. 1次元配列の作成

1次元配列
>>> import numpy as np
>>> A = np.array([1,2,3,4])
>>> print(A)
[1,2,3,4]
>>>np.ndim(A)   #配列の次元数を取得
1
>>>A.shape      #配列の形状をshapeというインスタンス変数で取得
(4,)            #タプルになっていることに注意
>>>A.shape[0]
4

上の例ではAは1次元の配列であり、4つの要素から構成されていることがわかります。

※ここではA.shapeの結果がタプルになっていることに注意しましょう。
これは1次元配列の場合であっても、多次元配列の場合と同じ統一された結果を返すからです。

タプルになっている理由
(4,3)       #2次元配列の場合 → タプル
(4,3,2)     #3次元配列の場合 → タプル

#1次元配列でも統一してタプルで表示

2. 2次元配列の作成

続いて2次元配列を作成していきます。

2次元配列
>>> B = np.array([[1,2], [3,4], [5,6]])
>>> print(B)
[[1 2]
 [3 4]
 [5 6]
>>> np.ndim(B)
2
>>> np.shape
(3,2)

ここでは「3✖️2」の配列であるBを作成しました。

「3✖️2」の配列とは
最初の次元に3つの要素があり、次の次元に要素が2つあるという意味です。

なお、最初の次元は0番目の次元、次の次元は1番目の次元に対応します。
(Pythonのインデックスは0から始まります。)

また、2次元配列は以下に示すように行列とも呼びます。
スクリーンショット 2021-08-16 15.11.07.png

3.3.2 行列の内積

続いて、行列(2次元配列)の内積について説明します。

行列の内積は計算の手順が定義されており、例えば次のように行ないます。

スクリーンショット 2021-08-16 15.17.58.png

そして、この計算をPythonで実装すると次のようになります。

Pythonで行列の内積を計算
>>> A = np.array([[1,2], [3,4]])
>>> A.shape
(2,2)
>>> B = np.array([[5,6], [7,8]])
>>> B.shape
(2,2)
>>> np.dot(A,B)      #引数としてNumPy配列を2つ取り、それらの配列の内積を結果として返す関数
array([[19,22],      #結合法則,分配法則は成立するが,交換法則は成立しない
       [43,50]])

ここで注意の必要なことがあります。
それは、行列の積では、被演算子(A,B)の順番が異なると結果も異なるということです。



先ほどは2✖️2の形状の行列についての計算を行いましたが、別の形状の行列についても同様に計算を行うことができます。

例)2✖️3の行列と3✖️2の行列の積
>>> A = np.array([[1,2,3], [4,5,6]])
>>> A.shape       
(2,3)
>>> B = np.array([[1,2], [3,4], [5,6]]) 
>>> B.shape
(3,2)
>>>np.dot(A,B)
array([[22, 28],
       [49, 64]])

2✖️3の行列と3✖️2の行列の積は上のように実装できます。
ここでも注意点があります。それは
行列の1次元目の要素数(列数)と行列Bの0次元目の要素数(行数)を同じ値にする必要がある
というものです。

もしこの値が異なれば、行列の計算はできません。
例えば、Pythonで行うとすれば、以下のようなエラーが出力されます。

2✖️3の行列と2✖️2の行列の積~エラー内容~
>>> C = np.array([[1,2], [3,4]])
>>> C.shape
(2,2)
>>> A.shape
(2,3)
>>> np.dot(A, C)
Traceback (most recent call last):
  File "<stdint>", line 1, in <module>
ValueError: shapes (2,3) and (2,2) not aligned: 3 (dim 1) !=2(dim 0 ) 
#↑行列Aの1次元目と行列Cの0次元目の次元数が一致していないという意味

つまり、多次元配列の積では、2つの行列で対応する次元を一致させる必要があるということです。
大切なことなのでもう一度図を用いて説明しておきます。

スクリーンショット 2021-08-16 17.14.47.png

計算結果である行列Cは、行列Aの行数と行列Bの列数から構成される ←これも重要な点です。

なお、Aが2次元の行列で、Bが1次元の配列でも以下に示すように「対応する次元の要素数を一致させる」という同じ原則が成り立ちます。

スクリーンショット 2021-08-16 17.25.50.png

Pythonで実装すると次のようになります。

対応する次元の要素数を一致させる~行列と配列~
>>> A = np.array([[1,2], [3,4], [5,6]]) 
>>> A.shape
(3,2)
>>> B =np.array([7,8])
>>> B.shape
(2,)
>>>np.dot(A, B)
array([23, 53, 83])

3.3.3 ニューラルネットワークの内積

それでは次はNumpy行列を使ってニューラルネットワークの実装を行います。
ここでは以下の簡単なニューラルネットワークを対象とします。
※バイアスと活性化関数は省略し、重みだけがあるとする

スクリーンショット 2021-08-16 17.35.23.png

実装に関してはX、W、Yの形状に注意しましょう。
特にXとWの対応する次元の要素数が一致していることが重要な点です。

スクリーンショット 2021-08-16 17.41.45.png

ニューラルネットワークの実装~簡易版~
>>> X = np.array([1,2])
>>> X.shape
(2,)
>>> W =np.array([[1,3,5], [2,4,6]])
>>> print(W)
[[1 3 5]
 [2 4 6]
>>> W.shape
(2,3)
>>> Y = np.dot(X, W)
>>> print(Y)
[ 5 11 17]

np.dot(多次元配列のドット積)を使えば、Yの結果を一度に計算することができます。
これが意味することは、例えYの要素数が100や1000だとしても、一度に計算できるということです。

もし使わなければ、Yの要素を一つずつ取り出して計算(or for文を使って計算をしなければならない)のでとても面倒です。

そのため、行列の内積によって一度で計算ができるというテクニックは、実装上とても重要であると言えます。
 

3
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1