【100 numpy exercises】でnumpy力を鍛える!(41〜50問目)


こんにちは!

前回はnumpy力を鍛えるために31~40問をやっていきました。

前回の記事はこちら

それでは前回に引き続き100 numpy exercisesを使ってnumpyの学習をしていきたいと思います!

今回は41~50問をやっていきます。

41. How to sum a small array faster than np.sum? (★★☆)

41. 小さな配列の合計をnp.sumよりも速く行うには?
100_numpy_exercises.ipynb(41)
Z = np.arange(10)
np.add.reduce(Z)

基本的にはnp.add.reducenp.sumは同じようです。ただ2つのパフォーマンス的には異なる部分があって、比較的小さい配列サイズの場合np.add.reduceは約2倍高速です。理由を簡単に言うと、引数がnumpy配列の場合、np.sumは最終的にadd.reduceを呼び出しています。つまりnp.sumの方が、少し回り道しているということです。

実行結果は以下の通りです。

100_numpy_exercises.ipynb(41)-output
45

42. Consider two random array A and B, check if they are equal (★★☆)

42. 2つのランダムな配列AとBを考え、それらが等しいかどうかをチェックする
100_numpy_exercises.ipynb(42)
A = np.random.randint(0,2,5)
B = np.random.randint(0,2,5)

# 配列の形状が同一で、値の比較に許容範囲があると仮定すると
equal = np.allclose(A,B)
print(equal)

# 形状と要素の値の両方をチェックし、許容範囲はない(値は完全に一致しなければならない)
equal = np.array_equal(A,B)
print(equal)

np.allclosenp.array_equalはどちらも全ての要素が等しいと判断する関数ですが、違いはnp.array_equalはお同じ位置に欠損値NaNが含まれている時にFalseになるのに対し、np.allcloseではNaNが含まれていても正常な判断をしてくれます。

実行結果は以下の通りです。

100_numpy_exercises.ipynb(42)-output
False

43. Make an array immutable (read-only) (★★☆)

43. 配列をイミュータブル(読み取り専用)にする
100_numpy_exercises.ipynb(43)
Z = np.zeros(10)
Z.flags.writeable = False
Z[0] = 1

ndarrayのメモリレイアウト情報はflagsというところに格納されています。なので、そのflagsに対して、.属性名[属性名]で各属性の値を確認できます。今回はZ.flags.writeableFalseとすることで設定を変えました。

実行結果は以下の通りです。

100_numpy_exercises.ipynb(43)-output
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-9-dcc5e7f145b5> in <module>
      1 Z = np.zeros(10)
      2 Z.flags.writeable = False
----> 3 Z[0] = 1

ValueError: assignment destination is read-only

書き換え禁止であるため、エラーが出ました。

44. Consider a random 10x2 matrix representing cartesian coordinates, convert them to polar coordinates (★★☆)

44. カルテシアン座標を表すランダムな10×2の行列を考え、それを極座標に変換する
100_numpy_exercises.ipynb(44)
Z = np.random.random((10,2))
X,Y = Z[:,0], Z[:,1]
R = np.sqrt(X**2+Y**2)
T = np.arctan2(Y,X)
print(R)
print(T)

カルテシアン座標から極座標に変換するには、カルテシアン座標から得られるX,Yの座標を点(X, Y)へのベクトルとそのベクトルとのx軸の正の方向となす角度を求められればいいです。np.arctan2は逆正接を返す関数です。np.arctanもあるが、極座標平面で考える場合はnp.arctan2の方が適当らしいです。

実行結果は以下の通りです。

100_numpy_exercises.ipynb(44)-output
[0.48243444 0.76827448 0.45851376 0.25038729 0.41031109 1.2707377
 1.08532695 0.89913902 0.77051956 0.9674972 ]
[0.46443241 1.20021712 1.27816847 0.44607712 0.10433143 0.88930636
 0.82714798 0.87287693 0.8056371  0.88556941]

45. Create random vector of size 10 and replace the maximum value by 0 (★★☆)

45. サイズ10のランダムなベクトルを作り、最大値を0に置き換える
100_numpy_exercises.ipynb(45)
Z = np.random.random(10)
Z[Z.argmax()] = 0
print(Z)

argmaxは配列の最大要素のインデックスを返す関数です。

実行結果は以下の通りです。

100_numpy_exercises.ipynb(45)-output
[0.50631072 0.9864651  0.00524783 0.2320057  0.68052622 0.
 0.70729782 0.23483311 0.1575789  0.00649772]

6番目の要素が0に置き換わっていることを確認できました。

46. Create a structured array with x and y coordinates covering the [0,1]x[0,1] area (★★☆)

46. [0,1]×[0,1]の領域をカバーするx,y座標の構造化配列を作成する
100_numpy_exercises.ipynb(46)
Z = np.zeros((5,5), [('x',float),('y',float)])
Z['x'], Z['y'] = np.meshgrid(np.linspace(0,1,5),
                             np.linspace(0,1,5))
print(Z)b

np.meshgridは配列の要素から格子列を作成します。**np.linspaceで生成される0から1までの等差数列をnp.meshgird*の第一引数、第二引数に入れれば指定した領域をカバーするx,y座標の構造化配列を作成することができます。

実行結果は以下の通りです。

100_numpy_exercises.ipynb(46)-output
[[(0.  , 0.  ) (0.25, 0.  ) (0.5 , 0.  ) (0.75, 0.  ) (1.  , 0.  )]
 [(0.  , 0.25) (0.25, 0.25) (0.5 , 0.25) (0.75, 0.25) (1.  , 0.25)]
 [(0.  , 0.5 ) (0.25, 0.5 ) (0.5 , 0.5 ) (0.75, 0.5 ) (1.  , 0.5 )]
 [(0.  , 0.75) (0.25, 0.75) (0.5 , 0.75) (0.75, 0.75) (1.  , 0.75)]
 [(0.  , 1.  ) (0.25, 1.  ) (0.5 , 1.  ) (0.75, 1.  ) (1.  , 1.  )]]

47. Given two arrays, X and Y, construct the Cauchy matrix C (Cij =1/(xi - yj)) (★★☆)

47. XとYの2つの配列が与えられたとき,コーシー行列C(Cij =1/(xi - yj))を構成しなさい
100_numpy_exercises.ipynb(47)
X = np.arange(8)
Y = X + 0.5
C = 1.0 / np.subtract.outer(X, Y)
print(np.linalg.det(C))

outerは2つの配列の全ての要素の組み合わせに対して、関数を適用することができます。コーシー行列は簡単に言うと部分行列の行列積の組み合わせを全て足すと求めたい行列の行列積を求められるというものです。コーシー行列の式を行列式を求める際に使うnp.linalg.detに渡せばXとYの行列積を求めることができます。

実行結果は以下の通りです。

100_numpy_exercises.ipynb(47)-output
3638.1636371179666

48. Print the minimum and maximum representable value for each numpy scalar type (★★☆)

48. numpyのスカラー型ごとに、表現可能な最小値と最大値を印刷する
100_numpy_exercises.ipynb(48)
for dtype in [np.int8, np.int32, np.int64]:
   print(np.iinfo(dtype).min)
   print(np.iinfo(dtype).max)
for dtype in [np.float32, np.float64]:
   print(np.finfo(dtype).min)
   print(np.finfo(dtype).max)
   print(np.finfo(dtype).eps)

np.iinfonp.finfoはそれぞれint型,float型の取りうる値の範囲を確認できます。minで最小値、maxで最大値の確認ができます。

実行結果は以下の通りです。

100_numpy_exercises.ipynb(48)-output
-128
127
-2147483648
2147483647
-9223372036854775808
9223372036854775807
-3.4028235e+38
3.4028235e+38
1.1920929e-07
-1.7976931348623157e+308
1.7976931348623157e+308
2.220446049250313e-16

49. How to print all the values of an array? (★★☆)

49. 配列のすべての値を表示するには?
100_numpy_exercises.ipynb(49)
np.set_printoptions(threshold=float("inf"))
Z = np.zeros((40,40))
print(Z)

ndarrayの要素数がパラメータthresholdで設定した値より大きいと省略されて表示されます。ちなみにthresholdのデフォルトは1000らしいです。
配列の全ての値を表示するにはfloat型にしてinfにすると無限大となるので全ての値を表示することができます。

100_numpy_exercises.ipynb(49)-output
np.set_printoptions(threshold=float("inf"))
Z = np.zeros((40,40))
print(Z)

実行結果は長いので省略します。(笑)

50. How to find the closest value (to a given scalar) in a vector? (★★☆)

50. ベクトルの中で、(与えられたスカラーに)最も近い値を見つけるには?
100_numpy_exercises.ipynb(50)
Z = np.arange(100)
v = np.random.uniform(0,100)
index = (np.abs(Z-v)).argmin()
print(Z[index])

2つのベクトルの最も近い値を求めれば良いので、2つのベクトルの差を算出して絶対値を出して、その中の最小値のインデックスから最も近い値を求めればいいです。

実行結果は以下の通りです。

100_numpy_exercises.ipynb(50)-output
1

今回は以上になります。
次回は51~60問をやっていきます。

次回の記事はこちら