NumPy를 사용한 성능 최적화 기법
데이터 분석과 과학 컴퓨팅의 필수 라이브러리인 NumPy는 강력하고 유연한 도구를 제공합니다. 하지만, 성능 최적화를 통해 코드를 더욱 효율적으로 작성할 수 있다면 작업 시간을 크게 단축할 수 있습니다. 오늘은 NumPy를 사용하여 성능을 극대화하는 기법들에 대해 알아보겠습니다.
1. 벡터화(Vectorization)
Python의 기본 반복문(예: for
문)은 느린 경우가 많습니다. NumPy는 배열 연산을 벡터화하여 반복문을 제거하고 성능을 크게 향상시킬 수 있습니다.
예제: 두 배열의 합 계산
import numpy as np
# 배열 생성
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([10, 20, 30, 40, 50])
# 벡터화 연산
result = arr1 + arr2
print(result) # 출력: [11 22 33 44 55]
위 예제에서 arr1 + arr2
는 반복문 없이 두 배열의 요소를 한 번에 더합니다. 이는 성능과 코드 가독성을 모두 향상시킵니다.
2. 브로드캐스팅(Broadcasting)
브로드캐스팅은 크기가 다른 배열 간의 연산을 가능하게 하여 불필요한 배열 복사를 줄이고 메모리 사용량을 절약합니다.
예제: 스칼라와 배열의 곱
# 스칼라 값과 배열의 곱
arr = np.array([1, 2, 3, 4, 5])
scalar = 10
result = arr * scalar
print(result) # 출력: [10 20 30 40 50]
브로드캐스팅은 스칼라를 배열의 각 요소에 확장하여 곱셈을 수행합니다.
3. 슬라이싱(Slicing)과 뷰(View) 사용
NumPy 배열은 슬라이싱을 통해 데이터를 복사하지 않고 참조를 반환합니다. 이는 메모리 사용을 줄이고 성능을 향상시킵니다.
예제: 배열의 부분 슬라이싱
# 배열 생성
arr = np.arange(10)
# 슬라이싱
sub_arr = arr[2:8]
print(sub_arr) # 출력: [2 3 4 5 6 7]
# 뷰를 변경하면 원본 배열도 변경됨
sub_arr[0] = 99
print(arr) # 출력: [ 0 1 99 3 4 5 6 7 8 9]
슬라이싱은 데이터를 복사하지 않으므로 대량 데이터 처리에 유리합니다.
4. 데이터 타입 최적화
NumPy 배열의 데이터 타입(dtype
)을 최적화하면 메모리 사용량을 줄이고 계산 속도를 향상시킬 수 있습니다.
예제: 데이터 타입 변경
# 기본 배열
arr = np.array([1, 2, 3, 4, 5], dtype=np.int64)
print(arr.nbytes) # 출력: 40 (바이트)
# 데이터 타입 변경
optimized_arr = arr.astype(np.int8)
print(optimized_arr.nbytes) # 출력: 5 (바이트)
데이터 타입을 적절히 선택하면 메모리 사용량을 대폭 줄일 수 있습니다.
5. NumPy 함수 활용
NumPy는 다양한 내장 함수를 제공하며, 이를 활용하면 반복문을 대체하고 성능을 최적화할 수 있습니다.
예제: 평균 계산
# 배열 생성
arr = np.random.rand(1000000)
# 내장 함수 사용
mean_value = np.mean(arr)
print(mean_value)
np.mean
은 C로 구현되어 있어 Python 반복문을 사용하는 것보다 훨씬 빠릅니다.
6. 메모리 매핑(Memory Mapping)
대용량 파일을 처리할 때 메모리 매핑을 사용하면 파일 전체를 메모리에 로드하지 않고도 데이터를 처리할 수 있습니다.
예제: 메모리 매핑 사용
# 메모리 매핑 파일 생성
filename = 'large_array.dat'
arr = np.memmap(filename, dtype=np.float32, mode='w+', shape=(10000, 10000))
# 배열 초기화
arr[:] = np.random.rand(10000, 10000)
arr.flush() # 디스크에 저장
# 메모리 매핑으로 파일 읽기
mapped_arr = np.memmap(filename, dtype=np.float32, mode='r', shape=(10000, 10000))
print(mapped_arr[0, 0])
메모리 매핑은 대용량 데이터를 처리하는 데 적합한 방법입니다.
7. 멀티스레딩과 병렬 처리
NumPy는 기본적으로 멀티스레드를 지원합니다. 추가적으로 병렬 처리를 통해 연산 속도를 높일 수 있습니다.
예제: np.dot
병렬 처리
# 대형 배열 생성
arr1 = np.random.rand(10000, 1000)
arr2 = np.random.rand(1000, 5000)
# 행렬 곱 연산
result = np.dot(arr1, arr2)
print(result.shape) # 출력: (10000, 5000)
NumPy의 np.dot
함수는 멀티스레드를 활용하여 최적화된 속도를 제공합니다.
마무리
오늘은 NumPy를 사용한 성능 최적화 기법에 대해 살펴보았습니다. 벡터화, 브로드캐스팅, 데이터 타입 최적화 등 다양한 방법을 적절히 활용하면 작업 속도를 크게 향상시킬 수 있습니다. 이러한 기법들을 실제 프로젝트에서 활용하여 보다 효율적인 코드를 작성해보세요!
'Python > NumPy' 카테고리의 다른 글
NumPy 벡터화와 루프 제거로 성능 극대화하기 (0) | 2025.10.22 |
---|---|
NumPy 텍스트 파일 읽기 및 쓰기 (loadtxt, savetxt) (0) | 2025.10.20 |
NumPy 배열 파일 저장 및 로드 (save, load, savez) (0) | 2025.10.19 |
NumPy 데이터 분석: 데이터 정렬 및 검색 (0) | 2025.10.18 |
NumPy로 배우는 데이터 분석: 배열 필터링과 수정 (0) | 2025.10.17 |