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

Python NumPy (1) Array, Indexing, Sorting

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

NumPy Library? : 수학적 계산

NumPy("Numerical Python") library는 수학적 계산에 사용되는 module들을 모아놓은 대표적인 library로 다양한 함수와 간편한 기능을 제공할 뿐만 아니라 연산실행 속도도 더 빠릅니다.

하지만, NumPy의 array는 동일한 type의 데이터만 담을 수 있다는 특징이 있습니다.

 

NumPy Library? : 수학적 계산

NumPy Array

NumPy Array의 색인(Indexing)

NumPy Array Sorting

 

NumPy 장점 1)

python에서는 float형 수를 정의할 때는 1.0처럼 소수부분을 덧붙여줘야 하지만, Numpy를 사용하면 깔끔하게 정의가 가능합니다.

>> import numpy as np
>> np.float(1)
1.0
>> np.array([1,2], dtype='float')
array([1., 2.])

복소수(complex)형은 1+0j로 허수부분을 더해줘야 하지만, Numpy를 사용하면 아래와 같이 정의가 가능합니다.

>> np.complex_(1)
(1+0j)
>> np.array([1, 2], dtype='complex_')
array([1.+0.j, 2.+0.j])

 

NumPy 장점 2) 실수형

한 array의 모든 요소에 일률적인 계산을 하기 편하다. array의 모든 요소들을 제공하려고 할 때 numPy를 사용하지 않으면, 

아래와 같이 list comprehension(for loop)를 사용해야 합니다.

>> x = [1, 3, 4]
>> x1 = [a**2 for a in x]
[1, 9, 16]

하지만 Numpy를 사용한다면 간단하게 구현이 가능합니다.

>> xn = np.array([1, 3, 4]
>> xn1 = xn**2
array([1, 9, 16], dtype=int32)

이와 같이 모든 요소들을 한번에 연산할 수 있어 가독성과 편의성이 좋아집니다. 만약 위에서 data type을 실수형으로 하고 싶다면 요소 최소 한개에 소수점을 붙여서 실수형으로 하거나 .astype() method를 사용해서 실수(float)형으로 반환할 수 있습니다.

>> xn = np.array([1., 3, 4])
array([1., 3., 4.])

>> xn1 = xn.astype(np.float)
array([1., 9., 16.])

 

NumPy 장점 3) arange

Python함수 range()를 사용해서 등차수열을 만들면 정수들로만 구성이 되지만, 

>> r = list(range(2,9,3)) # 2부터 (9-1)까지 3씩 증가시킨다.
[2, 5, 8]

NumPy 함수 ~.arange()를 사용하면 실수들로 구성된 등차수열도 만들 수 있습니다.

>> rn = np.arange(2, 4, 0.5) # 2부터 4미만까지 0.5씩 증가시킨다
array([2., 2.5, 3., 3.5)]

 

NumPy 장점 4) datetime

날짜, 월 등을 표현하는 datetime64형 데이터는 ~.datetime64() 함수를 사용하여 생성이 가능합니다.

 

- 일 단위 시점

>> day1 = np.datetime64('2020-12-25')
>> day1, day1.dtype
(numpy.datetime64('2020-12-25'), dtype('<M8[D]'))

 

- 월 단위 시점

>> month1 = np.datetime64('2020-12')
(numpy.datetime64('2020-12'), dtype('<M8[M]'))

Y(년)/M(월)/W(주)/D(일)/h(시)/m(분)/s(초) 로 다양하게 나타낼 수 있습니다.

 

- 일 단위 시점에 n일 더하기

>> day2 = np.datetime64('2020-12','D') # 12월 첫째날
>> day3 = day2 + np.timedelta64(24, 'D') # 12월 첫째날 + 24일
>> day3, dat3.dtype
(numpy.datetime64('2020-12-25'), dtype('<M8[D]'))

 


NumPy Array

ndarray는 NumPy에서 사용되는 N-차원 array형 data object로 같은 type으로 구성됩니다. NumPy에서 다뤄지는 data object의 type을 dtype이라고 합니다.

 

NumPy의 array() 함수를 사용하면 다차원의 숫자로 구성된 list를 numpy array로 만들 수 있습니다.

>> A = np.array([[1,0,3,4], [5,6,0,8], [9,10,11,12]])
>> A
array([[1, 0, 3, 4],
	[5, 6, 0, 8],
    [9, 10, 11, 12]])

.shape(array의 형태), .ndim(차원), .itemsize(한 요소의 byte 개수), .dtype(data type) 함수도 제공합니다.

차례대로 수행 결과는 아래와 같다

(3,4)
2
4 # 요소 한 개가 차지하는 메모리 사이즈는 4
int32

 

* 참고 : array는 한 가지 타입만 사용이 가능합니다. 1과 'Python'이라는 문자열을 묶으면 하나의 ndarray를 구성할 수 없습니다.

'<U6'은 6개의 byte를 차지하는 'little-endian Unicode'를 나타냅니다. 따라서 다양한 타입을 하나의 ndarray로 만드는 것은 불가능한 것을 알 수 있습니다.

 

하지만, dtype() 함수를 사용하면 사용자가 지정한 data type을 가진 복합적인(compound) data type을 가진 structed data type을 생성할 수 있습니다.

 

예를 들어서 student라는 자료형을 생성하고 테스트해보겠습니다. 자료형에 대한 자세한 내용은 아래 표를 참고해주세요.

한 가지 살펴볼 내용은 name의 타입을 U10(10 byte)로 설정했으나 춘식이의 name은 U3으로 byte개수가 줄어든 것을 확인할 수 있습니다. NumPy에서 메모리를 절약하기 위해 조정한 것으로 추측됩니다.

 

 

[NumPy 자료형]

https://nirmalwrites.substack.com/p/numpy-data-types

 

datetime64 형으로도 ndarray를 구성할 수 있습니다. 간단한 예시를 하나만 살펴보고 넘어가겠습니다.

위 예제로 arange를 사용하여 13일 이전인 11일, 12일이 출력되는 것과 datetime64[D]로 day 타입으로 사용하는 것을 확인할 수 있습니다.

 


NumPy Array의 색인(Indexing)

- 숫자로 Indexing

시작하는 index를 0으로 보고, 끝나는 index는 -1 한 값으로 생각하면 좋습니다.

빈 값은 처음(0)이나 마지막(n-1:사이즈가 n일 때)을 나타냅니다.

 

- extract() 함수 사용 : 조건을 만족시키는 요소들만 선택해서 볼 수 있습니다.

>> np.extract(A>9, A)
array([10, 11, 12])

 

 

- where(), argwhere() 함수 사용 : 조건을 만족시키는 요소들에 대한 index만 선택해서 볼 수 있습니다.

>> idx = np.where(A>9); idx
(array([2, 2, 2]), array([1, 2, 3]))

>> idx2 = np.argwhere(A>9); idx2
array([[2, 1],
       [2, 2],
       [2, 3]])

where과 argwhere의 결과는 똑같이 idx (2,1)(2,2)(2,3)을 나타냅니다. where은 앞 array에서 행의 idx를 뒤 array에서 열의 idx를 나타냅니다.

생각해보면, where은 특정 조건을 만족시키는 요소들을 뽑아낼 때 사용하면 좋습니다. 

>> A[idx[0][0],idx[1][0]] = 10

>> A[idx[0][1],idx[1][1]] = 11

>> A[idx[0][2],idx[1][2]] = 12

 

반면에, 조건에 맞는 idx를 시각적으로 보기를 원한다면 argwhere() 함수의 출력인자가 더 좋습니다.

 


NumPy Array Sorting

numpy.sort(A, axis, order)
A: 정렬 대상 array
axis: 2차원 기준으로 0은 정렬축을 수직, 1은 수평으로 설정
order: A가 여러 요소로 구성된 tuple인 경우 어떤 요소를 기준으로 정렬시킬 것인지 설정하는 용도

Q. sort()의 default는 오름차순이다. 내림차순으로 정렬하려면 어떻게 해야할까요?

A. 오름차순으로 정렬된 결과의 순서를 거꾸로 뒤집는 것입니다. [::-1]과 flip()을 사용할 수 있습니다.

* [::-1]에서 마지막 -1은 역순으로 라는 의미이며 2나 3같은 숫자는 2칸씩, 3칸씩 띄워서 간다는 표현으로 이해하시면 좋습니다.

 

또 다른 방법으로는 부호를 반대로 해서 정렬한 다음 부호를 바꾸는 방법이 있습니다. 아래 예제를 참고해주세요.

>> a = np.array([1, 7, 4, 9, 2])

>> a1 = np.sort(a)
array([1, 2, 4, 7, 9])

# 내림차순 정렬
>> a2 = np.sort(a)[::-1]
>> a2 = np.flip(a1)
array([9, 7, 4, 2, 1])

# 부호를 반대로 해서 오름차순으로 정렬한 다음에 다시 부호를 바꾼다
>> a3 = -np.sort(-a); a3
array([9, 7, 4, 2, 1])

 

이번에는 axis를 사용해 정렬 방향을 설정해보겠습니다.

아래 예시를 보면 axis=0은 x축(세로축)으로 정렬되며, axis=1은 y축(가로축)으로 정렬되는 것을 확인할 수 있습니다.

sort() 함수의 default는 axis=1입니다.

 

 

3D array에 sort()함수를 적용해 보겠습니다. 3D는 생각보다 복잡해서 책에서 제공해주는 그림을 참고하는 것이 좋습니다.

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

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

axis=0 (x축, 가로축) axis=1 (y축, 세로축) axis=2 (z축, 수직축) 으로 정렬되는 것을 알 수 있습니다.

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

array([[[8, 2],
        [3, 7]],

       [[6, 5],
        [1, 4]]])
        
>> A0 = np.sort(A, axis=0); A0

array([[[6, 2],
        [1, 4]],

       [[8, 5],
        [3, 7]]])
        
>> A1 = np.sort(A, axis=1); A1

array([[[3, 2],
        [8, 7]],

       [[1, 4],
        [6, 5]]])
        
>> A2 = np.sort(A, axis=2); A2

array([[[2, 8],
        [3, 7]],

       [[5, 6],
        [1, 4]]])

order 입력인자를 사용해보겠습니다. 여러 개의 요소로 구성된 tuple인 경우에 order 입력 인자를 사용하는 예시입니다.

>> students = [('Tom', 'B', 48.1),('Judy', 'B', 42.5),('Paul', 'A', 52.5)]

>> data_type = [('이름','U10'),('그룹','U10'),('점수',float)]

# ndarray 구성
>> students_a = np.array(students, dtype=data_type); students_a

array([('Tom', 'B', 48.1), ('Judy', 'B', 42.5), ('Paul', 'A', 52.5)],
      dtype=[('이름', '<U10'), ('그룹', '<U10'), ('점수', '<f8')])

위와 같이 data_type의 ndarray를 구성했습니다. 이제 order를 사용해서 정렬을 해보겠습니다.

마지막 예시처럼 order에 여러 개의 기준을 넣을 수 있습니다.

>> print(np.sort(students_a, order='이름'))

[('Judy', 'B', 42.5) ('Paul', 'A', 52.5) ('Tom', 'B', 48.1)]

>> print(np.sort(students_a, order='그룹'))

[('Paul', 'A', 52.5) ('Judy', 'B', 42.5) ('Tom', 'B', 48.1)]

>> print(np.sort(students_a, order='점수'))

[('Judy', 'B', 42.5) ('Tom', 'B', 48.1) ('Paul', 'A', 52.5)]

>> print(np.sort(students_a, order=['그룹','점수']))

[('Paul', 'A', 52.5) ('Judy', 'B', 42.5) ('Tom', 'B', 48.1)]

argsort() 함수를 사용하여 정렬된 ndarray의 요소에 대한 index를 뽑아내는 예제입니다.

>> a = np.array([1, 7, 4, 9, 2])
>> sorted_idx = np.argsort(a); sorted_idx

array([0, 4, 2, 1, 3])

 

심화로 한단계 더 진행해보겠습니다. 위에서 생성한 students_a와 같은 ndarray를 각 요소들의 idx2(세 번째) 요소인 '점수'를 기준으로 정렬하는 예시입니다.

by 라는 array에 정렬에 사용할 '점수' 값만 추출하고, argsort() 함수를 사용해서 정렬하는 과정입니다.

>> students_a = np.array(students, dtype=data_type); students_a

array([('Tom', 'B', 48.1), ('Judy', 'B', 42.5), ('Paul', 'A', 52.5)],
      dtype=[('이름', '<U10'), ('그룹', '<U10'), ('점수', '<f8')])

>> by = np.array([item[2] for item in students_a]); by

array([48.1, 42.5, 52.5])

>> students_sorted_by_score = students_a[np.argsort(by)]
print(students_sorted_by_score)

[('Judy', 'B', 42.5) ('Tom', 'B', 48.1) ('Paul', 'A', 52.5)]

 

 

 

References

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

 

 

반응형

댓글