NumPy Master Class

Chapter4 Vectorization

Notebook1 Example1

 

사실 NumPy의 ndarray에 대해서 배울 것이 훨씬 많이 남아있지만, 계속해서 그런 내용만 다루다 보면 지겹기도 하고 도대체 이런걸 배워서 뭐가 좋은지 모르는 채로 배우면 효과가 떨어지기 마련이다.

따라서 이번 Chapter4에서는 Vectorization에서 시작해서 Vectorization으로 끝나는 NumPy의 가장 큰 장점에 대해서 배워보려고 한다. 실제로 프로그래밍을 하면 초급 프로그래머에서 중급 프로그래머로 넘어가는 가장 큰 전환점이 아닐까싶다. 이 Vectorization을 얼마나 잘 하느냐에 따라서 프로그램의 성능은 차이가 생각보다 크게 벌어지므로 자세히 다뤄보도록 하자.

 

먼저 가장 간단한 예제를 들어보자. 우리가 Vectorization을 한다는 것은 수를 하나씩 다루지 않고 묶음으로 처리를 한다는 의미이고 이는 프로그램의 속도를 가장 늦추는 for loop을 없앤다는 의미이기도 하다.

다음의 data를 통해서 Vectorization의 첫 번째 예제를 다뤄보자.

In [54]:
import numpy as np
import time
In [55]:
n_class = 5000000
avg_np = np.random.randint(low = 50, high = 100, size = (n_class,))
n_student_np = np.random.randint(low = 5, high = 30, size = (n_class))

print("avg_np[:10]:", avg_np[:10])
print("n_students_np[:10]", n_students_np[:10])
 
avg_np[:10]: [67 84 71 84 57 86 51 51 94 52]
n_students_np[:10] [10 26  6 22 19  9 13 20 21 16]
 

위의 data는 전국 고등학교 학급마다의 수학 성적 평균을 구한 것이다. 총 500만개의 학급이 있었고, avg_np에는 각 학급들의 수학평균, 그리고 n_students_np에는 그 학급의 학생수를 모은 자료이다.

우리는 이 자료를 통해 전국 수학성적의 평균을 구하려고 한다.

그러면 우리는 다음과 같은 연산을 수행해야 한다.

$(전체 수학 성적 평균) = \frac{ \sum 학급의 학생수 * 학급의 평균점수}{\sum 학급의 학생수}$

먼저 vectorization을 사용하지 않고, for loop을 사용할 때의 속도를 측정해보자.

In [56]:
tic = time.time()

score_sum = 0
n_student_sum = 0
for i in range(n_class):
    score_sum += avg_np[i] * n_student_np[i]
    n_student_sum += n_student_np[i]
print("Total Average: ", score_sum / n_student_sum)

toc = time.time()
for_time = toc-tic
print(str(for_time) + "s")
 
Total Average:  74.50324818382985
3.542466163635254s
 

총 3.54s가 걸린 것을 알 수 있다. 그렇다면 여태까지 배웠던 element-wise operation과 np.sum을 이용하면 어떻게 될까?

In [61]:
tic = time.time()

avg = (np.sum(avg_np * n_student_np)) / (np.sum(n_student_np))
print("Total Average: ", avg)

toc = time.time()
np_time = toc - tic
print(str(np_time))
 
Total Average:  74.50324818382985
0.0171661376953125
 

이번엔 17.1ms가 걸린 것을 알 수 있다. 실제로 걸린 시간의 비율을 구해보면

In [62]:
print("Elapsed Time Ratio: ", for_time/np_time)
 
Elapsed Time Ratio:  206.3636111111111
 

결과는 약 200배 속도 차이가 난다. 이 속도 차이라면 Vectorization을 한 프로그램이 1분 걸릴 것을 for loop으로 돌리면 200분 즉, 3시간 20분이 걸린다는 뜻이다. 이 간단한 예제만 살펴봐도 Vectorization이 앞으로 우리가 다룰 큰 data에서 선택이 아닌 필수가 된다는 것은 쉽게 알 수 있을 것이다.

특히, nested for loop의 경우 for loop이 2개, 3개씩 쌓여있는 경우 말그대로 프로그램의 병목현상이 발생하는 부분이므로 프로그램의 성능에선 치명적일 수 밖에 없다. 따라서 앞으로 이런 for loop을 Vectorization을 통해 없애는 연습을 해보도록 하자.

 
 

+ Recent posts