# NumPy

ตรวจสอบเวอร์ชันของ `numpy`

```import numpy
print(numpy.version.version)
# 1.19.5```
```import numpy as np
print(np.__version__)
# 1.19.5```
`> conda list`

## Arrays

The array object in NumPy is called `ndarray`

```import numpy as np
arr = np.array([1, 2, 3, 4, 5])
print(arr)
print(type(arr))
# [1 2 3 4 5]
# <class 'numpy.ndarray'>```

0-D Arrays

```import numpy as np
arr = np.array(5)
print(arr)
print(type(arr))
# 5
# <class 'numpy.ndarray'>```

1-D Arrays

```import numpy as np
arr = np.array([1,2,3])
print(arr)
print(type(arr))
# [1 2 3]
# <class 'numpy.ndarray'>```

2-D Arrays

```import numpy as np

arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr)
print(type(arr))
# [[1 2 3]
#  [4 5 6]]
# <class 'numpy.ndarray'>```

3-D Arrays

```import numpy as np
arr = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
print(arr)
print(type(arr))
# [[[1 2 3]
#   [4 5 6]]
#
#  [[ 7  8  9]
#   [10 11 12]]]
# <class 'numpy.ndarray'>```

Number of Dimensions

```import numpy as np
a = np.array(5)
b = np.array([1, 2, 3])
c = np.array([[1, 2, 3], [4, 5, 6]])
d = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])

print(a.ndim)
print(b.ndim)
print(c.ndim)
print(d.ndim)
# 0
# 1
# 2
# 3```

Define the number of dimensions by using the `ndmin` argument.

```import numpy as np
arr = np.array([1, 2, 3, 4], ndmin=5)

print(arr)
print('number of dimensions :', arr.ndim)
# [[[[[1 2 3 4]]]]]
# number of dimensions : 5```

## NumPy Data Types

NumPy has some extra data types, and refer to data types with one character, like `i` for integers, `u` for unsigned integers etc.

• `i` – integer
• `b` – boolean
• `u` – unsigned integer
• `f` – float
• `c` – complex float
• `m` – timedelta
• `M` – datetime
• `O` – object
• `S` – string
• `U` – unicode string
• `V` – fixed chunk of memory for other type ( void )
```import numpy as np
arr = np.array([1, 2, 3, 4])
print(arr.dtype)
# int32```
```import numpy as np
arr = np.array(['apple', 'banana', 'cherry'])
print(arr.dtype)
# <U6```
```import numpy as np
arr = np.array([1, 2, 3, 4], dtype='S')
print(arr)
print(arr.dtype)
# [b'1' b'2' b'3' b'4']
# |S1```
```import numpy as np
arr = np.array([1, 2, 3, 4], dtype='i4')
print(arr)
print(arr.dtype)
# [1 2 3 4]
# int32```

Converting Data Type

```import numpy as np
arr = np.array([1.1, 2.1, 3.1])
newarr = arr.astype('i') # newarr = arr.astype(int)
print(newarr)
print(newarr.dtype)
# [1 2 3]
# int32```
```import numpy as np
arr = np.array([1, 0, 3])
newarr = arr.astype(bool)
print(newarr)
print(newarr.dtype)
# [ True False  True]
# bool```

## Array Copy vs View

The main difference between a copy and a view of an array is that the copy is a new array, and the view is just a view of the original array.

```import numpy as np
arr = np.array([1, 2, 3, 4, 5])
x = arr.copy()
arr = 42
print(arr)
print(x)
# [42  2  3  4  5]
# [1 2 3 4 5]```
```import numpy as np
arr = np.array([1, 2, 3, 4, 5])
x = arr.view()
arr = 42
print(arr)
print(x)
# [42  2  3  4  5]
# [42  2  3  4  5]```

Check if Array Owns it’s Data

copies owns the data, and views does not own the data

Every NumPy array has the attribute `base` that returns `None` if the array owns the data.

```import numpy as np
arr = np.array([1, 2, 3, 4, 5])
x = arr.copy()
y = arr.view()

print(arr.base)
print(x.base)
print(y.base)
# None
# None
# [1 2 3 4 5]```

## Array Shape

Array Shape

```import numpy as np
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
print(arr.shape)
print(type(arr.shape))
# (2, 4)
# <class 'tuple'>```
```import numpy as np
arr = np.array([1, 2, 3, 4], ndmin=5)

print(arr)
print('shape of array :', arr.shape)
# [[[[[1 2 3 4]]]]]
# shape of array : (1, 1, 1, 1, 4)```

Array Reshaping

Reshape From 1-D to 2-D

```import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
newarr = arr.reshape(4, 3)
print(newarr)
# [[ 1  2  3]
#  [ 4  5  6]
#  [ 7  8  9]
#  [10 11 12]]```

Reshape From 1-D to 3-D

```import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
newarr = arr.reshape(2, 3, 2)
print(newarr)
# [[[ 1  2]
#   [ 3  4]
#   [ 5  6]]
#
#  [[ 7  8]
#   [ 9 10]
#   [11 12]]]```

Reshape return view

```import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])
print(arr.reshape(2, 4).base)
# [1 2 3 4 5 6 7 8]```

Unknown Dimension

You are allowed to have one “unknown” dimension.

```import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])
newarr = arr.reshape(2, 2, -1) # newarr = arr.reshape(2, 2, 2)
print(newarr)
# [[[1 2]
#   [3 4]]
#
#  [[5 6]
#   [7 8]]]```

Flattening the arrays

Flattening array means converting a multidimensional array into a 1D array.

```import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6]])
newarr = arr.reshape(-1)
print(newarr)
# [1 2 3 4 5 6]```

## Array Iterating

```import numpy as np
arr = np.array([1, 2, 3])
for x in arr:
print(x)
# 1
# 2
# 3```
```import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6]])
for x in arr:
print(x)
# [1 2 3]
# [4 5 6]```
```import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6]])
for x in arr:
for y in x:
print(y)
# 1
# 2
# 3
# 4
# 5
# 6```

nditer() – Iterating Arrays Using nditer()

```import numpy as np
arr = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
for x in arr:
print(x)
# [[1 2]
#  [3 4]]
# [[5 6]
#  [7 8]]```
```import numpy as np
arr = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
for x in np.nditer(arr):
print(x)
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8```

nditer() – Iterating Array With Different Data Types

```import numpy as np
arr = np.array([1, 2, 3])
for x in np.nditer(arr, flags=['buffered'], op_dtypes=['S']):
print(x)
# b'1'
# b'2'
# b'3'```

nditer() – Iterating With Different Step Size

```import numpy as np
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
for x in np.nditer(arr[:, ::2]):
print(x)
# 1
# 3
# 5
# 7```

ndenumerate()

```import numpy as np
arr = np.array([1, 2, 3])
for idx, x in np.ndenumerate(arr):
print(idx, x)
# (0,) 1
# (1,) 2
# (2,) 3```
```import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6]])
for idx, x in np.ndenumerate(arr):
print(idx, x)
# (0, 0) 1
# (0, 1) 2
# (0, 2) 3
# (1, 0) 4
# (1, 1) 5
# (1, 2) 6```

## NumPy Joining Array

Joining NumPy Arrays

```import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
arr = np.concatenate((arr1, arr2))
print(arr)
# [1 2 3 4 5 6]```

Join two 2-D arrays along cols (axis=0)

```import numpy as np
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
arr = np.concatenate((arr1, arr2), axis=0)
print(arr)
# [[1 2]
#  [3 4]
#  [5 6]
#  [7 8]]```

Join two 2-D arrays along rows (axis=1)

```import numpy as np
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
arr = np.concatenate((arr1, arr2), axis=1)
print(arr)
# [[1 2 5 6]
#  [3 4 7 8]]```

stack()

```import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
arr = np.stack((arr1, arr2), axis=0)
print(arr)
# [[1 2 3]
#  [4 5 6]]```
```import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
arr = np.stack((arr1, arr2), axis=1)
print(arr)
# [[1 4]
#  [2 5]
#  [3 6]]```

hstack()

```import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
arr = np.hstack((arr1, arr2))
print(arr)
# [1 2 3 4 5 6]```

vstack()

```import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
arr = np.vstack((arr1, arr2))
print(arr)
# [[1 2 3]
#  [4 5 6]]```

dstack()

```import numpy as np
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
arr = np.dstack((arr1, arr2))
print(arr)
# [[[1 4]
#   [2 5]
#   [3 6]]]```

## Splitting Array

```import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6])
newarr = np.array_split(arr, 3)

print(type(newarr))
print(newarr)
# <class 'list'>
# [array([1, 2]), array([3, 4]), array([5, 6])]

print(newarr)
print(type(newarr))
# [1 2]
# <class 'numpy.ndarray'>```
```import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6])
newarr = np.array_split(arr, 4)
print(newarr)
# [array([1, 2]), array([3, 4]), array(), array()]```
```import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6])
newarr = np.array_split(arr, 5)
print(newarr)
# [array([1, 2]), array(), array(), array(), array()]```

Splitting 2-D Arrays

```import numpy as np
arr = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]])
print(arr)
# [[ 1  2]
#  [ 3  4]
#  [ 5  6]
#  [ 7  8]
#  [ 9 10]
#  [11 12]]

newarr = np.array_split(arr, 3) # newarr = np.array_split(arr, 3, axis=0)
print(newarr)
print(newarr)
print(newarr)
# [[1 2]
#  [3 4]]
# [[5 6]
#  [7 8]]
# [[ 9 10]
#  [11 12]]```
```import numpy as np
arr = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]])
print(arr)
newarr = np.array_split(arr, 3, axis=1)
print(newarr)
print(newarr)
# [[ 1]
#  [ 3]
#  [ 5]
#  [ 7]
#  [ 9]
#  ]
# [[ 2]
#  [ 4]
#  [ 6]
#  [ 8]
#  
#  ]```
```import numpy as np
arr = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]])
newarr = np.hsplit(arr, 2)
print(newarr)
print(newarr)
# [[ 1]
#  [ 3]
#  [ 5]
#  [ 7]
#  [ 9]
#  ]
# [[ 2]
#  [ 4]
#  [ 6]
#  [ 8]
#  
#  ]```