본문으로 건너뛰기
Advertisement

NumPy 완전 정복

NumPy는 Python 과학 컴퓨팅의 핵심 라이브러리입니다. ndarray 기반 벡터 연산으로 순수 Python보다 수십~수백 배 빠릅니다.


설치와 임포트

pip install numpy
import numpy as np

ndarray 생성

# 리스트로 생성
a = np.array([1, 2, 3, 4, 5]) # 1D
b = np.array([[1, 2, 3], [4, 5, 6]]) # 2D

print(a.shape) # (5,)
print(b.shape) # (2, 3)
print(b.dtype) # int64
print(b.ndim) # 2

# 특수 배열
np.zeros((3, 4)) # 0으로 채운 3x4
np.ones((2, 3)) # 1로 채운 2x3
np.eye(4) # 4x4 단위행렬
np.full((3, 3), 7) # 7로 채운 3x3

# 범위 배열
np.arange(0, 10, 2) # [0 2 4 6 8]
np.linspace(0, 1, 5) # [0. 0.25 0.5 0.75 1. ]

# 난수
np.random.seed(42)
np.random.rand(3, 3) # 균등분포 [0, 1)
np.random.randn(3, 3) # 표준정규분포
np.random.randint(1, 100, (3, 3)) # 정수 난수

인덱싱과 슬라이싱

a = np.array([10, 20, 30, 40, 50])
b = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# 기본 인덱싱
print(a[0]) # 10
print(a[-1]) # 50
print(b[1, 2]) # 6 (1행 2열)

# 슬라이싱
print(a[1:4]) # [20 30 40]
print(b[:, 1]) # [2 5 8] (전체 행의 1열)
print(b[0:2, 1:]) # [[2 3] [5 6]]

# 불리언 인덱싱 (조건 필터링)
a = np.array([10, 25, 3, 48, 12, 37])
mask = a > 20
print(a[mask]) # [25 48 37]
print(a[a > 20]) # 동일: [25 48 37]

# 팬시 인덱싱 (인덱스 배열)
idx = np.array([0, 2, 4])
print(a[idx]) # [10 3 12]

브로드캐스팅

# 스칼라 연산 (모든 원소에 적용)
a = np.array([1, 2, 3, 4, 5])
print(a * 2) # [2 4 6 8 10]
print(a ** 2) # [ 1 4 9 16 25]
print(a > 3) # [False False False True True]

# 배열 간 연산 (같은 shape → 원소별 연산)
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])
print(x + y) # [5 7 9]
print(x * y) # [ 4 10 18]

# 브로드캐스팅: shape이 달라도 규칙에 따라 자동 확장
a = np.array([[1, 2, 3], [4, 5, 6]]) # shape (2, 3)
b = np.array([10, 20, 30]) # shape (3,) → (1, 3) → (2, 3)
print(a + b)
# [[11 22 33]
# [14 25 36]]

# 열 벡터 브로드캐스팅
col = np.array([[100], [200]]) # shape (2, 1) → (2, 3)
print(a + col)
# [[101 102 103]
# [204 205 206]]

벡터 연산

# 수학 함수
a = np.array([1, 4, 9, 16, 25], dtype=float)
print(np.sqrt(a)) # [1. 2. 3. 4. 5.]
print(np.log(a)) # 자연로그
print(np.exp(np.array([0, 1, 2]))) # [1. 2.718 7.389]

# 통계 함수
a = np.array([[1, 2, 3], [4, 5, 6]])
print(a.sum()) # 21 (전체)
print(a.sum(axis=0)) # [5 7 9] (열 방향 합)
print(a.sum(axis=1)) # [ 6 15] (행 방향 합)
print(a.mean()) # 3.5
print(a.std()) # 표준편차
print(a.min(), a.max()) # 1 6
print(a.argmin()) # 0 (최솟값 인덱스)
print(a.argmax()) # 5

# 정렬
a = np.array([3, 1, 4, 1, 5, 9, 2, 6])
print(np.sort(a)) # [1 1 2 3 4 5 6 9]
print(np.argsort(a)) # 정렬된 인덱스

선형대수

# 행렬 곱 (dot product)
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

print(A @ B) # 행렬 곱 [[19 22] [43 50]]
print(np.dot(A, B)) # 동일

# 전치행렬
print(A.T) # [[1 3] [2 4]]

# 역행렬
print(np.linalg.inv(A))

# 행렬식 (determinant)
print(np.linalg.det(A)) # -2.0

# 고유값/고유벡터
eigenvalues, eigenvectors = np.linalg.eig(A)

# 연립방정식 풀기: Ax = b
b = np.array([5, 11])
x = np.linalg.solve(A, b) # x = [1. 2.]

# 내적 (벡터)
v1 = np.array([1, 2, 3])
v2 = np.array([4, 5, 6])
print(np.dot(v1, v2)) # 32
print(np.linalg.norm(v1)) # 벡터 크기 (L2 norm)

배열 변환

a = np.arange(12)

# reshape — 총 원소 수 유지
b = a.reshape(3, 4) # (12,) → (3, 4)
c = a.reshape(2, 2, 3) # (12,) → (2, 2, 3)
d = a.reshape(-1, 3) # -1은 자동 계산 → (4, 3)

# flatten / ravel
print(b.flatten()) # 1D 복사본
print(b.ravel()) # 1D 뷰 (메모리 공유)

# 쌓기 (concatenate / stack)
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])

np.concatenate([x, y]) # [1 2 3 4 5 6]
np.vstack([x, y]) # [[1 2 3] [4 5 6]]
np.hstack([x.reshape(-1,1), y.reshape(-1,1)]) # 열 방향 결합

# 분리
np.split(np.arange(9), 3) # [array([0,1,2]), array([3,4,5]), array([6,7,8])]

실전 예제 — 이미지 처리

# 이미지 = 픽셀값 배열
image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8) # 100x100 RGB

# 그레이스케일 변환 (가중 평균)
gray = (0.299 * image[:,:,0] + 0.587 * image[:,:,1] + 0.114 * image[:,:,2]).astype(np.uint8)

# 밝기 조정 (클리핑)
bright = np.clip(image.astype(int) + 50, 0, 255).astype(np.uint8)

# 좌우 반전
flipped = image[:, ::-1, :]

정리

기능방법
배열 생성np.array(), np.zeros(), np.arange()
조건 필터링불리언 인덱싱 a[a > 0]
원소별 연산+, -, *, /, **
방향별 집계.sum(axis=0), .mean(axis=1)
행렬 곱@ 연산자 또는 np.dot()
형태 변환.reshape(), .flatten()

NumPy의 핵심은 반복문 없이 배열 전체에 연산을 적용하는 벡터화(vectorization)입니다.

Advertisement