콘텐츠로 이동

개요

과학적 컴퓨팅을 위한 핵심 라이브러리 다차원 배열 객체와 이를 다르기 위한 도구들을 제공하며, 거의 모든 파이썬 데이터 사이언스 라이브러리의 기반이 된다.

특징

1. 고성능 다차원 배열

  • ndarray : 핵심 데이터 구조
  • 동질적 데이터 : 모든 원소가 같은 데이터 타입
  • C/Fortran으로 구현 : 파이썬 리스트보다 월등히 빠른 연산 속도
  • 메모리 효율성 : 연속된 메모리 블록에 데이터 저장

2. 백터화 연산

  • 브로드캐스팅 : 다른 크기의 배열 간 연산 가능
  • 유니버셜 함수(ufunc) : 원소별 연산을 고속으로 처리
  • No Loop 필요 : 명시적 반복문 없이 배열 전체 연산

설치

pip install numpy

import numpy as np

배열 생성

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의 장점

  1. 속도: C로 구현되어 파이썬 리스트보다 10-100배 빠름
  2. 메모리 효율성: 연속된 메모리 블록 사용
  3. 풍부한 함수: 수학, 통계, 선형대수 함수 제공
  4. 생태계: 판다스, 사이킷런 등 다른 라이브러리의 기반
  5. 브로드캐스팅: 유연한 배열 연산