개요
과학적 컴퓨팅을 위한 핵심 라이브러리 다차원 배열 객체와 이를 다르기 위한 도구들을 제공하며, 거의 모든 파이썬 데이터 사이언스 라이브러리의 기반이 된다.
특징
1. 고성능 다차원 배열
- ndarray : 핵심 데이터 구조
- 동질적 데이터 : 모든 원소가 같은 데이터 타입
- C/Fortran으로 구현 : 파이썬 리스트보다 월등히 빠른 연산 속도
- 메모리 효율성 : 연속된 메모리 블록에 데이터 저장
2. 백터화 연산
- 브로드캐스팅 : 다른 크기의 배열 간 연산 가능
- 유니버셜 함수(ufunc) : 원소별 연산을 고속으로 처리
- No Loop 필요 : 명시적 반복문 없이 배열 전체 연산
설치
pip install numpy
배열 생성
1. 기본 생성 방법
# 리스트에서 생성
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([1, 2](1,%202)) # 2차원 배열
# 특정 값으로 초기화
zeros = np.zeros((3, 4)) # 0으로 채운 3x4 배열
ones = np.ones((2, 3)) # 1로 채운 2x3 배열
empty = np.empty((2, 2)) # 초기화되지 않은 배열
full = np.full((2, 3), 7) # 7로 채운 2x3 배열
# 단위 행렬
identity = np.eye(3) # 3x3 단위 행렬
2. 범위와 간격
# 범위 생성
arange = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
linspace = np.linspace(0, 1, 5) # [0, 0.25, 0.5, 0.75, 1.0]
# 랜덤 배열
random = np.random.random((2, 3)) # 0~1 사이 난수
normal = np.random.normal(0, 1, (3, 3)) # 평균 0, 표준편차 1 정규분포
배열 속성
arr = np.array([1, 2, 3](1,%202,%203))
# 기본 속성
print(arr.shape) # (2, 3) - 배열 모양
print(arr.size) # 6 - 전체 원소 개수
print(arr.ndim) # 2 - 차원 수
print(arr.dtype) # int64 - 데이터 타입
print(arr.itemsize) # 8 - 각 원소의 바이트 크기
인덱싱과 슬라이싱
1. 기본 인덱싱
arr = np.array([0, 1, 2, 3, 4, 5])
# 기본 인덱싱
print(arr[0]) # 0
print(arr[-1]) # 5
print(arr[1:4]) # [1, 2, 3]
# 2차원 배열
arr2d = np.array([1, 2, 3](1,%202,%203))
print(arr2d[1, 2]) # 6
print(arr2d[1:, :2]) # [4, 5](4,%205)
2. 고급 인덱싱
# 불린 인덱싱
arr = np.array([1, 2, 3, 4, 5])
mask = arr > 3
print(arr[mask]) # [4, 5]
# 팬시 인덱싱
indices = [0, 2, 4]
print(arr[indices]) # [1, 3, 5]
배열 연산
1. 산술 연산
a = np.array([1, 2, 3, 4])
b = np.array([5, 6, 7, 8])
# 기본 연산
print(a + b) # [6, 8, 10, 12]
print(a * 2) # [2, 4, 6, 8]
print(a ** 2) # [1, 4, 9, 16]
# 배열 간 연산
print(a * b) # [5, 12, 21, 32]
print(a / b) # [0.2, 0.33, 0.43, 0.5]
2. 수학 함수
arr = np.array([1, 4, 9, 16])
# 수학 함수들
print(np.sqrt(arr)) # [1, 2, 3, 4]
print(np.log(arr)) # 자연로그
print(np.sin(arr)) # 사인 함수
print(np.abs(arr)) # 절댓값
통계 함수
arr = np.array([1, 2, 3](1,%202,%203))
# 기본 통계
print(np.mean(arr)) # 3.5 - 평균
print(np.median(arr)) # 3.5 - 중간값
print(np.std(arr)) # 표준편차
print(np.var(arr)) # 분산
# 축별 연산
print(np.sum(arr, axis=0)) # [5, 7, 9] - 열별 합
print(np.sum(arr, axis=1)) # [6, 15] - 행별 합
# 최댓값, 최솟값
print(np.max(arr)) # 6
print(np.min(arr)) # 1
print(np.argmax(arr)) # 5 - 최댓값의 인덱스
배열 조작
1. 모양 변경
arr = np.arange(12)
# reshape - 모양 변경
reshaped = arr.reshape(3, 4) # 3x4로 변경
reshaped = arr.reshape(-1, 3) # 자동으로 4x3
# 차원 조작
flattened = reshaped.flatten() # 1차원으로 평탄화
ravel = reshaped.ravel() # flatten과 유사하지만 뷰 반환
# 전치
transposed = reshaped.T # 전치 행렬
2. 배열 결합과 분할
a = np.array([1, 2](1,%202))
b = np.array([5, 6](5,%206))
# 결합
vstack = np.vstack([a, b]) # 세로로 결합
hstack = np.hstack([a, b]) # 가로로 결합
concatenate = np.concatenate([a, b], axis=0) # 축 지정하여 결합
# 분할
arr = np.arange(10)
split1, split2 = np.split(arr, [3]) # 인덱스 3에서 분할
hsplit = np.hsplit(arr.reshape(2, 5), 5) # 가로로 분할
브로드캐스팅
# 다른 크기 배열 간 연산
a = np.array([[1, 2, 3],
[4, 5, 6]]) # (2, 3)
b = np.array([10, 20, 30]) # (3,)
result = a + b # 브로드캐스팅으로 자동 확장
# [[11, 22, 33],
# [14, 25, 36]]
# 스칼라와의 연산
arr = np.array([1, 2, 3, 4])
result = arr * 10 # [10, 20, 30, 40]
선형대수
# 행렬 곱셈
a = np.array([1, 2](1,%202))
b = np.array([5, 6](5,%206))
matmul = np.matmul(a, b) # 또는 a @ b
dot = np.dot(a, b) # 내적
# 고급 선형대수 (numpy.linalg)
det = np.linalg.det(a) # 행렬식
inv = np.linalg.inv(a) # 역행렬
eigenvals, eigenvecs = np.linalg.eig(a) # 고유값, 고유벡터
조건문과 논리 연산
arr = np.array([1, 2, 3, 4, 5])
# 조건문
result = np.where(arr > 3, arr, 0) # [0, 0, 0, 4, 5]
# 논리 연산
print(np.any(arr > 3)) # True - 하나라도 조건 만족
print(np.all(arr > 0)) # True - 모두 조건 만족
# 조건 결합
mask = (arr > 2) & (arr < 5) # [False, False, True, True, False]
파일 입출력
arr = np.array([1, 2, 3](1,%202,%203))
# 저장
np.save('array.npy', arr) # 바이너리 형식
np.savetxt('array.txt', arr) # 텍스트 형식
# 불러오기
loaded = np.load('array.npy')
loaded_txt = np.loadtxt('array.txt')
# CSV 파일
np.savetxt('array.csv', arr, delimiter=',')
loaded_csv = np.loadtxt('array.csv', delimiter=',')
성능 최적화 팁
1. 벡터화 활용
# 비효율적인 방법 (반복문)
result = []
for i in range(len(arr)):
result.append(arr[i] ** 2)
# 효율적인 방법 (벡터화)
result = arr ** 2
2. 메모리 관리
# 뷰 vs 복사
arr = np.array([1, 2, 3, 4, 5])
view = arr[::2] # 뷰 생성 (메모리 공유)
copy = arr[::2].copy() # 복사본 생성
# 인플레이스 연산
arr += 1 # 새로운 배열 생성하지 않음
데이터 타입
# 다양한 데이터 타입
int_arr = np.array([1, 2, 3], dtype=np.int32)
float_arr = np.array([1, 2, 3], dtype=np.float64)
bool_arr = np.array([True, False, True], dtype=np.bool_)
# 타입 변환
converted = int_arr.astype(np.float64)
실제 활용 예시
# 이미지 처리 예시
import matplotlib.pyplot as plt
# 가상의 이미지 데이터 (100x100 픽셀)
image = np.random.rand(100, 100)
# 이미지 필터링
filtered = np.where(image > 0.5, 1, 0)
# 통계 분석 예시
data = np.random.normal(100, 15, 1000) # 평균 100, 표준편차 15
print(f"평균: {np.mean(data):.2f}")
print(f"표준편차: {np.std(data):.2f}")
print(f"95% 구간: {np.percentile(data, [2.5, 97.5])}")
NumPy의 장점
- 속도: C로 구현되어 파이썬 리스트보다 10-100배 빠름
- 메모리 효율성: 연속된 메모리 블록 사용
- 풍부한 함수: 수학, 통계, 선형대수 함수 제공
- 생태계: 판다스, 사이킷런 등 다른 라이브러리의 기반
- 브로드캐스팅: 유연한 배열 연산