Python の list と numpy.ndarray の操作で同じこと、違うこと

# list, numpy.ndarray とは
## list
- int、str、dict、関数(function)などのオブジェクトを格納することができる。
    - 異なるオブジェクトを同時に格納することもできる。
- リストのサイズは変更できる。

## numpy.ndarray
NumPyはPythonで使用できる拡張モジュールで、ベクトルや行列などを表現できる多次元配列を効率的に数値計算するためのサポートを行い、サポートを操作するための大規模な高水準の数学関数ライブラリを提供している。
画像は多次元配列オブジェクト(numpy.ndarray)で表現され、listと似た性質を持っている。
ただ、異なる点もあるので以下に示す。

- 配列内のすべての要素が同じ型である必要がある。
- 動的に配列のサイズの変更が可能だが、固定のサイズを持っている。そのため、配列のサイズが変更された場合は、元の配列を削除し新しい配列を生成する(一部の例外を除く)。
- 配列が固定サイズで、配列のすべての要素が同じデータ型であるため、大量のデータを効率的に処理することができる。

# listとnumpy.ndarrayの操作
## 同じこと
まず、操作が同じであるものを以下に示す。

```python:list_same
#list型の変数を作成
>>> tmp_list = ['a', 'b', 'c', 'd', 'e']
#インデックス0の要素を参照
>>> tmp_list[0]
'a'
#インデックス1から3までの要素を参照
>>> tmp_list[1:4]
['b', 'c', 'd']
#右端からインデックス3までの要素を参照
>>> tmp_list[:4]
['a', 'b', 'c', 'd']
#インデックス1から右端までの要素を参照
>>> tmp_list[1:]
['b', 'c', 'd', 'e']
#インデックス0の要素に’A’を代入
>>> tmp_list[0] = 'A'
>>> tmp_list
['A', 'b', 'c', 'd', 'e']
#インデックス1の要素に’B’を代入
>>> tmp_list[1] = 'B'
>>> tmp_list
['A', 'B', 'c', 'd', 'e']
#インデックス2から末尾までの要素に['C', 'D', 'E']を代入
>>> tmp_list[2:] = ['C', 'D', 'E']
>>> tmp_list
['A', 'B', 'C', 'D', 'E']
```

```python:ndarray_same
>>> import numpy as np
>>>
>>> ndarray = np.full(5, ['a', 'b', 'c', 'd', 'e'])
>>> ndarray
array(['a', 'b', 'c', 'd', 'e'], dtype='<U1')
>>> ndarray[0]
'a'
>>> ndarray[1:4]
array(['b', 'c', 'd'], dtype='<U1')
>>> ndarray[:4]
array(['a', 'b', 'c', 'd'], dtype='<U1')
>>> ndarray[1:]
array(['b', 'c', 'd', 'e'], dtype='<U1')
>>> ndarray[0] = 'A'
>>> ndarray
array(['A', 'b', 'c', 'd', 'e'], dtype='<U1')
>>> ndarray[2:] = ['C', 'D', 'E']
>>> ndarray
array(['A', 'b', 'C', 'D', 'E'], dtype='<U1')
```

## 違うこと
スライスで範囲指定を行い操作する場合は、listとnumpy.ndarrayで結果が変わるので、注意が必要。

```python:list_diff
#list型の変数を作成
>>> tmp_list = ['a', 'b', 'c', 'd', 'e']
#list型では、代入する要素数が左辺の要素数より少ないと、リストが縮小
>>> tmp_list[:] = 'A'
>>> tmp_list
['A']
```

```python:ndarray_diff
>>> import numpy as np
# numpy.ndarray型の変数を作成
>>> ndarray = np.full(5, ['a', 'b', 'c', 'd', 'e'])
>>> ndarray
array(['a', 'b', 'c', 'd', 'e'], dtype='<U1')
#numpy.ndarray型では、list型と異なり、指定した範囲すべてに対して代入
>>> ndarray[:] = 'A'
>>> ndarray
array(['A', 'A', 'A', 'A', 'A'], dtype='<U1')
>>>
```

listで各要素すべてに対して操作を行いたい場合は、mapやリスト内包記法を使う。

```python:map
>>> tmp_list = ['a', 'b', 'c', 'd', 'e']
>>>
>>> tmp_map = map(lambda str: str.upper(), tmp_list)
>>>
# map()の返り値はmapオブジェクトなので注意
>>> tmp_map
<map object at 0x0000019A7EF1FB38>
>>>
>>> list(tmp_map)
['A', 'B', 'C', 'D', 'E']
```

```python:list
>>> tmp_list = ['a', 'b', 'c', 'd', 'e']
>>>
>>> tmp_list = [str.upper() for str in tmp_list]
>>>
>>> tmp_list
['A', 'B', 'C', 'D', 'E']
```

# おまけ : 多次元のnumpy.ndarrayの操作
numpy.ndarrayは多次元で使うことが多いので、多次元での操作の例を以下に示す。

```python:ndarray_multi
>>> import numpy as np
# 400 * 400 * 3 のサイズですべての要素が0のnumpy.ndarray型の変数を作成
>>> ndarray = np.zeros((400, 400, 3), np.uint8)
>>> ndarray
array([[[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0],
        ...,
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]],
       ...,

       [[0, 0, 0],
        [0, 0, 0],
        [0, 0, 0],
        ...,
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]]], dtype=uint8)
#0行0列目の要素に[255, 0, 0]を代入
>>> ndarray[0, 0] = [255, 0, 0]
>>> ndarray
array([[[255,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0],
        ...,
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0]],

       ...,

       [[  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0],
        ...,
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0]]], dtype=uint8)
#すべての行の0列目に[255, 0, 0]を代入
>>> ndarray[:, 0] = [255, 0, 0]
>>> ndarray
array([[[255,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0],
        ...,
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0]],

       ...,

       [[255,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0],
        ...,
        [  0,   0,   0],
        [  0,   0,   0],
        [  0,   0,   0]]], dtype=uint8)
#すべての行のすべての列に[255, 0, 0]を代入
>>> ndarray[:, :] = [255, 0, 0]
>>> ndarray
array([[[255,   0,   0],
        [255,   0,   0],
        [255,   0,   0],
        ...,
        [255,   0,   0],
        [255,   0,   0],
        [255,   0,   0]],

       ...,

       [[255,   0,   0],
        [255,   0,   0],
        [255,   0,   0],
        ...,
        [255,   0,   0],
        [255,   0,   0],
        [255,   0,   0]]], dtype=uint8)
>>>
```