とある変人のお道具箱

技術系のことにについて幅広く触れていくブログです

Numpyの練習 100 Numpy Exercises Q16-Q20

前回はこちら

www.henjins-toolbox.tech
この記事の続きです。今回は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()を使うと楽にすることが可能です。
今回の引数を少し説明すると、width=1というのが境界線の太さです。mode='constant'というのが標準モードを選択しています。他にもモードがたくさんあるので今回は説明しません。constant_value=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のほうが大きく感じますが、infもnanも非数なので比較はできません。よってこの式は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 5x5 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 8x8 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()は配列を作ってから数える必要がありません。