100 numpy exercisesを40問解いてみた

# 100 numpy exercisesを解いてみた
## 100 numpy exercisesとは
　numpyというpythonの有名なライブラリがあるのですが、その練習問題100題がgithubに公開されている。それが100 numpy exercisesです。サイトを下記に示す。

githubのリンク：https://github.com/rougier/numpy-100/

この中には
問題のみのファイル(100_Numpy_exercises.md)、
ヒント付きのファイル(100_Numpy_exercises_with_hints.md)、
解答付きのファイル(100_Numpy_exercises_with_soliutions.md)、
ヒント・解答付きのファイル(100_Numpy_exercises_with_hints_with_soliutions.md)があり、
それらをダウンロードしてからオフラインで学習するのも良いのではないか。
難易度は（★☆☆，★★☆，★★★)の3段階に分かれている。

##解いてみる。

### まずは１～10

#### 1. Import the numpy package under the name "np" (★☆☆)
numpyのパッケージをnpの名前でImportしなさいという問題

~~~python
import numpy as np
~~~
で実行するとnumpyをnpとしてImportすることができる。

#### 2. Print the numpy version and the configuration (★☆☆)
numpyのバージョンと構成をPrintしなさいという問題

~~~python
print(np.__version__)
np.show_config()
~~~
これで、numpyのバージョンとconfigfileの場所が示すことができる。

#### 3. Create a null vector of size 10 (★☆☆)
サイズ10の０ベクトルを作る問題

~~~python
vector = np.zeros(10)
~~~
`.zero`で零ベクトルを作ることができる（2次元以上も括弧を中に作ることで作成可能）。実行すると、大きさ10の零ベクトルがvectorに作られる。

#### 4. How to find the memory size of any array (★☆☆)
いくつかの配列のメモリの大きさを見つける方法を示す問題。

~~~python
vector = np.zeros((10, 10))
print(vector, vector.itemsize, vector.size)
print("{} bites".format(vector.size * vector.itemsize))
~~~
`.itemsize` は1つの配列要素の長さをバイト単位で指定する属性
`.size`は配列の大きさを指定する属性
であるのでそれぞれを掛けた積を配列のメモリの大きさとして出力した。

#### 5. How to get the documentation of the numpy add function from the command line? (★☆☆)
コマンドラインからnumpy.add関数の文章を取得する方法を示す問題。

`.info()`で各関数のヘルプ情報を取得するので

~~~pyhton
>command line
python
>>> import numpy as np
>>> np.info(np.add)
~~~
とコマンドラインに打ち込むと

```python

add(x1, x2, /, out=None, *, where=True, casting='same_kind', order='K', dtype=None, subok=True[, signature, extobj])

Add arguments element-wise.
#（以下省略）
```
と出力される。

#### 6. Create a null vector of size 10 but the fifth value which is 1 (★☆☆)
5番目の値が1だけのサイズが10の零行列を作る

~~~python
vector = np.zeros(10)
vector[4] = 1
~~~
と先に10が大きさの零行列を作ってから5番目の値を1に変えることで作成することができる。

#### 7. Create a vector with values ranging from 10 to 49 (★☆☆)
ranging:並べている
10から49までを並べた値のベクトルを作る

~~~python
vector = np.arange(10,50)
~~~
`.arange([n,]m)`で[n以上]m未満の順列を作成する。
forと同じで左側以上右側未満の数列なので+1する必要があることに注意する。

#### 8. Reverse a vector (first element becomes last) (★☆☆)
ベクトルを反転させる問題。（最初の要素が最後の要素になる。）

~~~python
vector = vector[::-1]
vector = np.fliplr([vector])[0]  # 1次元
vector = np.filplr(vector)  # 2次元から
~~~
`.filp`、`.filplr`を用いて反転することもできるが1次元の場合逆スライスを用いると簡単に反転ができる。（どのように反転するかによるが）

#### 9. Create a 3x3 matrix with values ranging from 0 to 8 (★☆☆)
0から8までの順列の値を持った3×3の行列(matrix)を作る問題

~~~python
vector = np.arange(9).reshape(3, 3)
~~~
`np.arange(9)`で0から8までの順列を作成し、
`reshape(3,3)`で3×3の行列に並べ替えることで求めるとこができる。

#### 10. Find indices of non-zero elements from [1,2,0,0,4,0]　 (★☆☆)
[1,2,0,0,4,0]のベクトルから0ではない要素の

~~~python
zero = np.nonzero([1, 2, 0, 0, 4, 0])
~~~
`np.nonzero`を用いると何番目が0でないかを求めることができる。

#### 11. Create a 3x3 identity matrix (★☆☆)
3×3の単位行列(identity matrix)を作成する問題。

~~~python
np.eye(3) #np.identity(3)でも可
~~~
`np.eye(n[,m])`はn行[m列,Noneの時はn列]の単位行列を作成することができる（正方行列以外でも作成可能）。
`np.identity(n)`はn行n列の単位行列を作成することができる（正方行列以外は作成不可）。

#### 12. Create a 3x3x3 array with random values (★☆☆)
3×3×3の乱数の行列を作成する。

~~~python
vector = np.random.rand(3, 3, 3）
~~~
`np.random.rand()`は0～1の間の小数の一様分布に則った乱数を作成し、`np.random.randn`は正規分布に則った乱数の行列を作成する。
また、3×3×3の0以上10未満の乱数の行列を作成するときは

~~~python
vector=np.random.randint(0,10,3**3).reshape(3,3,3)
~~~
と`.reshape()`を用いる。

#### 13. Create a 10x10 array with random values and find the minimum and maximum values (★☆☆)
10×10の乱数の行列を作成し、最小と最大の値の行列を作成する問題。

~~~python
vector = np.random.rand(10, 10)
Max = vector.max()
Min = vector.min()
~~~
`.max()`、`.min()`を用いることで、行列の最大値と最小値を求めることが出来る。

#### 14. Create a random vector of size 30 and find the mean value (★☆☆)
サイズが30の乱数の行列を作成し、平均値を求める問題

~~~python
vector = np.random.rand(10, 10)
Mean = vector.mean()
~~~
`.mean()`で行列の平均値を求めることが出来る。
`.std()`で行列の標準偏差を求めることが出来る。

#### 15. Create a 2d array with 1 on the border and 0 inside (★☆☆)
境界線が１、内側が０の2次元行列を作成する。

~~~python
vector = np.ones((10, 10))
vector[1:-1] = 0
~~~
で割り出すことが出来る。また、非効率ではあるが、
`.ones()`ではなく、`.zeros()`用いて

~~~python
vector = np.zeros((10, 10))
vector[0,:] = vector[:, -1] = vector[:, 0] = vector[-1,:] = 1
~~~
と求めることが出来る。

#### 16. How to add a border (filled with 0's) around an existing array? (★☆☆)
既存の配列の周りに境界線（０で塗りつぶされた）を追加するには？？

~~~python
z = np.ones((5, 5))
z = np.pad(z, pad_width=1, mode='constant', constant_values=0)
~~~
既存の配列zに`.pad()`を適応させることで、配列zに幅１値０を加えることができる。

#### 17. What is the result of the following expression? (★☆☆)
次の式の結果は？？

~~~python
0 * np.nan               >> nan
np.nan == np.nan         >> False
np.inf > np.nan          >> False
np.nan - np.nan          >> nan
np.nan in set([np.nan])  >> True
0.3 == 3 * 0.1           >> False
~~~
`np.nan`の取り扱いについて
`np.nan`は配列の取得の際に起きてしまう不測の値である。また.`np.inf`に`np.inf`を引いてしまう(`-np.inf`を足す)と得られる。
`np.nan`に何らかの四則演算をしても必ず`non`になってしまいます。
不測の値なので`np.non`と比べても（比較演算をしても）値は`False`を返します。
`non`であるかを判定する際には'np.isnon()'を用いるか`set()`を用いて集合に変換し、`np.non`であるかを調べることで求めることができます。
最後の行は２進小数で表すときに表せない小数になった際誤差が発生する。例えば`3*0.1=0.30000000000000004`となるので`False`になる。

#### 18. Create a 5x5 matrix with values 1,2,3,4 just below the diagonal (★☆☆)
対角線の真下（just below）に1,2,3,4以下の値を持った行列を作成する問題。

~~~python
z = np.diag(np.arange(5) + 1, k=-1)
~~~
`np.diag()`を用いることで対角行列を作成することができる。２次行列を入れると対角成分を出力させるが、１次の行列を入力するとそれを対角成分とする行列を出力する。また、kの値だけ対角行列をずらすことができる。

#### 19. Create a 8x8 matrix and fill it with a checkerboard pattern (★☆☆)
８×８の行列を作成し、すべてにチェックボードパターンを敷き詰める問題。

~~~python
z = np.zeros((8, 8))
z[1::2,::2] = 1 #２番目から１つ飛ばしで１を代入を２つ飛ばし
z[::2, 1::2] = 1 #始点から１つ飛ばしで１を代入を２列目から２つ飛ばし
~~~
説明が下手ですがスライスをうまく用いるとチェックボードバターンを敷き詰めることができる。

#### 20. Consider a (6,7,8) shape array, what is the index (x,y,z) of the 100th element?
(6,7,8)の形状の配列を考えてみる(consider)。100個目の(x,y,z)要素はなにか？

~~~python
print(np.unravel_index(100,(6,7,8)))
~~~
`np.unravel_index()`を活用して

#### 21. Create a checkerboard 8x8 matrix using the tile function (★☆☆)
8×8のチェックボード配列をtile関数を用いて作成する。

~~~python
Z = np.tile(np.array([[0, 1], [1, 0]]), (4, 4))
~~~
これで、([0,1],
　　　　[1,0])をタイルみたいに
配列(4,4)に並べるので、

~~~python
[[0 1 0 1 0 1 0 1]
 [1 0 1 0 1 0 1 0]
 [0 1 0 1 0 1 0 1]
 [1 0 1 0 1 0 1 0]
 [0 1 0 1 0 1 0 1]
 [1 0 1 0 1 0 1 0]
 [0 1 0 1 0 1 0 1]
 [1 0 1 0 1 0 1 0]]
~~~
とチェックボード配列を作成することができる。

#### 22. Normalize a 5x5 random matrix (★☆☆)
5×5の乱数配列を正則化する問題
正規化とは機械学習の際に過学習を防ぐ際に行われる重みを小さい値に保つ方法であり、

~~~python
z = np.random.random((5, 5))
x = np.random.random((5, 5))
#正則化
z = (z - np.min(z)) / (np.max(z) - np.min(z))
#標準化
x = (x - np.mean(x)) / np.std(x)
~~~

#### 23. Create a custom dtype that describes a color as four unsigned bytes (RGBA) (★☆☆)
色を4つの符号なしバイトで表記するカスタムdtypeを作成する問題。

~~~python
color = np.dtype([('r', np.ubyte, 1),
                  ('g', np.ubyte, 1),
                  ('b', np.ubyte, 1),
                  ('a', np.ubyte, 1)])
~~~

#### 24. Multiply a 5x3 matrix by a 3x2 matrix (real matrix product) (★☆☆)
5×3の行列に3×2の行列を乗算する（実数行列の積）

~~~python
left = np.random.random((5, 3))
right = np.random.random((3, 2))
ans = np.dot(left, right)
ans = left.dot(right)      #同義
~~~
`np.dot`で配列の内積を出力する

#### 25. Given a 1D array, negate all elements which are between 3 and 8, in place. (★☆☆)
１次元の配列が与えられたときその場で３から８までの空いたのすべての要素を否定します。

~~~python
Z = np.array(range(10))
Z[(3 < Z) & (Z < 8)] *= -1  # ３と８の間を-1する
~~~
とするとZ配列は
`[ 0  1  2  3 -4 -5 -6 -7  8  9]`

#### 26. What is the output of the following script? (★☆☆)
出力される次のスクリプトは何か。

~~~python
print(sum(range(5), -1))    #sum([配列](,始点))最後に始点の値を足す
from numpy import *
print(sum(range(5), -1))  #np.sum([配列](,軸))
~~~
組み込み関数とnumpyで仕様が異なるので値も異なる
#### 27. Consider an integer vector Z, which of these expressions are legal? (★☆☆)
整数の行列Zを考える。これらの表現のうち、どれが適してるか？

~~~python
Z = np.array([1,2,3])
# 各要素の累乗の形
Z**Z                #[ 1  4 27]
# シフト演算 2bit左に移動してから2bit右に移動したときの値
2 << Z >> 2         #[1 2 4]
# 全体を否定し各要素と比べる
Z < - Z             #[False False False]
# 各要素を虚数方向の大きさに。
1j*Z                #[0.+1.j 0.+2.j 0.+3.j]
# 
Z/1/1               #[1. 2. 3.]
Z < Z > Z           #Traceback (most recent call last):
~~~

#### 28. What are the result of the following expressions?
次の計算の答えは何？

~~~python
np.array(0) / np.array(0)   #RuntimeWarning: invalid value encountered in true_divide
np.array(0) // np.array(0)  #RuntimeWarning: invalid value encountered in true_divide
np.array([np.nan]).astype(int).astype(float)   #[-2.14748365e+09]
~~~
０での除算はできないので上二つは０除算エラーを吐く
3番目はnp.nanの型を強制的にint型にするとint型の最小値-2147483648になり、float型にすると桁が10桁以上なのでa+enで10の累乗の形で表される。

#### 29. How to round away from zero a float array ? (★☆☆)
どのようにfloatの配列を０から離れるように小数点を切るか。
絶対値にして小数点以下を切り上げして、符号を付け足すことで求めることができる。

~~~python
Z = np.random.uniform(-10, 10, 10)
# np.copysign(a, b) aにｂの符号を付け足す。
print(np.copysign(np.ceil(abs(Z)),Z))
~~~
そのままnp.ceilを行うと負の数が0から近づくので絶対値にしてから切り上げを行い、符号をつけると条件を満たす。

#### 30. How to find common values between two arrays? (★☆☆)
二つの配列の間の共通な値を見つける方法

~~~python
one = np.random.randint(0, 10, 10)
two = np.random.randint(0, 10, 10)
print(np.intersect1d(one, two))
~~~
intrsect：交差する
`np.intrsect1d`で配列の共通要素を抜き出す。

#### 31. How to ignore all numpy warnings (not recommended)? (★☆☆)
すべてのnumpyの警告を無視する方法（推奨されていない）
recommend：推奨する
ignore：無視する

~~~python
a = np.array(0)
#warning.simplefilterを用いて警告を無視する方法
warnings.simplefilter('ignore',category=RuntimeWarning)
print(1 / a)
#np.seterrを用いる方法（これだと０除算エラーのみ）
np.seterr(divide='ignore')
print(1 / a)
# np.errstate()を用いて０除算エラーを無視する方法
with np.errstate(divide='ignore'):
    divide = 1 / a
print(divide)
~~~
一番上のコードはコード全体に`RuntimeWarning`を無視する方法
二番上のコードはコード全体に`RuntimeWarning`の中のゼロ除算エラーを(divide='ignore')引数で指定し、無視するように設定することが可能
三番目のコードはwith文と`np.errstate`を用いることでwith文下の命令文でしか適応させない設定することができます。

#### 32. Is the following expressions true? (★☆☆)
次の式は真ですか？

~~~python
np.sqrt(-1) == np.emath.sqrt(-1)
>>False
~~~
```math
\sqrt{-1}=1i\\
```
であることは複素数を学んでいる人は理解出来るが、`np.sqrt()`を使うと出力が実数しかなく虚数で返すことが出来ないため、`Runtimeerror`を吐き、nonを出力する。
また、複素数を返すのが`np.emath.sqrt()`を用いると複素数で表すことが出来るので、0+j1を出力する。
`non`と`0+j1`は同じではないのでよって`False`を返す

#### 33. How to get the dates of yesterday, today and tomorrow? (★☆☆)
昨日、今日、明日のデータの入手方法とは

~~~python
Today = np.datetime64('today', 'D')
Yesterday = Today - np.timedelta64(1, 'D')
Tomorrow = Today + np.timedelta64(1, 'D')
print(Yesterday, Today, Tomorrow)
~~~
`np.datetime('today',"D")`を用いることで今日の日付を[第二変数によって年、月、日]取り出すことが出来る。また"today"を任意な整数に置き換えると1970-01-01に第二変数の値を足した値を出力する。

#### 34. How to get all the dates corresponding to the month of July 2016? (★★☆)
2016年６月に対応した全ての日を得る方法

~~~python
dates = np.arange("2016-06", '2016-07', dtype='datetime64[D]')
print(dates)
~~~
データ型を指定することで、2016年6月から2016年7月まで（含まれない）の日付を出力することが出来る。

#### 35. How to compute ((A+B)*(-A/2)) in place (without copy)? (★★☆)
その場で（copy無しで）((A+B)*(-A/2))を割り出す方法を求める。

~~~python
A = np.ones(3) * 1
B = np.ones(3) * 2  #適当な配列
print((A + B) * (-A / 2)) #愚直に実行
np.add(A, B, out=B)  #+ AとBを足しBに出力
np.divide(A, 2, out=A)  #/ Aと2の商をA出力
np.negative(A, out=A)  #- Aを負に出力
np.multiply(A, B,out=A)  #* AとBの積をAに出力
print(A)
~~~

#### 36. Extract the integer part of a random array using 5 different methods (★★☆)
5つの違った方法をを用いて乱数の整数部分を抜き出す方法

~~~python
Z = np.random.uniform(0, 10, 10) #適当な乱数
print(Z)
print(Z - Z % 1)  #１桁目以外の小数を引く
print(np.ceil(Z) - 1)  #切り上げ-1する
print(Z.astype(int)) #dtype(int) 配列の要素をint型に変換する
print(np.floor(Z)) #切り捨て(小数部分を取り除く)
print(np.trunc(Z))  #切り捨て(小さな部分の整数に丸める)
~~~
以上の方法で求めることが出来る。

#### 37. Create a 5x5 matrix with row values ranging from 0 to 4 (★★☆)
5×5の0から5までの範囲の行の値を持った5×5の行列を作成する問題

~~~python
Z = np.zeros((5, 5))  #零行列を作成する
Z += np.arange(5)  
#+=[0,1,2,3,4]が
#ブロードキャストするので列が一致していれば良い。（条件あり）
print(Z)
~~~
`np.arange(n)`でn以下の順列を作成する。

#### 38. Consider a generator function that generates 10 integers and use it to build an array (★☆☆)
10個の整数を生成する関数を考える

~~~python
def genereate():
   for x in range(10):
      yield x #yield：一旦関数内の動作を一時停止してxを出力
Z = np.fromiter(generate(),dtype=float,count=-1)
~~~
ここで特記することは`yield ` と`fromiter`である．
yieldは基本的に関数の中で用いられ，一旦関数内の動作を一時停止して値を返す．
関数内の動作を停止して値を返すreturnと異なって，値を返した後，処理が再開されるのでメモリの消費が抑えられる．
np.fromiterはiterableからobjectから新しい一次元配列を作成する．関数でdtypeは配列の要素の型，countはiterableから読み取る要素の値をそれぞれとしてある，

#### 39. Create a vector of size 10 with values ranging from 0 to 1, both excluded (★★☆)
0,1を除く0から1までの値を持つサイズ10のベクトルを作成する

```python
Z = np.linspace(0,1,11,endpoint=False)[1:]
print(Z)
#[0.09090909 0.18181818 0.27272727 0.36363636 0.45454545 0.54545455 0.63636364 0.72727273 0.81818182 0.90909091]
```
全体が等差数列であるベクトルを作成する方法として`arange`と`linspace`がある．
arangeは引数の考え方が`range()`と同様に初期値[初期値は０]と最終値と間隔（公差）[初期値は１]を適切に選択することで
初期値から始まり最終値で終わるベクトルを作成するとことが出来る．
また，linspaceは間隔（公差）ではなく要素数を設定する，
この問題では０と１を含まない大きさ10のベクトルを作成するのでnp.linspaceのendpointをFalseにすることで最終値を含まないベクトルを作成することが出来る．
また，初期値を削除するため，１つ多い大きさのベクトルを作成し．[1:]で0番目の要素である0を排除することで0,1を含まない大きさ10のベクトルを作成することが出来る．

#### 40. Create a random vector of size 10 and sort it (★★☆)
ソートされたサイズが10の乱数ベクトルを作成する．

```python
Z = np.random.random(10)
Z.sort()
print(Z)
```
`np.random.random(size)`で0より大きく1より小さいベクトルをsize分だけ作成することが出来る．また，`list.sort()`[listは型]はlist内容を降順にソートするpythonの組み込み関数である．

#最後に
今回は1から40までのnumpyについての基本的な操作を理解するための問題を解いた．
今後，41から100までを解いていきたいです．
皆さんも良かったら基礎が復習できるので暇な時間にでも解いて見ると良いのではないでしょうか？