見出し画像

AI 実装検定への道(5)

AI 実装検定 A級合格へ向けて学習を進めています。

前回投稿が4回目で、引き続きGoogle Colaboratoryを利用してプログラミングの章を進めて書いています。

第4回では、NumPyの情報取得機能を利用して、8×8の配列(行列)で示された0〜9までの手書き文字のデータセット(digit)を例として画像を読み込み、それぞれマス目の濃淡を0〜16で指定されて表されることを学び、その次に引き続きNumPyを利用して配列の一部抽出と連結を学び進めました。今回は途中までとなりましたが、「digits」「target」「images」「shape」「ndim」「size」を利用して、その配列(行列)に関する「target」「images」に対して「shape」=形状、「ndim」=次元数、「size」=含まれる数値の個数などをカウントしてきました。また、前回に引き続きrandamを利用してランダムに数値をピックアップし、1次元ないしは2次元の配列(行列)を生成し、x1、x2、そしてx3を用意するところまで進めてきました。中には、ある位置の数値を指定して置換するという「x2[1,2]=3」のような記述も含まれています。

ついつい、公式テキストでは一連のものとして描かれているため見逃してしまいがちですが、この一連のプログラムは「NumPy」を使って動かしています。勉強を再開するのに、公式テキストにあるままを入力し実行すると、見慣れないエラーが出てくることがあります。NumPyが読み込まれていません!的なエラーですが、今一度「import numpy as np」の記述を追加するか、Google Colaboratory上の再開するプログラムの前回に戻って、 import numpy as npに記述のある部分を再実行してから進めていくといいでしょう。

それでは、前回最後に、x1、x2、そしてx3を用意したので、今回はここから開始していきます。公式テキストでは199ページの「view」で取り出すというところから開始です。

viewで取り出す

今一度、x3を再確定させます。
Pythonを再稼働して、NumPyを読み込ませることから再スタートするので、「import numpy as np」を忘れないように記述します。(以降、できるだけ省略せずに書いていきますが、省いちゃう場合もあるかも)

(コード記述)
import numpy as np
x3=np.random.randint(15,size=(3,4))
x3

上記プログラムで、ランダムに0〜14までの数字で3×4の行列(配列)を生成しました。

(結果)
array([[10, 5, 7, 0],
  [12, 7, 3, 2],
  [ 2, 9, 1, 7]])

では、次にviewの機能を試します。
上記3×4の行列(配列)から、2×2の部分だけを抽出します。

(コード記述)
import numpy as np
x3_sub=x3[:2,:2]
x3_sub

(結果)
array([[10, 5],
  [12, 7]])

結果は上記の通り、上述の3×4の行列(配列)から、2×2の部分だけを抽出できました。ここで、「:2」の記述について公式テキストではきちんと解説してくれています。0からの場合、0の記述を省略できるので、「:2」となっていますが、省略しない場合、本来は「0:2」(0番目=即ち1番目から、2番目の手前まで)という記述。では、次に3〜4列目のみを抜き出すには下記のように記述します。

(コード記述)
import numpy as np
x3_sub2=x3[:,2:]
x3_sub2

(結果)
array([[7, 0],
[3, 2],
[1, 7]])

これもうまく抽出できました。
今度は、中央の2行目から2〜3列目を抽出します。

(コード記述)
import numpy as np
x3_sub3=x3[1:,1:3]
x3_sub3

(結果)
array([[7, 3],
  [9, 1]])

ここまでに抽出時に、x3_sub、x3_sub2、x3_sub3と指定しているのを理解しておきましょう。次に、x3_sub3と抽出した行列(配列)から1の部分に13で置き換えてみます。前回やったように場所を指定して、置き換える数値を=で示します。

(コード記述)
import numpy as np
x3_sub3[1,1]=13
x3_sub3

(結果)
array([[ 7, 3],
[ 9, 13]])

間違いなく、右下の1が13に置き換わりました。
さて、置き換えた数値で元の行列(配列)x3が変わっているのか、改めて確認してみます。

(コード記述)
x3

(結果)
array([[10, 5, 7, 0],
[12, 7, 3, 2],
[ 2, 9, 13, 7]])

このように3行目3列目の数値が、確かに13に変わっています。
sub1〜3で抽出したプログラムでは、常にx3_sub1〜3とx3に対する記述をしてきたので、しっかり反映されたことが理解できました。viewは元の行列(配列)と関連づけて操作をしているということになるようです。
201ページ最下端の記述参照

逆に、viewでの操作は、元の行列(配列)と関連づいているために、この操作により書き換わってしまうため注意が必要ということになります。このため、元の行列(配列)と関連づけない方法として、viewに代わりcopyという方法があるそうです。
202ページ最上段センテンス参照

copyの利用

x1〜x3までは、既に作成してきましたので、新たにx4を用意して実行します。0〜15までのランダムな数値で埋めた3×5の行列(配列)をx4として準備します。

(コード記述)
import numpy as np
x4=np.random.randint(16,size=(3,5))
x4

(結果)
array([[ 2, 2, 11, 8, 13],
[ 5, 1, 12, 11, 4],
[10, 1, 12, 1, 11]])

ここで、2×3の行列(配列)をx4から抽出します。

(コード記述)
import numpy as np
x4_sub_copy=x4[:2,:3].copy()
x4_sub_copy

(結果)
array([[ 2, 2, 11],
  [ 5, 1, 12]])

確かに抽出されました。viewの場合は、viewという記述が含まれませんでしたが、copyの場合は.copy()と記述が追加されます。また同時に、x4_sub_copyと記述されている点にも留意しましょう。
次に、この中から、下の1を9に置き換えてみます。

(コード記述)
x4_sub_copy[1,1]=9
x4_sub_copy

(結果)
array([[ 2, 2, 11],
  [ 5, 9, 12]])

確かに、下段中央の1が9に変換されました。
viewを使った場合は、これで元のx4が変わってしまいましたが、copyでは実際どうなのでしょうか?今一度、x4を呼び出してみます。

(コード記述)
x4

(結果)
array([[ 2, 2, 11, 8, 13],
[ 5, 1, 12, 11, 4],
[10, 1, 12, 1, 11]])

見事、元通りの3×5の行列(配列)が表示されました。
こういうのはテストする時に利用するんですかね??

公式テキスト203ページには、メモリについての注意があります。
viewの場合は、元のデータを触っているので新たな保存容量を必要としないが、copyの場合はそのまま新たなデータを生成してしまうので、追加の保存容量を必要とすることになるとのこと。上記のようなわずかなデータでは影響がありませんが、実際のデータを考えると確かに、このように理解ができるというものです。

行列(配列)の形状変更

機械学習や深層学習(ディープラーニング)のプログラムを書く時に、行列(配列)の形状変更を活用することがあるそうです。現段階では理解がありませんが、公式テキストに沿って進めていきます。

まず、1〜12までの数値で構成された1×12の配列を準備します。

(コード記述)
import numpy as np
grid=np.arange(1,13)
grid

(結果)
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])

これを、行列(配列)の形状(shape)を変える「reshape」を利用するそうです。「reshape」を利用して4×3の行列(配列)に形状変更します。

(コード記述)
grid.reshape((4,3))

(結果)
array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]])

確かに、1行の行列(配列)から4×3の行列(配列)に形状変更できました。
公式テキスト204ページに進んでいます
ここでは、12の数値を利用したので、4×3=12の行列(配列)に形状変更できましたが、そうでない場合はエラー表示されます。
例えば、2×5に変更しようとしてみます。

(コード記述)
grid.reshape((2,5))

ちょっと意味が分かりませんが、下記のようなエラーが表示されました。
公式テキストでは、「NameError」と表示されていますが、ここでは「ValueError」と出ています。size が12の行列(配列)を(2,5)の形状(shape)の形状変更(reshape)出来ません!・・・そんな意味でしょうか?

(結果)
----------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-15-efbee3fb276d> in <module>
----> 1 grid.reshape((2,5))

ValueError: cannot reshape array of size 12 into shape (2,5)

2×4の行列(配列)に形状変更しようとしても・・・

(コード記述)
grid.reshape((2,4))

(結果)
----------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-16-8b08fe824b79> in <module>
----> 1 grid.reshape((2,4))

ValueError: cannot reshape array of size 12 into shape (2,4)

このように、同様に処理できないとのエラーが表示されます。
(ここで、よくよく見ると・・・ipython-input-16-の後の文字列が変わっていることに気づきました。何を意味しているのかは、現段階では理解できていません。)

一次元配列を使ってベクトル表現(1次元配列)から行列表現(2次元配列)にする

(コード記述)
import numpy as np

x=np.array([5,8])
x

(結果)
array([5, 8])

まずは、1次元配列を生成しました。
次に、reshapeを利用して、これを2次元配列に変換します。

(コード記述)
x.reshape((1,2))

(結果)
array([[5, 8]])

これだと分かりにくいんですが、[ ]が[[ ]]になって二重になったことに気づきます。reshpeの代わりにnewaxisを使っても同様の結果を得られるようです。

(コード記述)
x[np.newaxis]

(結果)
array([[5, 8]])

記述の仕方が若干異なるので、覚えにくいですが・・・

1次元配列、行ベクトルから、次は列ベクトルへ

(コード記述)
x.reshape((2,1))

(結果)
array([[5],
  [8]])

これも、newaxisを使って同様に処理できるようです。

(コード記述)
x[:,np.newaxis]

(結果)
array([[5],
  [8]])

前述は、x[np.newaxis]と表し、行の処理をしたようですが、ここではx[:,np.newaxis]と表し、列の方の処理をしたように見えます。

配列を連結する「concatenate」

まずは、xに3、4、yに5、6と行列(配列)を作成します。

(コード記述)
import numpy as np
x=np.array([3,4])
x

(結果)
array([3, 4])

(コード記述)
y=np.array([5,6])
y

(結果)
array([5, 6])

このxとyの行列を「concatenate」で連結します。

(コード記述)
np.concatenate([x,y])

(結果)
array([3, 4, 5, 6])

次に、もう一つ7、8、9を持つzを生成します。

(コード記述)
z=np.array([7,8,9])
z

(結果)
array([7, 8, 9])

で、x、y、zを「concatenate」で連結させるんですね。

(コード記述)
np.concatenate([x,y,z])

(結果)
array([3, 4, 5, 6, 7, 8, 9])


今回は、もう少し進みたいところでしたが、ここまでにしておきます。

行列(配列)を生成し、viewで取り出し、一部を修正したり、元データを変更したくない場合は、copyを使う方法。行列(配列)の形状(shape)を変更するのに、reshapeを使うこと。reshapeならびにnewaxisを利用して、1次元から2次元へ、行、列共に変更をして、concatenateを利用した連結をするところまで学びました。

公式テキストでは、207ページの途中までです。

今日のところは以上。


この記事が気に入ったらサポートをしてみませんか?