前回はこちら

前回記事の続きです。今回は100 numpy execiseのQ16-Q20を解いていきます。

16. How to add a border (filled with 0’s) around an existing array?

(既存の配列の周りに0で境界線を追加しなさい)

Z = np.ones((5,5))
Z = np.pad(Z,pad_width=1,mode='constant',constant_values=0)
print(Z)
[[0. 0. 0. 0. 0. 0. 0.]
 [0. 1. 1. 1. 1. 1. 0.]
 [0. 1. 1. 1. 1. 1. 0.]
 [0. 1. 1. 1. 1. 1. 0.]
 [0. 1. 1. 1. 1. 1. 0.]
 [0. 1. 1. 1. 1. 1. 0.]
 [0. 0. 0. 0. 0. 0. 0.]]

Q15との違いは元あった配列の値を変更するのではなく、元あった配列の外側に数値を追加するという点です。 この場合は np.pad() を使うと楽にすることが可能です。 今回の引数を少し説明すると、pad_width=1 というのが境界線の太さです。mode='constant' というのが標準モードを選択しています。他にもモードがたくさんあるので今回は説明しません。constant_values=0 というのは境界線の文字の指定ですね。ここで説明してもよくわからないと思うので、実際に値を変えて実行してみるとわかりやすいと思います。

17. What is the result of the following expression?

(これらを実行したらどうなりますか?)

一つずつ解説していきます

print(0 * np.nan)
nan

nan というのは null とほぼ同じと考えてもらっていいと思います。ただ None とは異なります。 None は存在自体がないことを表しています。numpy.nan は数ではないものを表しています。このあたりの説明は難しいのでわかりやすい記事を貼っておきます。 【python】0,None,numpy.nanの比較 – Qiita 感覚的に理解してほしいのですが、何に nan をかけても結果は nan になります。

print(np.nan == np.nan)
False

これは予想と違ったかもしれません。一見左辺と右辺は同じに見えますが、先程も説明したとおり numpy.nan は数ではない(非数)なので比較はできないのです。

print(np.inf > np.nan)
False

np.inf は無限大を表すものです。一見 inf のほうが大きく感じますが、infnan も非数なので比較はできません。よってこの式は False になります。

print(np.nan - np.nan)
nan

nan から nan を引いても 0 にはなりません。これも今までと同様に nan が非数だからです。非数は演算をすることができないのです。

print(np.nan in set([np.nan]))
True

nan は非数ですが存在自体はあります。よって set の要素として nan を持っているのでこれは True になります。

print(0.3 == 3 * 0.1)
False

これはかなりややこしい話なのでここではきっちりと説明できませんが、Python の float 型は C 言語の double 型を使って実装されていることが理由です。Python の浮動小数点値の精度は 53 ビットなので、ややこしい理由があります。詳しく知りたい人はググってください。これはコンピューターの仕組みなどに関わってくることなので一旦飛ばします。

18. Create a 5×5 matrix with values 1,2,3,4 just below the diagonal

対角線のすぐ下に1,2,3,4の値を持つ5×5行列を作れ

Z = np.diag(1+np.arange(4),k=-1)
print(Z)

np.diag() に1次元の行列を渡すとそれを対角成分とする対角行列を返してくれます。k=-1 と指定しているのは下向きに一つずらすことを指定しています。(ずらすという表現であってるのかな?)

19. Create a 8×8 matrix and fill it with a checkerboard pattern

(チェッカーボード状の8×8行列を作れ)

Z = np.zeros((8,8),dtype=int)
#print(Z)
Z[1::2,::2] = 1
#print(Z)
Z[::2,1::2] = 2
print(Z)
[[0 2 0 2 0 2 0 2]
 [1 0 1 0 1 0 1 0]
 [0 2 0 2 0 2 0 2]
 [1 0 1 0 1 0 1 0]
 [0 2 0 2 0 2 0 2]
 [1 0 1 0 1 0 1 0]
 [0 2 0 2 0 2 0 2]
 [1 0 1 0 1 0 1 0]]

要素が全て0の8×8行列を作成してから1と2を入れていっています。 1::2 は1を元にして1個間隔、::2 は0を元にして1個間隔で要素を指定できます。それを利用して行と列をうまくずらして1,2を入れています。

20. Consider a (6,7,8) shape array, what is the index (x,y,z) of the 100th element?

(shapeが(6,7,8)の配列において、100番目の要素の位置(x,y,z)を求めよ)

print(np.unravel_index(100,(6,7,8)))
(1, 5, 4)

100番目の要素が (x,y,z)=(1,5,4) の位置にあることがわかりました。 unravel_index() は配列を作ってから数える必要がありません。