[Python-NumPy] 2.NumPy.sort() 정렬

728x90
반응형

이번포스팅의 주제는 배열을 데이터의 기본구성으로하는 넘파이에서 정렬에대해 알아보겠다. 데이터를 다루다보면 순차적으로 정렬하거나 어떤 기준을 중심으로 데이터를 정리해야할 일이 엄청나게 많이 생긴다. 넘파이는 이런 문제를 간단히 해결할 수 있는 다양한 메소드를 제공한다. 

 

1. 1차원 배열 정렬

1.1 1차원 배열 오름차순 정렬 

arr = np.array([8,2,4,7,0,5,6,1,9])

위와같은 배열을 만들고 오름차순으로 정렬하고자한다면?

np.sort(arr)

넘파이에서 제공하는 sort()메소드를 이용하면된다. sort() 매개변수에 arr을 전달하면 정렬된 배열을 반환한다. 아래 코드로 확인해보자!

arr = np.array([8,2,4,7,0,5,6,1,9])
sort_arr = np.sort(arr)
print(sort_arr)
print(type(sort_arr))

출력결과는 아래와 같다.

sort()매소드는 전달된 매개변수를 복사한다음 오름차순으로 정렬해 반환하는 메소드다. 즉, arr을 정렬하는것이 아니라 arr을 복사해 정렬한 다음 정렬된 데이터를 반환하는 것이다. 

 

여기서 sort()매소드를 이용해 정렬된 객체를 반환하는 방식이 아닌 arr배열 자체를 변환하고 싶다면 아래와 같이 처리하면된다. 

arr.sort()

no.sort()매소드는 전달된 배열을 정렬해 복사본을 반환하지만 배열에서 바로 sort()를 호출하면 배열자체가 정렬된다.

1.2 1차원 배열 내림차순 정렬 

NumPy는 기본적으로 내림차순정렬을 지원하지 않는다. 데이터를 내림차순으로 정렬하기 위해서는 약간의 꼼수(?)를 사용해야한다. 첫 번째 방법으로는 오름차순으로 정렬된 배열을 반대로 뒤집는것이다. 배열의 슬라이싱을 활용하면 가능하다. 위에서 정렬한 배열을 그대로 활용해보도록 하겠다.

arr = np.array([8,2,4,7,0,5,6,1,9])
sort_arr = np.sort(arr)
print(sort_arr)
sort_des = sort_arr[::-1]
print(sort_des)

4번째 줄에서 정렬된 배열 sort_arr을 슬라이싱으로 거꾸로 뒤집은다음 sort_des에 저장해 내림차순으로 정렬된 배열을 만들었다. 이 과정이 조금 복잡하게 느껴진다면 아래와 같은 방법을 사용해도된다. 이 방법도 배열의 슬라이싱을 활용한 방법이다. 

 

sort_arr = np.sort(arr)[::-1]
print(sort_arr)

2. 2차원 배열 정렬

다양한 예제를 다뤄보기위해 다음 포스팅에서 ..! 

3. argsort

위에서 살펴본 .sort()매소드는 매개변수로 전달된 배열을 오름차순으로 정렬해 반환하는 매소드다. 배열의 각 요소는 인덱스를 통해 배열내에서 자신의 위치를 알수 있다. argsort는 요소의 오름차순으로 인덱스(데이터의 위치)를 반환하는 매소드다. 아래와 같이 배열 x에 3, 1, 2 라는 값이 있다면 인덱스 번호는 순서대로 0, 1, 2 이다.

위 배열의 오름차순으로 정렬하면 1, 2, 3이 된다. 1의 인덱스 번호는 1, 2의 인덱스 번호는 2, 3의 인덱스 번호는 0이다. 따라서 argsort()메소드에 x를 전달하면 argsort()메소드는 1, 2, 0을 배열로 반환한다. 아래코드를 통해 확인해보자.

x = np.array([3,1,2])
print(np.argsort(x))

위 코드를 실행하면

이와 같은 결과를 확인할 수 있다. 

 

결과를 통해 확인할 수 있는것은 정렬된 배열의 요소를 반환하는것이 아니라 정렬된 배열요소의 인덱스를 반환한다는 것이다. 정렬은 배열요소값을 기준으로 잡고 정렬하고, 인덱스는 최초의 요소가 위치한 인덱스를 그대로 가져온다. 

4. lexsort()

lexsort는 argsort와 마찬가지로 배열의 인덱스를 반환한다. 2개의 배열을 간접정렬할때 사용한다. 사실 이 메소드의 개념과 사용에대해서는 아직 이해가 부족하지만 지금까지 이해한 내용을 바탕으로 작성해보겠다.

코드로 작성하면 아래와 같이 작성할 수 있다.

A = np.array([2, 5, 1, 8, 1])
B = np.array([9, 0, 3, 2, 0])

lexsort()메소드에 배열 A와 B를 순서대로 전달하면 결과는 아래와 같을것이다. 

A = np.array([2, 5, 1, 8, 1])
B = np.array([9, 0, 3, 2, 0])
ind = np.lexsort((A, B))
print(ind)

코드실행결과다.

 

지금부터 동작에대해 설명하겠다. NumPy 공홈에 들어가면 설명이 나와있지만 그다지 자세하지 않고 처음공부하는 입장에서 본다면 이게 뭐지?라는 생각부터 든다. 항상 그렇듯..이해하고나면 쉽지만 그전까지는 어려우니까.

 

위 코드의 배열을 아래와같이 표로 나타내봤다.

배열 A, B를 A를 기준으로 정렬해보자. 이때 인덱스 번호도 함께 이동한다. 

다시 B를 기준으로 정렬해보자.

 

여기서 주목해야할 부분은 인덱스 번호다. lexsort는 첫 번째 전달인자 (여기서는 A)를 기준으로 정렬하고 다음으로 두 번째 전달인자(여기서는 B)를 기준으로 정렬한다음 인덱스 번화를 반환한다. 이때 인덱스번호는 최초에 배열을 선언했을때 기준으로 변하지 않는다. 넘파이에서 왜 이런기능을 만들었는지는 잘 모르겠지만 분명 필요하니까 만들었을 것이다!

 

 

5. searchsorted

이미 정렬되어있는 배열의 요소를 탐색하는 기능이다. 이진탐색을 수행하며 전달인자로 정렬되어있는 배열을 전달하고, 찾고자하는 값을 넣으면 해당인덱스를 반환한다. 만약 일치하는 값이 없다면 가장 가까운값의 인덱스를 반환한다. 아래코드로 확인해보자.

arr = np.array([1,2,3,4,5,6])
print(np.searchsorted(arr, 3))

배열 arr 중 3을 찾아 인덱스를 반환한다. 결과는 2가 나올것이다. 탐색의 방향은 기본적으로 왼쪽이고, side= 옵션을통해 방향을 변경할 수 있다. 

arr = np.array([1,2,3,4,5,6])
print(np.searchsorted(arr, 3, side='right'))

위 코드를 실행해보면 결과로 3이 나오는것을 확인할 수 있을 것이다. 탐색방향을 right로 변경했기 때문이다. 

 

탐색조건을 right로 변경하면 arr[i-1] <= v < arr[i] 조건으로 검색하고, left로 검색하면 arr[i-1] < v <= a[i] 조건으로 검색을 수행하기 때문에 결과가 다르게 나온다. 

 

아래코드를 보자.

arr = np.array([1,2,6,9,10])
print(np.searchsorted(arr, [4, 8]))

arr 배열은 1, 2, 6, 9, 10순으로 정렬되어있고, arr 배열중에서 4, 8 을찾고자한다. 출력 결과는 [2, 3]이 될것이다. 왼쪽부터 탐색을 시작하면 4에서 가장 가까운값은 두 번째 인덱스의 요소값 6이고, 8에서 가장 가까운 숫자는 세 번째 인덱스 요소값인 9가 된다.

 

6. partition

partition메소드의 첫번째 전달인자는 배열이고, 두번째 전달인자는 "배열요소 중 가장 작은 값 n개를 맨 앞으로 이동해라" 문장의 n을 의미한다.

arr = np.array([3,2,10,20,7,9,8,123,89,62,1])
print(np.partition(arr, 5))

실행결과는 다음과 같다. 

[  2   1   3   7   8   9  10 123  89  62  20]

배열의 가장작은 값 5개를 맨 앞으로 배치하고, 그 뒤로는 임의로 숫자를 배치했다. 

 

 

 

이번포스팅에서는 정렬에 대해 다뤄봤다. 정렬만해도 깊게 파고들면양이 만만치않다.. 아 근데 또 시작하면 끝장을 봐야하기 때문에 다음포스팅으로 넘어간다 ! 우선 1차원 배열과 NumPy에서 제공하는 메소드의 옵션을 활용하는 방법을 모두 살펴본 다음 2차원 배열에 대해 다뤄보려고 한다.

 

 

- 끝 - 

 

 

728x90
반응형