본문 바로가기
프로그래밍 언어

Python NumPy (2) 특수한 Array, reshape, dimension, copy, nan

by 내기록 2023. 1. 24.
반응형

 

 

Python Numpy의 일반적이지 않은 Array, 변경, 차원, 복제, nan과 inf 타입에 대해 알아보겠습니다.

아래는 목차입니다.

 

특수한 NumPy Array - zeros, eye, arange, linspace, logspace

NumPy Array의 변경 - reshape, flatten, swapaxes, insert, delete

NumPy Array의 차원(Dimension) 변경

NumPy Array의 복제

NumPy.nan과 NumPy.inf

 

 

특수한 NumPy Array - zeros, eye, arange, linspace, logspace

모든 요소들이 모두 다 0 또는 1인 zeros/ones array를 생성하는 방법입니다.

dtype을 명시하지 않으면 기본적으로 실수형으로 생성되는 것을 확인할 수 있습니다.

>> a = np.zeros(3); a # zero array of length 3

array([0., 0., 0.])

>> a2 = np.zeros((2,3)); a2

array([[0., 0., 0.],
       [0., 0., 0.]])
       
>> b = np.ones((2,3)); b

array([[1., 1., 1.],
       [1., 1., 1.]])
       
>> b = np.ones((2,3), dtype=int); b

array([[1, 1, 1],
       [1, 1, 1]])

 

대각 요소만 1이고 다른 요소들은 0인 단위 array를 만들기 위해 eye() 함수를 사용합니다.

(이렇게 대각원소가 1이고, 나머지는 모두 0인 n차 정방행렬을 단위행렬이라고 합니다.)

>> I = np.eye(3); I # 3x3 identity array

array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])

 

eye() 함수의 k 입력인자로 부 대각(subdiagonal) 요소들만 1인 array도 생성 가능합니다.

>> I1 = np.eye(3, k=-1); I1 

array([[0., 0., 0.],
       [1., 0., 0.],
       [0., 1., 0.]])

 

기존 array의 shape(size)를 알지 못해도 같은 shape를 가지는 zero/ones array를 만들 수도 있습니다.

→ zeros_like(array), ones_like(array)

 

arange() : 등차수열을 만드는데 사용합니다.

>> x = np.arange(0, 5, 0.5); x # 0부터 5미만까지 공차가 0.5인 등차수열

array([0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5])

 

linspace(), logspace() : 일반 그래프나 log 그래프를 그리기 위한 수평축(x축) 변수값을 만드는데 사용합니다.

linspace(초항, 말항, 항의 개수)

>> x1 = np.linspace(0, 5, 5); x1 #0~5까지의 구간에서 5개 값으로 구성된 등차수열

array([0.  , 1.25, 2.5 , 3.75, 5.  ])

 

logspace에 대해 살펴보겠습니다.

logspace의 결과는 아래 그래프에서 y=-1 ~ 2 사이의 값을 5등분 했을 때 [-1, -0.25, 0.5, 1.25, 2]의  x 값입니다.

따라서 log10() 함수에 x2 값을 넣으면 y의 간격이 동일한 것을 확인할 수 있습니다.

>> x2 = np.logspace(-1, 2, 5); x2 # log10(x) 10^-1~10^2 까지의 구간에서 5개 값으로 구성된 수열

array([  0.1  ,  0.56234133,   3.16227766,  17.7827941 ,  100.  ])

>> np.log10(x2)

array([-1.  , -0.25,  0.5 ,  1.25,  2.  ])

 

wikipedia

 

또한, logspace() 함수의 base 입력 인자를 따로 넣어주면 default 10이 아닌 다른 값으로 설정할 수 있습니다.

→ np.logspace(-1, 2, 5, base=2)

이 결과는 log2(x)의 2^-1 ~ 2^2 구간에서 등간격인 5개의 값으로 구성된 수열을 반환합니다.

 

참고로, linspace() 함수를 사용해서 logspace()를 구현할 수 있습니다.

 

 


NumPy Array의 변경 - reshape, flatten, swapaxes, insert, delete

reshape() : array를 다른 모양의 array로 바꾸기 위해 사용합니다.

>> a = np.arange(6); a
array([0, 1, 2, 3, 4, 5])

>> A1 = a.reshape(2,3); A1
array([[0, 1, 2],
       [3, 4, 5]])

flatten() : 2D array를 1D array로 바꾸기 위해 사용합니다.

default는 행 우선으로 하며, order='F' 를 추가하면 열 우선으로 진행합니다.

>> a1 = A1.flatten(); a1
array([0, 1, 2, 3, 4, 5])

>> a2 = A1.flatten(order='F'); a2
array([0, 3, 1, 4, 2, 5])

>> at = np.transpose(A1); at
array([[0, 3],
       [1, 4],
       [2, 5]])

 

swapaxes() : 축을 바꿔주는 함수로 0(x), 1(y), 2(z) 축을 나타냅니다.

 

Python(파이썬)과 Matplotlib, Numpy, Pandas - 양원영,고병천 외 3명

위 그림을 코드로 나타내면 아래와 같습니다. 3D array 참고

>> A = np.array([[[8,2],[3,7]],[[6,5],[1,4]]]); A
array([[[8, 2],
        [3, 7]],

       [[6, 5],
        [1, 4]]])
        
>> A0 = A.swapaxes(0,1); A0
array([[[8, 2],
        [6, 5]],

       [[3, 7],
        [1, 4]]])

 

insert() : array에 새로운 요소를 삽입할때 사용합니다.

insert(대상 array, 삽입 idx, 삽입 value)

 

axis=0 으로 하면 하나의 행을 삽입할 수도 있고, axis=1으로 하나의 열을 삽입할 수도 있습니다.

 

 

delete() : array에서 한 개 이상의 행이나 열을 제거할 때 사용합니다.

delete(대상 array, 삭제 idx)

axis를 사용해서 삭제하고자 하는 행, 열을 선택할 수 있습니다.

 

NumPy Array의 차원(Dimension) 변경

>> A = np.array([1,2]); A
array([1, 2])

>> A.shape, A.ndim
((2,), 1)

위 array는 행벡터일 것으로 생각되지만 shape가 (1,2)이 아니기 때문에 행 벡터인지 열 벡터인지 분명하지 않습니다. 이렇게 되면 행렬-벡터 연산이 수행될 때 dimension compatibility 조건에서 유연하게 행/열 벡터로 바뀐다는 장점이 있습니다만 상황에 따라서는 행/열 벡터를 분명하게 해야 할 때도 있습니다. 이럴 때 사용되는 NumPy의 상수가 바로 np.newaxis 입니다.

 

>> A_r = A[np.newaxis, :]; A_r # 행 벡터
array([[1, 2]])

>> A_r, A_r.shape, A_r.ndim
(array([[1, 2]]), (1, 2), 2)


>> A_c = A[:,np.newaxis]; A_c # 열 벡터
array([[1],
       [2]])
       
>> A_c, A_c.shape, A_c.ndim
(array([[1],
        [2]]),
 (2, 1),2)

참고) np.newaxis 값을 print해보면 Nonde이 나옵니다. 따라서 np.newaxis 대신 None을 사용해도 결과는 같습니다.

 

np.repeat(반복 대상 array, 반복 횟수, 반복 기준 축) : 벡터를 복사 증식해서 행렬로 만들 때 사용합니다.

repeat 함수도 axis를 사용해서 행, 열로 복제가 가능합니다.

A_r : 1x2 , A_c : 2x1 인 두 array를 사용한 샘플코드입니다.

 

NumPy Array의 복제(Copy)

A array가 있을 때, 동일한 데이터와 형태를 가진 A1이라는 array를 생성하려고 합니다.

>> A1 = A

위와 같이 생성했을 때, A1의 값이 바뀌면 A의 값도 같이 바뀌는 것을 확인할 수 있습니다.

A와 A1의 id 값을 찍어보면 이름은 다르지만 동일한 객체이기 때문입니다.

>> A = np.arange(6);
>> A1 = A
>> id(A1), id(A)
(140622852480720, 140622852480720)

 

원래의 array를 보존하면서 값을 copy 하기 위해서는 ndarray.view() method를 사용합니다.

아래의 코드를 보면 A2가 변경되었지만 A의 값은 그대로 보존되었으며, id 값도 다른 것을 확인할 수 있습니다. 

>> A
array([0, 1, 2, 3, 4, 5])

>> A2 = A.view() # array copy

>> print(A); print(A2)
[0 1 2 3 4 5]
[0 1 2 3 4 5]

>> A2.shape = 2,3; A2
array([[0, 1, 2],
       [3, 4, 5]])
       
>> A
array([0, 1, 2, 3, 4, 5])

>> id(A), id(A2)
(140622852480720, 140622852408304)

하지만 여기에는 함정이 있습니다. 복제된 A2의 일부 값을 변경하면 A의 요소도 함께 바뀌게 됩니다.

 

이유는 A와 A2의 id는 다르지만, 각 요소들끼리의 id는 달라지지 않았기 때문입니다.

→ 이러한 복제를 얕은 복제(shallow copy) 라고 합니다.

 

그렇다면 어떤 경우에도 원본 array는 건들지 않으면서 copy하는 방법은 무엇일까요?

ndarray.copy() method를 이용하는 것입니다. 아래 결과를 보면 A3이 변경되어도 A의 값은 유지되는 것을 알 수 있습니다.

→ 이러한 복제를 깊은 복제(deep copy) 라고 합니다.

 

NumPy.nan과 NumPy.inf

np.nan : 없거나(missing) 유효하지 않은(invalid) 값을 나타냅니다.

np.inf : 무한대 숫자를 나타냅니다.

 

np.nan은 None과 비슷하면서도 다른 점이 있습니다. 차이점 중 하나는 None인지 검사를 할 때는 간단히 == 연산자를 사용하는 데 비해서 np.nan 인지 검사하기 위해서는 np.isnan() 이나 math.isnan()을 사용해야 합니다.

 

(주의) np.nan을 검사할 때 == 를 사용하면 아무런 경고 메시지도 없이 False를 반환합니다.

 

한편, np.inf는 무한대 숫자를 나타내는 float('inf')와 동일한 것으로 == 연산자를 사용해도 되고, np.isinf()나 math.isinf()를 사용할 수도 있습니다.

 

Q. 어떤 상황에서 np.nan이나 np.inf를 만나게 될까요?

A. Numpy를 사용하지 않고 아래와 같은 계산을 하려고 하면 Error가 발생합니다.

>> np.array([1])/0, np.array([0])/0, np.sqrt(-1)
(array([inf]), array([nan]), nan)

 

[심화] NumPy.nan_to_num() 

np.nan, np.inf를 각각 0 이나 매우 큰 숫자로 대체하는 np.nan_to_num() 함수입니다.

>> x1 = np.nan_to_num(x, nan=0.0, posinf=None, neginf=None, copy=True)

x를 copy하며 np.nan과 np.inf를 0과 매우 큰 숫자로 대체한 결과를 x1에 저장합니다.

 

만약 다른 값으로 대체하고자 한다면 nan, posinf, neginf 에 값을 넣어주면 됩니다. copy를 0 또는 False로 하면 대체한 결과가 x에도 반영이 됩니다.

>> x = np.array([[np.nan, -np.inf, 3],[2, np.inf, None]], dtype=np.float16); x
array([[ nan, -inf,   3.],
       [  2.,  inf,  nan]], dtype=float16)
       
>> x1 = np.nan_to_num(x); x1
array([[ 0.00e+00, -6.55e+04,  3.00e+00],
       [ 2.00e+00,  6.55e+04,  0.00e+00]], dtype=float16)

 

 

만약, np.nan의 위치가 궁금하다면 np.where() 또는 np.argwhere(), np.isnan() 함수를 활용해서 찾을 수 있습니다.

np.where()와 np.argwhere()에 대한 내용은 링크를 참고해주세요.

 

>> x
array([[ nan, -inf,   3.],
       [  2.,  inf,  nan]], dtype=float16)
       
>> np.where(np.isnan(x))
(array([0, 1]), array([0, 2]))

>> np.argwhere(np.isnan(x))
array([[0, 0],
       [1, 2]])

 

 

참고하면 좋은 게시글

 

Python NumPy (1) Array, Indexing, Sorting

NumPy Library? : 수학적 계산 NumPy Array NumPy Array의 색인(Indexing) NumPy Array Sorting NumPy Library? : 수학적 계산 NumPy("Numerical Python") library는 수학적 계산에 사용되는 module들을 모아놓은 대표적인 library로 다

sunrise-min.tistory.com

 

 

 

 

References

Python(파이썬)과 Matplotlib, Numpy, Pandas - 양원영, 고병천 외 3명 

 

 

 

반응형

댓글