본문 바로가기
Language

파이썬 초보를 위한 리스트와 NumPy Array 차이 쉽게 이해하기

by markbyun 2025. 4. 23.

Python 기반 수치 연산 및 데이터 처리에서 두 가지 주요 구조가 중심을 이룹니다: 기본 Python 리스트와 NumPy 배열입니다. 기본적인 기능은 비슷하지만, 성능, 유연성, 내부 구현 측면에서 크게 다릅니다. 이 가이드는 두 구조의 사용법을 설명하고, 코드 예제를 제공하며, 성능이 중요한 응용 분야를 위해 기술적 차이를 비교합니다.


Python 리스트

Python 리스트는 변경 가능한(mutable) 순서가 있는 컬렉션으로, 다양한 데이터 타입을 요소로 가질 수 있습니다.

기본 사용법:

# 리스트 생성
py_list = [1, 2, 3, 4, 5]

# 요소 접근 및 수정
py_list[0] = 10

# 요소 추가 및 확장
py_list.append(6)
py_list.extend([7, 8])

# 리스트 컴프리헨션
squared = [x**2 for x in py_list]

# 다양한 타입을 포함하는 리스트
mixed_list = [1, 'two', 3.0, [4]]

제한사항:

  • 벡터화 연산에 대한 기본 지원이 없습니다.
  • 대규모 수치 연산 시 성능이 좋지 않습니다.
  • 동적 타이핑 및 객체 래핑으로 인한 메모리 오버헤드가 큽니다.

NumPy 배열

NumPy 배열(ndarray)은 고정 타입이며, 수치 계산에 최적화된 균일한 데이터 컨테이너입니다.

기본 사용법:

import numpy as np

# 배열 생성
np_array = np.array([1, 2, 3, 4, 5])

# 벡터화 연산
np_array_squared = np_array ** 2

# 브로드캐스팅
np_array_plus_scalar = np_array + 10

# 슬라이싱 및 인덱싱
sub_array = np_array[1:4]

# 다차원 배열 생성
matrix = np.array([[1, 2], [3, 4]])

고급 기능:

  • 브로드캐스팅
  • SIMD 벡터화 연산
  • FFT, 선형대수, 통계 함수
  • 대규모 데이터셋을 위한 메모리 매핑 파일 지원
  • 불필요한 복사를 방지하는 뷰(view) 기반 슬라이싱

성능 비교

벤치마크 코드:

import time

size = 10**6
py_list = list(range(size))
np_array = np.arange(size)

# Python 리스트 성능
start = time.time()
py_squared = [x**2 for x in py_list]
print("List Time:", time.time() - start)

# NumPy 배열 성능
start = time.time()
np_squared = np_array ** 2
print("NumPy Time:", time.time() - start)

결과:

 

NumPy 배열은 수치 연산에서 일반적으로 Python 리스트보다 10배에서 100배 정도 빠릅니다. 그 이유는 다음과 같습니다:

기술적 차이:

특징 Python 리스트 NumPy 배열
메모리 구조 객체에 대한 포인터 배열 일관된 C 타입으로 연속된 메모리 블록
타이핑 동적 정적(동질적)
벡터화 지원 없음 있음(SIMD, BLAS, LAPACK 사용)
메모리 효율성 낮음 높음
인터페이싱 순수 Python C, Fortran API

내부 구조:

  • Python 리스트: 각 요소는 전체 Python 객체(PyObject*)로 저장되어 포인터 추적이 필요하고, 캐시 지역성이 좋지 않습니다.
  • NumPy 배열: 요소가 연속된 메모리에 밀집 저장되며, SIMD 명령어 및 기본 BLAS 라이브러리를 활용합니다.

참고자료