2022년 8월 28일 일요일

python Numpy basic 기본 사용법 정리

 

Numpy

1. 특징

  • 다차원 행렬 및 배열 처리 및 연산

출처 : 기본 내용은 아래 링크로부터 가져왔습니다.
https://numpy.org/doc/stable/user/quickstart.html

2. NumPy 설치

Python이 있는 경우 다음을 사용하여 NumPy를 설치할 수 있습니다.

conda install numpy

또는

pip install numpy


3. NumPy를 가져오는 방법

NumPy 및 해당 기능에 액세스하려면 다음과 같이 Python 코드에서 가져옵니다.
import numpy as np

np를 사용하여 코드의 더 나은 가독성을 위해 가져온 이름을 줄여서 사용합니다.



4. 완전 기본


NumPy의 다차원 배열을 표현하고 사용하기 위해서 사용합니다. 이것은 양수의 튜플에 의해 인덱싱된 같은 유형의 요소(보통 숫자)의 테이블입니다. 

(튜플이란 python에서 () 로 이루어진 데이터의 연속이나 수정이 안되는 배열로 생각 하면 됩니다. list의 수정 안되는 형태라고 이해하시면 됩니다. )

아래와 같이 표현된다면 2차원 배열이라고 생각 하면 됩니다.

[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]


위 리스트를 numpy로 생성시키면 아래와 같은 2차원으로 배열로 표현이 됩니다. 


이걸 코드로 만들어 보면 아래와 같습니다.

import numpy as np
a = np.array([[ 0,  1,  2,  3,  4],[ 5,  6,  7,  8,  9],[10, 11, 12, 13, 14]])
print(f"array {a}")


array [[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]


여기에서 np.array() 함수는 list나 tuple 형태를 np 로 변환하게 됩니다.


ndarray.ndim

배열의 축(차원) 수입니다.

ndarray.shape

배열의 차원. 이것은 각 차원에서 배열의 크기를 나타내는 정수의 튜플입니다. n개의 행과 m 개의 열 shape이 있는 행렬의 경우 (n,m)입니다. shape따라서 튜플의 길이는 축의 수입니다. 많이 사용하게 되므로 꼭 기억해 둘 필요가 있습니다.

ndarray.size

배열의 총 요소 수입니다. 

ndarray.dtype

배열의 요소 유형을 설명하는 개체입니다. 표준 Python 유형을 사용하여 dtype을 만들거나 지정할 수 있습니다. 또한 NumPy는 자체 유형을 제공합니다. numpy.int32, numpy.int16 및 numpy.float64가 몇 가지 예입니다.

ndarray.itemsize

배열의 각 요소의 크기(바이트)입니다.

ndarray.data

배열의 실제 요소를 포함하는 버퍼. 일반적으로 인덱싱 기능을 사용하여 배열의 요소에 액세스하기 때문에 이 속성을 사용할 필요가 없습니다.


import numpy as np
a = np.array([[ 0,  1,  2,  3,  4],[ 5,  6,  7,  8,  9],[10, 11, 12, 13, 14]])
print(f"array {a}")
print(f"np.ndim {a.ndim}")
print(f"np.shape {a.shape}")
print(f"np.size {a.size}")
print(f"np.dtype {a.dtype}")
print(f"np.itemsize {a.itemsize}")
print(f"np.data {a.data}")

array [[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]
np.ndim 2
np.shape (3, 5)
np.size 15
np.dtype int32
np.itemsize 4
np.data <memory at 0x000001F07A34AEE0>


2차원까지는 그럭저럭 그려보는데... 3차원 이상의 경우 그림으로 그려보기 힘듭니다. 따라서 차원이 복잡한 경우 shape으로 디버깅을 해서 구조를 파악해 둘 필요가 있습니다.


5. 생성


5.1 array 이용

앞선 예제에도 사용했지만 기본으로는 array 함수를 사용합니다.
array 결과 배열의 유형은 시퀀스의 요소 유형에서 추론됩니다.

import numpy as np
>>> a = np.array([2, 3, 4])
>>> a
array([2, 3, 4])
>>> a.dtype
dtype('int64')
>>> b = np.array([1.2, 3.5, 5.1])
>>> b.dtype
dtype('float64')

위 결과를 보면 실제 부동 소수점이냐 아니면 정수 형태냐는 입력값을 가지고 판단을 하게 됩니다. 인자로 형태를 고정 할 수도 있습니다. ( dtype 사용함 )

c = np.array([[1, 2], [3, 4]], dtype=complex)
>>> c
array([[1.+0.j, 2.+0.j],
       [3.+0.j, 4.+0.j]])


5.2 zeros, ones, empty 함수 사용


함수 zeros는 0으로 가득 찬 배열을 만들고,
함수 ones는 1로 가득 찬 배열,
함수 empty는 초기 내용이 무작위이고 메모리 상태에 따라 달라지는 배열을 만듭니다. 
기본적으로 생성된 배열의 dtype은 float64이지만 키워드 인수를 통해 지정할 수 있습니다.

np.zeros((3, 4))
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.],
       [0., 0., 0., 0.]])
>>> np.ones((2, 3, 4), dtype=np.int16)
array([[[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]],

       [[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]]], dtype=int16)
>>> np.empty((2, 3)) 
array([[3.73603959e-262, 6.02658058e-154, 6.55490914e-260],  # may vary
       [5.30498948e-313, 3.14673309e-307, 1.00000000e+000]])


5.3 arange 함수 사용


숫자 시퀀스(순서대로 증감하는 배열)를 생성하기 위해 NumPy는 arange 를 이용(Python 내장과 유사한 함수를 range 제공 ) 배열을 반환합니다.

np.arange(10, 30, 5)
array([10, 15, 20, 25])
>>> np.arange(0, 2, 0.3)  # it accepts float arguments
array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])


6. 차원의 변환

많은 경우 차원의 변환이 필요한 경우가 많습니다.
reshape을 이용하게 되는데 아래 예제를 봅시다.

c = np.arange(24)
print(f"array {c}")
print(f"array {c.reshape(2,3,4)}")
print(f"array {c.reshape(-1,3,4)}")

array [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
array [[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]
array [[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]

reshape의 특성상 제일 하위 차원부터 구성을 하기 때문에 제일 상위 차원의 형태의 경우 -1을 입력하더라도 남은 구조를 알아서 계산 하기 때문에 같은 형태의 결과를 얻을 수 있습니다. 즉 위의 예제에서 24개의 배열이니 2*3*4 = 24개의 크기가 맞기 때문에 형태를 변환하는것은 문제 없었습니다.

만약 위의 예제에서 c = np.arange(24) -> c = np.arange(23) 으로 변환 했다면 크기가 맞지 않아서 아래와 같은 에러가 발생하게 됩니다.
Traceback (most recent call last):
  File "np.py", line 14, in <module>
    print(f"array {c.reshape(2,3,4)}")
ValueError: cannot reshape array of size 23 into shape (2,3,4)


7. 기본 연산

연산이야 말로 numpy를 사용하는 목적이 됩니다. 연산 자체를 배열 통째로 할 수 있기 때문입니다.
배열의 산술 연산자는 요소별로 적용 됩니다 . 새 배열이 생성되고 결과로 채워집니다.

a = np.array([20, 30, 40, 50])
>>> b = np.arange(4)
>>> b
array([0, 1, 2, 3])
>>> c = a - b
>>> c
array([20, 29, 38, 47])
>>> b**2
array([0, 1, 4, 9])
>>> 10 * np.sin(a)
array([ 9.12945251, -9.88031624,  7.4511316 , -2.62374854])
>>> a < 35
array([ True,  True, False, False])

b**2 는 제곱을 의미합니다.

사칙 연산뿐만 아니라 함수 연산도 기본적으로 배열 통째로 이루어집니다.

배열의 곱셈은 두가지가 있습니다. *은 + - 처럼 원소별로 이루어 지고 행렬 곱은 @연산자(python >=3.5) 또는 dot함수 또는 메서드를 사용하여 수행할 수 있습니다.

A = np.array([[1, 1],
...               [0, 1]])
>>> B = np.array([[2, 0],
...               [3, 4]])
>>> A * B     # elementwise product
array([[2, 0],
       [0, 4]])
>>> A @ B     # matrix product
array([[5, 4],
       [3, 4]])
>>> A.dot(B)  # another matrix product
array([[5, 4],
       [3, 4]])

+=및 와 같은 일부 작업 *=은 새 배열을 생성하는 대신 기존 배열을 수정하는 역할을 합니다. ( 이건 당연한 겁니다. )


8. 합, 최대 최소 값 그리고 축이야기

배열에 있는 모든 요소의 합을 계산하는 것과 같은 많은 단항 연산은 ndarray 클래스의 메서드로 구현됩니다.

a = rg.random((2, 3))
>>> a
array([[0.82770259, 0.40919914, 0.54959369],
       [0.02755911, 0.75351311, 0.53814331]])
>>> a.sum()
3.1057109529998157
>>> a.min()
0.027559113243068367
>>> a.max()
0.8277025938204418

기본적으로 이러한 작업은 배열의 모양에 관계없이 마치 숫자 목록인 것처럼 배열에 적용됩니다. 그러나 axis 매개변수를 지정하면 배열의 지정된 축을 따라 작업을 적용할 수 있습니다.

b = np.arange(12).reshape(3, 4)
>>> b
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>>
>>> b.sum(axis=0)     # sum of each column
array([12, 15, 18, 21])
>>>
>>> b.min(axis=1)     # min of each row
array([0, 4, 8])
>>>
>>> b.cumsum(axis=1)  # cumulative sum along each row
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]])


9. sin, cos, exp 함수 범용 기능


NumPy는 sin, cos, exp와 같은 친숙한 수학 함수를 제공합니다. NumPy에서는 이것을 "범용 함수"라고 합니다. NumPy 내에서 이러한 함수는 배열에서 요소별로 작동하여 배열을 출력으로 생성합니다.

B = np.arange(3)
>>> B
array([0, 1, 2])
>>> np.exp(B)
array([1.        , 2.71828183, 7.3890561 ])
>>> np.sqrt(B)
array([0.        , 1.        , 1.41421356])
>>> C = np.array([2., -1., 4.])
>>> np.add(B, C)
array([2., 0., 6.])


10. 인덱싱, 슬라이싱

이건 리스트와 동일하다고 생각하면 됩니다.
다차원 배열은 축당 하나의 인덱스를 가질 수 있습니다. 이러한 인덱스는 쉼표로 구분된 튜플에 제공됩니다.

def f(x, y):
...     return 10 * x + y
...
>>> b = np.fromfunction(f, (5, 4), dtype=int)
>>> b
array([[ 0,  1,  2,  3],
       [10, 11, 12, 13],
       [20, 21, 22, 23],
       [30, 31, 32, 33],
       [40, 41, 42, 43]])
>>> b[2, 3]
23
>>> b[0:5, 1]  # each row in the second column of b
array([ 1, 11, 21, 31, 41])
>>> b[:, 1]    # equivalent to the previous example
array([ 1, 11, 21, 31, 41])
>>> b[1:3, :]  # each column in the second and third row of b
array([[10, 11, 12, 13],
       [20, 21, 22, 23]])

축 수보다 적은 인덱스가 제공되면 누락된 인덱스는 완전한 슬라이스로 간주됩니다.:

b[-1]   # the last row. Equivalent to b[-1, :]
array([40, 41, 42, 43])


11. 배열에 다른 배열을 쌓기


내용이 복잡하기 때문에 다른 링크를 참고하세요























댓글 없음:

댓글 쓰기