본문 바로가기
Language & Tool/Python

🐍배열, 행렬 기반의 numpy

by 박수무당벌레 2025. 6. 17.

1. 핵심 개념

  • 다차원 배열(ndarray) 기반의 고속 수치 연산 라이브러리 (자료형 numpy.ndarray 전용)
    → Python(인터프리터 언어)과 달리 연산 로직이 C로 작성된 내부 루프를 통해 직접 수행 (= 수십 배 이상 빠르게 계산)
    for문 없이(반복제거) 배열 전체에 연산을 적용 가능한 벡터화 연산 지원 (C언어 + SIMD 명령어를 사용해서 CPU에서 병렬 계산)
  • 대규모 데이터 배열을 빠르게 처리하고, 과학 계산에 필수적인 기능들을 제공
    → 벡터화, 브로드캐스팅, 집계 함수 등을 통해 빠르고 효율적인 데이터 처리가 가능
  • 머신러닝, 데이터 분석(통계), 고성능 과학 계산 등 다양한 분야의 기초 인프라로 사용됨
  • 간단한 연산 외엔 BLAS, LAPACK, OpenBLAS, Intel MKL 등의 수학 라이브러리를 백엔드로 사용
pip install numpy  # 설치 필요

import numpy as np
a = np.array([1, 2, 3, 4])
b = a * 2
※ 내장 모듈인 math, operator와 달리 표준 라이브러리에 포함되지 않기 때문에 pip 설치 필요
※ 예시의 내부 동작 정리 
- a는 numpy.ndarray객체이므로 a * 2의 호출은, 사실상 a.__mul__(2)
→ Python의 일반 연산자가 아니라 C로 오버로드된 ufunc(범용 함수)라는 구조를 통해 동작 (__mul__ 오버로딩)
- ufunc는 반복 없이 배열 전체에 연산 적용, 내부는 C에서 컴파일되어 고속 실행됨
- (추가) 일부 연산은 외부 라이브러리에 맡기는데 CPU가 제공하는 SIMD 명령어(SSE, AVX 등)를 활용
※ 정렬 / 키 함수로서 사용 가능하지만 고급 연산에 더 적합함

 

 

2. 주요 함수 목록 (ufunc)

 

- 배열 생성

  설명 예시
np.array(object[, dtype=None, copy=True, ndmin=0, order='K']) 리스트 → ndarray 변환 np.array([1,2,3])
np.zeros(shape[, dtype=float, order='C']) 0으로 채운 배열 생성 np.zeros((2,3))
np.ones(shape[, dtype=float, order='C']) 1로 채운 배열 생성 np.ones(5)
np.full(shape, fill_value[, dtype=None, order='C']) 특정 값으로 채운 배열  생성  
np.eye(N[, M=None, k=0, dtype=float, order='C']) 단위 행렬 생성  
np.arange([start,] stop[, step=1, dtype=None]) range처럼 사용 (정수 또는 실수 가능) np.arange(0, 10, 2)
np.linspace(start, stop[, num=50, endpoint=True, dtype=None]) 구간을 일정 간격으로 나눈 값 생성 np.linspace(0, 1, 5)
numpy.copy(a, order='K', subok=False) or
ndarray.copy(order='C')
원본과 독립된 새로운 배열 생성 (깊은 복사) np.copy(a) or a.copy() 
(a는 ndarray)
※ 매개변수 의미
- dtype : 배열의 자료형(Data Type) 지정
- copy : 원본 배열을 복사할지 여부 (True일때 복사본 생성)
- ndmin : 최소 차원 수 지정 ex) 1 → 1D, 2 → 2D
- order : 메모리 순서 지정
  → 'C' (C 언어-연속 방식) : 행 우선(row-major) (기본값),  stride가 (col*itemsize, itemsize)
  → 'F' (Fortran-연 방식) : 열 우선(col-major) (행렬 계산 최적화 시 사용),  stride가 (itemsize, row*itemsize)
  → 'A' : 입력 배열을 기준으로 유지 (복사 시 메모리 순서 유지)
  → 'K' : 가능한 한 원본 배열의 순서( stride )를 유지하되, 구조체 호환도 고려 (복사, 정렬, 구조체 배열을 다룰때 유용)
- N / M : 행(N), 열(M)의 개수 (M 생략시 M=N이 되는 정사각 단위행렬)
- a : array_like, 복사할 원본 배열 (리스트, 튜플 등 array_like 가능)
- subok : bool (default False)
  → True : 서브클래스 유지
  → False : 항상 ndarray로 반환
※ np.copy(a) vs a.copy()
- NumPy 모듈 vs ndarray 메서드
- 둘다 동작 방식 동일
- 실제 데이터 버퍼까지 새로 복제
  → 내부적으로 C 레벨에서 새로운 메모리 블록 할당 후 memcpy 수행
  → 따라서 깊은 복사와 동일한 효과
※ stride 란?
- 메모리에서 한 요소에서 다음 요소로 이동하는 byte 간격
- 연속된 메모리에 저장되는데, 어떤 요소를 접근할 때 몇 byte를 건너뛸지 를 나타내는 값
- stride는 배열이 메모리를 어떻게 읽는지 정의
- stride 정보만 바뀌어도 새로운 배열 처럼 보임
→ 얕은 복사는 stride만 바꿔서 새로운 모양을 만듦
→ 깊은 복사는 stride까지 새롭게 계산해서 독립된 메모리를 만듦
  예시) a.T(얕은 복사, view)  a.T.copy()(깊은 복사)

 

- 배열 정보 조회

  설명 예시
a.shape 배열의 구조 반환 (2, 3)
a.ndim 배열 차원 수 반 2
a.size 총 원소 개수 반환 6
a.dtype 배열 데이터 타입 확 dtype('int64')
a.itemsize 요소 1개의 바이트 크기  
a.nbytes 전체 메모리 크기 (byte)  
a.T 전치(transpose)  
a.flatten([order='C']) 다차원 배열 → 1차원으로 평탄화  
a.reshape(shape[, order='C']) 배열 모양(구조) 변경 a.reshape(2,3)
※ 매개변수 의미
- a : 연산 대상 배열 (입력 배열)

 

- 배열 연산

  설명 예시
+, -, *, / 벡터화 연산 (요소별 계산) a + b
np.add(x1, x2[, out=None]) 덧셈 np.add(a, b) → a + b
np.subtract(x1, x2[, out=None]) 뺄셈  
np.multiply(x1, x2[, out=None]) 곱셈 np.multiply(a, b) → a * b
np.divide(x1, x2[, out=None]) 나눗셈  
np.power(x1, x2[, out=None]) 제곱  
np.sqrt(x[, out=None, where=True, casting='same_kind']) 각 요소의 제곱근 반환 np.sqrt(a)
np.exp(x[, out=None, where=True]) 각 요소에 대해 자연 지수함수 e^ 반환 np.exp(a)
np.sin(x[, out=None, where=True]) 각 요소(라디안 단위)의 사인 함수 값 반환 np.sin(a)
np.cos(x[, out=None, where=True]) 각 요소(라디안 단위)의 코사인 함수 값 반환  
np.dot(a, b[, out=None]) 행렬 곱 (내적)  
np.sum(a[, axis=None, dtype=None, keepdims=False]) 합계 계산 (집계 함수) np.sum(a, axis=0)
np.mean(a[, axis=None, dtype=None, keepdims=False]) 평균 계산 (집계 함수)  
np.std(a[, axis=None, dtype=None, ddof=0, keepdims=False]) 표준편차  
np.cumsum(a[, axis=None, dtype=None]) 누적합  
np.max(a[, axis=None, out=None, keepdims=False]) 배열 전체 또는 지정된 축(axis)에서 최댓값 반환 np.max(a)
np.min(a[, axis=None, out=None, keepdims=False]) 배열 전체 또는 지정된 축에서 최솟값 반환 np.min(a)
np.maximum(x1, x2[, out=None]) 두 배열의 각 원소별로 큰 값 반환 np.maximum(x, y)
※ 매개변수 의미
- x1, x2 : 요소별 계산 대상 배열 
- axis : 연산 방향 지정
  → 0 = 세로(행 단위), 1 = 가로(열 단위), None = 전체 배열에 대한 연산(축 무시)
- out : 결과 저장 배열 지정 (= 새 배열이 아닌 기존 배열에 덮어쓰기) → 메모리 재활용 목적
- where : True인 위치만 계산하고 나머지는 그대로 유지 (조건 필터링)
- casting : 자료형 변환 허용 범위 지정
  → 'no' : 자료형 변환 불가(정확히 일치), 'equiv' : 동일 표현 범위 안에서는 허용
  → 'safe' : 안전한 경우에만 허용 ex) int → float,  'same_kind' : 유사한 종류끼리 허용 ex) int ↔ float
  → 'unsafe' : 모든 형 변환 허용
- keepdims : 축(axis) 기준 연산 후, 차원 수를 유지할지 결정
  → False : 축 방향 차원이 사라짐 (기본값), True : 차원 유지 (크기가 1로 바뀜)
- ddof : 0일때 모집단 기준(기본값), 1일때 표본 기준

 

- 슬라이싱 & 인덱싱

  설명 예시
a[start:stop[:step]] 행/열 슬라이싱 a[1:3], a[:, 0]
a[a > 3] 조건 필터링 (Boolean Indexing)  
a[[1, 3, 4]] 정수 인덱싱  
a.take(indices[, axis=None]) 인덱스 기반 추출  

 

- 랜덤 생성

  설명 예시
np.random.rand(d0, d1, ..., dn) [0,1) 균일분포 난수 생성 np.random.rand(3)
np.random.randn(d0, d1, ..., dn) 표준 정규분포  
np.random.randint(low[, high=None, size=None, dtype=int]) 정수 난수 생성 np.random.randint(1,10,5)
np.random.choice(a[, size=None, replace=True, p=None]) 샘플링  
np.random.shuffle(x) 배열 섞기 (in-place)  
np.random.seed(seed) 난수 고정용 시드 설정 np.random.seed(42)
※ 매개변수 의미
- d0, d1, ... : 배열의 각 차원 크기 지정

 

- 비교/논리

  설명 예시
np.where(condition[, x, y]) 조건에 따라 값 선택 np.where(a > 0, 1, -1)
np.isin(element, test_elements[, assume_unique=False]) 특정 값 포함 여부 np.isin(a, [3, 7])
np.equal(x1, x2) 요소별 비교 (==)  
np.greater(x1, x2) 요소별 비교 (>)  
np.logical_and(x1, x2) 논리곱  
np.all(a[, axis=None, keepdims=False]) 모두 True인지 확인 np.all(a > 0)
np.any(a[, axis=None, keepdims=False]) 하나라도 True인지 확인  
※ 매개변수 의미
- element : 포함 여부 확인 대상 값 (or 배열)
- test_elements : 비교 대상 배열, element가 이 안에 있는지 확인
- assume_unique : True일 경우 중복 제거 건너뜀 (성능 높임)

 

- 기타 함수

  설명 예시
np.unique(ar[, return_index=False, return_counts=False]) 중복 제거 후 정렬된 고유값 반환 np.unique([1,2,1,3])
np.argsort(a[, axis=-1, kind='quicksort', order=None]) 정렬 시 인덱스 반환 np.argsort(a)
np.sort(a[, axis=-1, kind='quicksort', order=None]) 정렬  
np.clip(a, a_min, a_max[, out=None]) 값 범위 제한  
np.concatenate((a1, a2, ...)[, axis=0, out=None]) 배열 연결  
np.stack(arrays[, axis=0, out=None]) 배열 새 차원으로 쌓기  
np.argmin(a[, axis=None, out=None]) 최솟값 위치 인덱스 반환  
np.argmax(a[, axis=None, out=None]) 최댓값 위치 인덱스 반  
※ 매개변수 의미
- kind : 정렬 알고리즘 종류
  → 'quicksort' : 빠른 정렬 (기본값), 'mergesort' : 병합 정렬 (= 순서가 유지되는 안정 정렬)
  → 'heapsort' : 힙 정렬 (= 메모리 적게 씀), 'stable' : 'mergesort'와 동일 (NumPy 1.15부터 권장)