후 Numpy 기본문법도 어느정도 익숙해졌다.
오늘 알아본 내용은 np.round()를 중심으로한 소수점 내림, 근사값 구하기, np.sort()을 중심으로 한 정렬과 관련한 문법이다
1. 소수점 절사
1.1 np.round()
소수점 관련 메소드의 중심엔 np.round()가 있다. "round"는 "반올림"이라는 뜻의 영어단어이다. 말그대로 반올림을 진행한다.
코드로 살펴보자.
import numpy as np
x = np.random.uniform(-5, 5, (5, ))
print(x)
# [-0.37197568 -1.60538727 3.54762048 3.31087264 -1.42819026]
print(np.round(x))
# [-0. -2. 4. 3. -1.]
print(np.round(x, 1))
# [-0.4 -1.6 3.5 3.3 -1.4]
print(np.round(x, 3))
# [-0.372 -1.605 3.548 3.311 -1.428]
위의 코드를 살펴보면, 반올림의 대상과 소수점 몇번째 자리까지 표시를 지정하는 파라미터가 있다.
- np.round(x)
default로 0, 소수점 제거를 목표로 하겠다. 그러므로 소수점 첫째자리 값이 반올림과정(사사오입)을 거쳐 값이 출력된다.
- np.round(x, 1)
이 메소드는 소수점 첫번째자리까지 표시를 목표로 하게되니, 소수점 두번째자리 값이 반올림과정을 거쳐 값이 결정된다.
- np.round(x, 3)
이 메소드는 소수점 세번째자리까지 표시를 목표로 하게되니, 소수점 네번째자리 값이 반올림과정을 거쳐 값이 결정된다.
* 아참! 음수의 반올림이 잠시 헷갈릴 수도 있는데, 헷갈린다면 마이너스(-)가 없다고 생각하고, 양수의 반올림과 똑같이 진행하면 된다.
1.2 np.ceil(), np.floor()
np.ceil(), np.floor()는 메소드명에서 알 수 있듯이 올림, 내림메소드이다.
코드로 살펴보자
import numpy as np
x = np.random.uniform(-5, 5, (5, ))
print(x)
# [ 0.92524944 -2.32533942 -3.8690332 0.45242311 2.74391876]
print(np.ceil(x))
print(np.floor(x))
# [ 1. -2. -3. 1. 3.]
# [ 0. -3. -4. 0. 2.]
# print(np.ceil(x, 1)) # error return arrays must be of ArrayType
# print(np.floor(x, 1))
# print(np.ceil(x,3))
# print(np.floor(x,3))
위의 코드를 통해 알 수 있는 것은 ceil()은 올림 연산, floor()는 내림연산을 진행한다는 것, 그리고 신기한 것은 Numpy에는 소수점 올림 내림연산이 없는 듯하다. 그래서 곱하고 나누는 식으로 해당 연산을 구현한다.
import numpy as np
x = np.random.uniform(-5, 5, (5, ))
print(x)
# [-4.24839917 -4.96692481 -1.69391161 -1.42982281 3.36270581]
# 소수점 2번째 자리까지 올림, 내림
print(np.ceil(x*(100))/100)
print(np.floor(x*(100))/100)
# [-4.24 -4.96 -1.69 -1.42 3.37]
# [-4.25 -4.97 -1.7 -1.43 3.36]
위의 코드와 같이 소수점 n번째 자리수 올림, 내림 연산이 동작한다.
* 음수의 올림, 내림은반올림의 경우와 다르다. 그래서 자주 헷갈리곤 하는데, 위 코드에서 확인할 수 있듯 올림 = 0에 가까워진다. 내림= 0에서 멀어진다고 이해하면 좋겠다. 양수와 반대이다.
1.3 np.fix(), np.trunc()
올림, 내림의 경우 값이 양수인지 음수인지에 따라 0에서 가까워지고, 멀어지는게 반대로 동작한다.
np.fix()는 양수이든 음수이든 모든 소수점 내림을 0에 가까워지도록 연산한다.
코드로 살펴보자
import numpy as np
x = np.random.uniform(-5, 5, (5, ))
print(x)
# [ 0.59287063 4.21332711 4.7461975 -3.70217004 3.96346158]
print(np.fix(x))
# [ 0. 4. 4. -3. 3.]
# print(np.fix(x,1)) # error
print(np.fix(x*100)/100)
# [ 0.59 4.21 4.74 -3.7 3.96]
코드를 통해 알수 있듯, 먼저 np.fix()는 양수는 내림연산, 음수는 올림연산을 수행한다. 그리고 ceil(), floor()처럼 소수점 아래 연산을 제공하지 않는다. 외부에서 곱하고 나누기를 추가한다.
np.trund()는 trund이 "truncated(잘린)"의 약어로 "소수점을 자르고, 버리는 기능"을 수행하는 메소드이다.
import numpy as np
a = np.random.uniform(-10, 10, (5, ))
print(a)
# [-8.19040796 -0.53968042 -1.15971128 -7.42209702 -6.61719908]
print(np.trunc(a))
# [-8. -0. -1. -7. -6.]
코드를 보면, 말그대로 소수점은 모조리 자른다. 수행하는 기능을 보면 np.fix()와 같은 기능을 수행한다.
2. 정렬
정렬은 데이터의 결과를 구하는데, 중요한 개념이다.
학생별 시험점수가 있다고 했을때, "고득점 3명의 점수"라는 식의 "의미있는 값"을 뽑아내려면 정렬은 필수적이다.
정렬을 한다고, for문을 돌리고 있을순 없으니, 우리 예쁜 Numpy는 정렬 기능을 제공해주고 있다.
값 정렬뿐만 아니라, 정렬된 요소들의 index를 추출할 수도 있다.
2.1 np.sort()
np.sort()는 말 그대로 정렬 메소드이다. default는 "오름차순"정렬이다.
코드를 통해 살펴보자
import numpy as np
a = np.random.randint(0, 100, (5, ))
# 오름차순 정렬
ascend_sort = np.sort(a)
# 내림차순 정렬
descend_sort = np.sort(a)[::-1]
print(a)
# [47 51 83 92 14]
print(ascend_sort)
# [14 47 51 83 92]
print(descend_sort)
# [92 83 51 47 14]
위의 코드를 통해 살펴보면, default는 앞서 말한대로 오름차순 정렬이 진행되고, 이전 포스팅을 통해 공부한 indexing, slicing을 활용하면, 내림차순 정렬도 가능하다.
다차원 배열의 경우는 어떨까?
import numpy as np
a = np.random.randint(0, 100, (3, 3))
# 오름차순 정렬
ascend_sort = np.sort(a)
# 내림차순 정렬
descend_sort_err = np.sort(a)[::-1]
descend_sort = np.sort(a)[::, ::-1]
print(a)
# [[43 88 78]
# [60 66 55]
# [88 17 69]]
print(ascend_sort)
# [[43 78 88]
# [55 60 66]
# [17 69 88]]
print(descend_sort_err)
# [[17 69 88]
# [55 60 66]
# [43 78 88]]
print(descend_sort)
# [[88 78 43]
# [66 60 55]
# [88 69 17]]
a = np.random.randint(0, 100, (2, 3, 4))
# 오름차순 정렬
ascend_sort = np.sort(a)
# 내림차순 정렬
descend_sort = np.sort(a)[..., ::-1]
print(a)
# [[[ 1 32 59 72]
# [36 85 27 69]
# [ 9 94 14 92]]
# [[28 0 83 31]
# [47 85 83 69]
# [24 18 41 9]]]
print(ascend_sort)
# [[[ 1 32 59 72]
# [27 36 69 85]
# [ 9 14 92 94]]
# [[ 0 28 31 83]
# [47 69 83 85]
# [ 9 18 24 41]]]
print(descend_sort)
# [[[72 59 32 1]
# [85 69 36 27]
# [94 92 14 9]]
# [[83 31 28 0]
# [85 83 69 47]
# [41 24 18 9]]]
코드를 작성하면서 예상하기로는 numpy 메소드들이 그러했듯 default일시, 차원을 무시하고 전체 데이터를 정렬할 줄 알았다. 그런데 axis=-1와 같이 마지막 차원을 기준으로 정렬이 진행됐다.
* descend_sort_err와 같이 다차원 슬라이싱시, 헷갈리지 않도록 주의하자!
그러면, np.sort()의 axis 속성을 건드려 값을 받아보자!
import numpy as np
a = np.random.randint(0, 100, (3, 3))
sort = np.sort(a)
sort_axis_0 = np.sort(a, axis=0)
sort_axis_1 = np.sort(a, axis=1)
print(a)
# [[ 1 30 75]
# [63 48 27]
# [62 66 99]]
print(sort)
# [[ 1 30 75]
# [27 48 63]
# [62 66 99]]
print(sort_axis_0)
# [[ 1 30 27]
# [62 48 75]
# [63 66 99]]
print(sort_axis_1)
# [[ 1 30 75]
# [27 48 63]
# [62 66 99]]
그렇다. 코드 결과를 보면 알 수 있 듯, np.sort와 np.sort(axis=1)이 동일한 결과를 갖는걸 알 수 있다.
np.sort()의 default axis=-1인 걸로 이해하자구!
2.2 np.argsort()
위에서 말했듯, np.argsort()는 정렬된 값들의 index를 리턴하는 메소드이다.
정렬을 했을 때, 순서대로 있는 값들이 원래 배열에서 몇번째 index였는지를 알려주는 메소드이다.
역시나 코드를 통해 확인해보쟝
import numpy as np
a = np.random.randint(0, 100, (3, 3))
sort = np.sort(a)
argsort = np.argsort(a)
print(a)
# [[ 1 77 4]
# [67 9 46]
# [15 7 19]]
print(sort)
# [[ 1 4 77]
# [ 9 46 67]
# [ 7 15 19]]
print(argsort)
# [[0 2 1]
# [1 2 0]
# [1 0 2]]
print(a)
# [[ 1 77 4]
# [67 9 46]
# [15 7 19]]
a_ = list()
cnt = 0
for row in argsort:
a_.append(sort[cnt][row])
cnt += 1
a_ = np.array(a_)
print(a_)
# [[ 1 77 4]
# [46 67 9]
# [15 7 19]]
위의 코드를 보면 알 수 있듯이, np.argsort()는 np.sort()한 값들이 원래 몇번째 index였는지 파악해준다.
print(sort)
# [[ 1 4 77]
# [ 9 46 67]
# [ 7 15 19]]
print(argsort)
# [[0 2 1]
# [1 2 0]
# [1 0 2]]
둘을 비교해보면, np.sort()가 진행되서 오름차순 정렬이
0열은 [0행, 2행, 1행] 순으로 오름차순 정렬,
1열은 [1행, 2행, 0행] 순으로 오름차순 정렬,
2열은 [1행, 0행, 2행] 순으로 오름차순 정렬
됐음을 알 수 있다ㅏ!
이러한 기능은 다양한 방식으로 활용될 수 있다.
과목별 고득점 학생을 출력하는 예제를 진행해보겠다.
import numpy as np
a = np.random.randint(1, 101, (5, 3))
sort = np.sort(a, axis=0)[::-1]
argsort = np.argsort(a, axis=0)[::-1]
print(a)
# 국 영 수
# 학생0 [[74 10 23]
# 학생1 [19 20 78]
# 학생2 [23 79 60]
# 학생3 [95 93 87]
# 학생4 [13 89 65]]
print(sort) # 내림차순 정렬
# [[95 93 87]
# [74 89 78]
# [23 79 65]
# [19 20 60]
# [13 10 23]]
print(argsort) # 과목별 고득점순으로
# 국 영 수
# [[학생3 학생3 학생3]
# [학생0 학생4 학생1]
# [학생2 학생2 학생4]
# [학생1 학생1 학생2]
# [학생4 학생0 학생0]]
print(argsort[:2])
# 국 영 수 # 과목별 고득점 2위까지
# [[학생3 학생3 학생3]
# [학생0 학생4 학생1]
위의 코드처럼,
행을 시험점수로 보고, 열을 학생들로 본다면,
열을 기준으로 내림차순정렬을 하면, 고득점순으로 정렬이 되고,
np.argsort()를 같이 활용하면, 그 고득점자들이 몇번째 index, 학생n인지 확인할 수 있다.
끝! 문법이 천천히 정리되고 있다. 미니프로젝트를 통해 실제로 활용해보자구! 문법 배우는 이유가 사용하려는거니까.
댓글