강의
https://cs231n.github.io/python-numpy-tutorial
Numpy란?
- Numerical Python의 줄임말
- 파이썬의 고성능 과학 계산용 패키지
- Matrix와 Vector와 같은 Array 연산의 사실상의 표준
Numpy 특징
- 다차원 배열 객체: NumPy의 핵심 기능 중 하나는
ndarray
라 불리는 다차원 배열을 제공하는 것입니다. - 브로드캐스팅 기능: 서로 다른 크기의 배열 간에도 산술 연산이 가능하게 해줍니다.
- 효율적인 수학 함수: 고성능의 다양한 수학적 연산을 수행할 수 있는 함수를 제공합니다. 이 함수들은 배열의 각 요소별 연산을 지원하며, 수학, 통계, 선형대수 등의 분야에 활용될 수 있습니다.
- 배열 인덱싱: 데이터의 일부를 선택하거나 조작할 때 유용한 다양한 인덱싱 방법을 제공합니다. 슬라이싱, 마스킹, 정수 인덱싱 등을 포함합니다.
- 메모리 효율성: NumPy 배열은 기본 Python 리스트에 비해 더 적은 메모리를 사용하며, 배열 간의 연산 속도도 훨씬 빠릅니다.
- C/C++ 및 Fortran 코드 통합: NumPy는 C나 C++, Fortran 등 다른 언어로 작성된 코드와 통합할 수 있는 기능을 제공합니다.
- 파일 입출력: 데이터를 파일에 저장하고 불러오는 기능을 제공합니다. NumPy 자체의 바이너리 형식 뿐만 아니라, 텍스트 파일이나 다른 파일 형식을 지원합니다.
Numpy 호출 방법
# numpy 설치하기
pip install numpy
# numpy 호출하기
# np는 넘파이를 사용할 때 일반적으로 사용되는 관례적인 약칭
import numpy as np
ndarray
ndarray란?
- NumPy에서 제공하는 N-dimensional array의 약자
- 파이썬에서 고성능의 다차원 배열을 구현한 것
- 모든 원소가 동일한 데이터 타입
- 고정된 크기의 다차원 그리드 형태로 데이터를 저장
- 과학 계산을 위한 다양한 연산과 함께 빠른 배열 처리를 가능하게 하는 기능을 제공
ndarray 특징
- 동질성: 배열의 모든 요소는 같은 데이터 타입을 가져야함
- 고정된 크기: 생성 시 지정된 배열의 크기는 변경할 수 없음. 배열의 크기를 변경하려면 새 배열을 생성하고 원래 데이터를 복사해야함
- 다차원 데이터 지원:
ndarray
는 다차원 데이터를 효과적으로 처리할 수 있으며, 이는 과학 및 엔지니어링 계산에 매우 유용 - 빠른 연산 속도: NumPy의 내부는 C와 C++로 구현되어 있어, 순수 파이썬보다 훨씬 빠른 연산이 가능
- 브로드캐스팅: 서로 다른 크기를 가진 배열 간에도 연산을 수행할 수 있는 능력을 제공
np.array()
# 기본 형태
array = np.array(sequence_data)
# 정수 리스트로부터 1차원 배열 생성
arr1 = np.array([1, 2, 3, 4, 5])
# 중첩 리스트로부터 2차원 배열 생성
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
- 파이썬의 리스트나 튜플과 같은 다양한 시퀀스 데이터를
numpy.ndarray
객체로 변환하는 데 사용 - 하나의 데이터 타입만 배열에 넣을 수 있음 → 속도 증가
- C의 Array를 사용하여 배열을 생성함
- 메모리에 연속적으로 저장됌
- 보통은 2차원 데이터를 많이 다루고, 이미지의 경우 3차원 데이터를 다룬다
- 생성된 배열의 데이터 타입은 입력 데이터에 따라 자동으로 결정
dtype
매개변수를 통해 명시적으로 지정할 수도 있음
Array 만드는 함수
arange
# 기본 형태
numpy.arange([start, ]stop, [step, ]dtype=None)
# 기본 사용
# 출력: [0 1 2 3 4]
arr1 = np.arange(5)
# 시작, 종료, 간격 지정
# 출력: [2 4 6 8]
arr2 = np.arange(2, 9, 2)
# 부동 소수점
# 출력: [0. 0.5 1. 1.5 2. 2.5 3. 3.5 4. 4.5]
arr3 = np.arange(0, 5, 0.5)
# 데이터 타입 지정
# 출력: [0. 1. 2. 3. 4.]
arr4 = np.arange(5, dtype=np.float64)
- 주어진 범위 내에서 일정한 간격의 값을 갖는 배열을 생성
- 반복문에서 사용할 인덱스 배열을 생성하거나, 기본적인 순차적 데이터를 빠르게 생성할 때 유용.
- 또한, 시각화에서 x축의 포인트를 지정하거나, 수학적 연산을 위한 초기 벡터/행렬을 만들 때 자주 사용
ones
# 기본 사용법
numpy.ones(shape, dtype=None, order='C')
# 1차원 배열 생성
# [1. 1. 1. 1. 1.]
ones_array = np.ones(5)
# 2차원 배열 생성
# [[1. 1. 1. 1.]
# [1. 1. 1. 1.]
# [1. 1. 1. 1.]]
ones_matrix = np.ones((3, 4))
# int 타입으로 2차원 배열 생성
# [[1 1 1]
# [1 1 1]]
ones_int_matrix = np.ones((2, 3), dtype=np.int)
- 모든 요소가 1인 NumPy 배열을 생성
- 특정 모양(shape)과 데이터 타입(dtype)을 가진 배열을 초기화할 때 유용
- order: 배열의 메모리에 저장되는 순서를
'C'
스타일(행 우선 순서) 또는'F'
스타일(열 우선 순서)로 지정합니다. 대부분의 경우 기본값인'C'
를 사용합니다.
zeros
# 기본 사용법
numpy.zeros(shape, dtype=None, order='C')
# 1차원 배열 생성
# [0. 0. 0. 0. 0.]
zeros_array = np.zeros(5)
# 2차원 배열 생성
# [[0. 0. 0.]
[0. 0. 0.]]
zeros_matrix = np.zeros((2, 3))
# int 타입으로 3차원 배열 생성
# [[[0 0 0]
[0 0 0]]
[[0 0 0]
[0 0 0]]]
zeros_int_cube = np.zeros((2, 2, 3), dtype=np.int)
- 모든 요소가 0인 NumPy 배열을 생성하는 데 사용
- 특정 모양(shape)과 데이터 타입(dtype)을 가진 배열을 0으로 초기화할 때 매우 유용
empty
- memory initailization이 되지 않음
- 기존에 남아있던 값들이 출력됌
something_like
- 기존 ndarray의 shape 크기 만큼 1, 0 또는 empty array를 반환
identity
eye
diag
- k
random sampling
- uniform
- normal
많이 사용하는 함수들
dtype 객체
# 정수 배열 생성
arr_int = np.array([1, 2, 3], dtype=np.int32)
# 부동소수점 배열 생성
arr_float = np.array([1.0, 2.0, 3.0], dtype=np.float64)
- ndarray의 데이터 타입을 설명하는 객체
- NumPy에서는 배열 내의 모든 요소가 동일한 타입을 가져야 하며,
dtype
은 해당 타입을 명시적으로 정의 - 정수형
int8
,int16
,int32
,int64
: 각각 8, 16, 32, 64비트 크기의 정수를 나타냅니다. 부호가 있는 정수형입니다.uint8
,uint16
,uint32
,uint64
: 각각 8, 16, 32, 64비트 크기의 부호 없는 정수(양의 정수)를 나타냅니다.
- 부동소수점
float16
,float32
,float64
: 각각 16, 32, 64비트 크기의 부동소수점 수를 나타냅니다. 이들은 실수를 표현합니다.float128
: 일부 시스템에서는 128비트 부동소수점 수를 지원합니다.
- 복소수형
complex64
,complex128
: 각각 64, 128비트 크기의 복소수를 나타냅니다. 이들은 실수부와 허수부를 갖는 수입니다.complex256
: 일부 시스템에서는 256비트 복소수를 지원합니다.
- 기타 타입
bool
: 불리언 값을 나타내며,True
또는False
값을 가질 수 있습니다.object
: 파이썬 객체를 배열 요소로 사용할 수 있게 합니다. 이는 NumPy 배열이 파이썬의 거의 모든 종류의 객체를 담을 수 있게 해줍니다.string_
: 고정 길이 문자열을 나타냅니다. 문자열의 길이는dtype
을 생성할 때 지정해야 합니다.unicode_
: 유니코드 문자열을 나타내는데 사용됩니다. 고정 길이이며, 길이는dtype
을 생성할 때 지정합니다.
shape 속성
# (5,)
arr1d = np.array([1, 2, 3, 4, 5])
arr1d.shape
# (2, 3)
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
arr2d.shape
# (2, 2, 2)
arr3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
arr3d.shape
- 배열의 구조를 나타냄
- 각 차원(dimension)에서의 배열의 크기(size)를 튜플(tuple) 형태로 표현
ndim 속성
# 출력: 1
arr1d = np.array([1, 2, 3, 4, 5])
arr1d.ndim
# 출력: 2
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
arr2d.ndim
# 출력: 3
arr3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
arr3d.ndim
- 배열의 차원 수
- 배열이 가진 차원의 개수를 정수로 반환
size 속성
# 출력: 5
arr1d = np.array([1, 2, 3, 4, 5])
arr1d.size
# 출력: 6
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
arr2d.size
# 출력: 8
arr3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
arr3d.size
- NumPy 배열에 포함된 전체 요소의 개수
- 즉,
size
는 배열 내의 총 원소 수를 하나의 정수로 표현한 것
nbytes 속성
# int32 타입의 1차원 배열 생성
# int32는 보통 4바이트를 사용
# 총 20바이트(5 * 4)를 사용
arr1 = np.array([1, 2, 3, 4, 5], dtype=np.int32)
# float64 타입의 2차원 배열 생성
# float64는 보통 8바이트를 사용
# 총 48바이트(6 * 8)를 사용
arr2 = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], dtype=np.float64)
- NumPy 배열이 메모리에서 차지하는 총 바이트 수
- 배열의
dtype
과size
에 따라 결정됩니다.
reshape()
# 1차원 배열 생성
arr = np.arange(6)
# 1차원 배열을 2x3 2차원 배열로 재구성
reshaped_arr = arr.reshape((2, 3))
# 자동으로 크기를 계산하여 재구성
auto_reshaped_arr = arr.reshape((-1, 3))
- NumPy 배열의 형태를 변경하는 데 사용
- 배열의 총 요소 수를 유지하면서, 지정된 새로운 형태로 배열의 차원과 크기를 재구성
- 배열의 데이터 자체를 변경하지 않고, 배열의 뷰(view)를 변경하여 새로운 형태를 제공
- 데이터를 다른 형태로 효율적으로 재해석하고자 할 때 유용
- 한 차원을
1
로 지정하면, 해당 차원의 크기가 자동으로 계산
flatten
# 2차원 배열 생성
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
# 2차원 배열을 1차원 배열로 평탄화
# 결과 [1, 2, 3, 4, 5, 6]
flattened_arr = arr2d.flatten()
- NumPy 배열을 1차원 배열로 변환하는 데 사용
- 배열의 복사본을 생성하여 반환하기 때문에, 원본 배열은 변경되지 않음
astype
# float64 타입의 배열 생성
arr_float64 = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
# float64에서 int32 타입으로 변환
arr_int32 = arr_float64.astype(np.int32)
# int32에서 float32 타입으로 변환
arr_float32 = arr_int32.astype(np.float32)
- NumPy 배열의 데이터 타입을 변환하는 데 사용
- 타입이 변환된 배열의 새로운 복사본을 생성하여 반환. 원본 배열은 변경되지 않음
- 불필요하게 큰 데이터 타입을 더 작은 타입으로 변환함으로써 메모리 사용량을 최적화할 수 있음
- 특정 연산이나 알고리즘 요구사항에 맞추어 데이터 타입을 조정할 수 있음
Indexing
# 1차원 배열 생성
arr = np.array([10, 20, 30, 40, 50])
# 단일 요소 접근
# 출력: 30
print(arr[2])
# 2차원 배열 생성
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 다차원 배열에서의 단일 요소 접근
# 출력: 6
print(arr2d[1, 2])
- 단일 요소 접근:
array[i]
- 다차원 배열:
array[i, j]
Slicing
# 기본 구조
array[start:stop:step]
# 1차원 배열 슬라이싱
# [0 1 2 3 4 5 6 7 8 9]
arr = np.arange(10)
# [2 4 6]
arr[2:7:2]
# 2차원 배열 생성
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# [[1 2 3]
# [4 5 6]]
arr2d[0:2]
# [[2 3]
# [5 6]
# [8 9]]
arr2d[:, 1:3]
# [4 5]
arr2d[1, 0:2]
- 배열의 부분집합을 선택하는 방법
- 원본 배열의 연속적인 요소들을 선택하여 새로운 배열(view)을 생성할 수 있음
- 슬라이싱은 원본 배열에 대한 뷰를 반환하기 때문에, 슬라이싱을 통해 생성된 배열을 수정하면 원본 배열도 함께 수정됌
- 원본 데이터를 보존하고 싶다면, 슬라이싱 결과를
.copy()
메서드를 사용하여 복사
- 시작 인덱스는 포함되고 종료 인덱스는 포함되지 않음
- 간격은 선택적으로 지정할 수 있음
- 다차원 배열에서 슬라이싱을 사용할 때는 각 차원별로 슬라이싱을 지정할 수 있음
- 콤마(
,
)를 사용하여 각 차원의 슬라이스를 구분
- 콤마(
계산 함수
sum
# 기본 사용법
numpy.sum(a, axis=None, dtype=None, out=None, keepdims=False, initial=0, where=True)
# 1차원 배열의 합
arr = np.array([1, 2, 3, 4])
# 출력: 10
np.sum(arr)
# 2차원 배열 생성
arr2d = np.array([[1, 2], [3, 4]])
# 출력: 10
np.sum(arr2d)
# 각 열의 합
# 출력: [4 6]
np.sum(arr2d, axis=0)
# 각 행의 합
# 출력: [3 7]
np.sum(arr2d, axis=1)
# 출력:
# [[3]
# [7]]
np.sum(arr2d, axis=1, keepdims=True)
- 배열의 요소들을 합하는 연산을 수행
- 지정된 축(axis)에 따라 합을 계산하는 기능도 제공
mean
# 기본 사용법
numpy.mean(a, axis=None, dtype=None, out=None, keepdims=np._NoValue)
# 1차원 배열의 평균
arr = np.array([1, 2, 3, 4])
# 출력: 2.5
np.mean(arr)
# 2차원 배열 생성
arr2d = np.array([[1, 2], [3, 4]])
# 전체 평균
# 출력: 2.5
np.mean(arr2d)
# 각 열의 평균 (axis=0)
# 출력: [2. 3.]
np.mean(arr2d, axis=0)
# 각 행의 평균 (axis=1)
# 출력: [1.5 3.5]
np.mean(arr2d, axis=1)
# keepdims 사용 예
# 출력:
# [[1.5]
# [3.5]]
np.mean(arr2d, axis=1, keepdims=True)
- 주어진 배열의 요소들의 산술 평균(average)을 계산
- 특정 축(axis)을 따라 평균을 계산하는 기능도 제공
std
# 기본 사용법
# ddof: 델타 자유도(Delta Degrees of Freedom). 기본값은 0이며, 분모에서 사용되는 N-ddof에서 N은 요소의 수입니다.
numpy.std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=np._NoValue)
# 1차원 배열의 표준편차
# 출력: 1.118033988749895
arr = np.array([1, 2, 3, 4])
# 2차원 배열 생성
arr2d = np.array([[1, 2], [3, 4]])
# 전체 표준편차
# 출력: 1.118033988749895
np.std(arr2d)
# 각 열의 표준편차 (axis=0)
# 출력: [1. 1.]
np.std(arr2d, axis=0)
# 각 행의 표준편차 (axis=1)
# 출력: [0.5 0.5]
np.std(arr2d, axis=1)
# keepdims 사용 예
# 출력:
# [[0.5]
# [0.5]]
np.std(arr2d, axis=1, keepdims=True)
- 주어진 배열의 요소들에 대한 표준편차(standard deviation)를 계산
- 표준편차는 데이터의 분산을 측정하는 값으로, 데이터가 평균으로부터 얼마나 퍼져 있는지를 나타냄
- 전체 배열 또는 지정된 축을 따라서 표준편차를 계산할 수 있으며, 다차원 배열에서도 사용할 수 있음
그 외 수학 연산자
- 기본 수학 연산
np.add
: 요소별 덧셈np.subtract
: 요소별 뺄셈np.multiply
: 요소별 곱셈np.divide
: 요소별 나눗셈np.sqrt
: 요소별 제곱근np.square
: 요소별 제곱np.power
: 요소별 거듭제곱np.exp
: 요소별 지수 함수np.log
: 요소별 자연 로그np.log10
: 요소별 상용 로그np.log2
: 요소별 밑이 2인 로그
- 통계 함수
np.mean
: 평균np.median
: 중앙값np.std
: 표준편차np.var
: 분산np.min
: 최솟값np.max
: 최댓값np.sum
: 합계np.prod
: 요소들의 곱np.cumsum
: 누적 합np.cumprod
: 누적 곱
- 비교 및 논리 연산
np.greater
,np.greater_equal
: 요소별 ‘>’, ‘>=’ 비교np.less
,np.less_equal
: 요소별 ‘<‘, ‘<=’ 비교np.equal
,np.not_equal
: 요소별 ‘==’, ‘!=’ 비교np.logical_and
: 요소별 논리 AND 연산np.logical_or
: 요소별 논리 OR 연산np.logical_not
: 요소별 논리 NOT 연산
- 삼각 함수
np.sin
: 사인 함수np.cos
: 코사인 함수np.tan
: 탄젠트 함수np.arcsin
,np.arccos
,np.arctan
: 아크 사인, 아크 코사인, 아크 탄젠트 함수np.sinh
,np.cosh
,np.tanh
: 쌍곡선 사인, 쌍곡선 코사인, 쌍곡선 탄젠트 함수
- 선형 대수 연산
np.dot
: 점곱(dot product)np.cross
: 벡터곱(cross product)np.linalg.inv
: 역행렬np.linalg.det
: 행렬식np.linalg.eig
: 고유값과 고유 벡터
축(Axis)의 이해
# 2차원 배열 생성
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
# 전체 요소의 합
print(np.sum(arr2d)) # axis를 지정하지 않으면 전체 배열에 대한 합을 계산
# 각 열의 합 (세로 방향)
print(np.sum(arr2d, axis=0))
# 각 행의 합 (가로 방향)
print(np.sum(arr2d, axis=1))
# 3차원 배열 생성
arr3d = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
# 각 2차원 배열의 합 (깊이 방향)
print(np.sum(arr3d, axis=0))
# 각 행의 합 (세로 방향)
print(np.sum(arr3d, axis=1))
# 각 열의 합 (가로 방향)
print(np.sum(arr3d, axis=2))
- 1차원 배열: 축이 하나만 존재합니다.
axis=0
이 전체 배열을 의미합니다. - 2차원 배열:
axis=0
은 행(세로 방향),axis=1
은 열(가로 방향)을 나타냅니다. - 3차원 배열:
axis=0
은 깊이,axis=1
은 행,axis=2
은 열을 의미합니다.
concatenate
concatenate
# 기본 사용법
numpy.concatenate((a1, a2, ...), axis=0)
# 1차원 배열
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
result = np.concatenate((arr1, arr2))
print(result)
# 출력: [1 2 3 4 5 6]
# 2차원 배열
arr3 = np.array([[1, 2], [3, 4]])
arr4 = np.array([[5, 6]])
result2 = np.concatenate((arr3, arr4), axis=0)
print(result2)
# 출력:
# [[1 2]
# [3 4]
# [5 6]]
- 주어진 축(axis)을 따라 배열들을 연결
- 가장 범용적이며, 어떤 축을 따라 배열을 결합할지 직접 지정할 수 있음
vstack
# 기본 사용법
numpy.vstack((a1, a2, ...))
# 1차원 배열
arr5 = np.array([1, 2, 3])
arr6 = np.array([4, 5, 6])
result3 = np.vstack((arr5, arr6))
print(result3)
# 출력:
# [[1 2 3]
# [4 5 6]]
# 2차원 배열
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])
result = np.vstack((arr1, arr2))
#[[1 2]
# [3 4]
# [5 6]
# [7 8]]
- 배열을 수직(행 방향)으로 쌓음
- 1차원 배열을 2차원 배열의 행으로 취급하여 쌓을 때 특히 유용
hstack
# 기본 사용법
numpy.hstack((a1, a2, ...))
# 1차원 배열
arr7 = np.array([1, 2, 3])
arr8 = np.array([4, 5, 6])
result4 = np.hstack((arr7, arr8))
print(result4)
# 출력: [1 2 3 4 5 6]
# 2차원 배열
arr9 = np.array([[1, 2], [3, 4]])
arr10 = np.array([[5, 6], [7, 8]])
result5 = np.hstack((arr9, arr10))
print(result5)
# 출력:
# [[1 2 5 6]
# [3 4 7 8]]
- 배열을 수평(열 방향)으로 쌓음
- 1차원 배열을 연결할 때나, 2차원 배열을 열 방향으로 결합할 때 사용
Array operations
# 예시 1: 스칼라와 배열의 연산
a = np.array([1, 2, 3])
b = 2
print("스칼라와 배열의 곱셈:\n", a * b)
# [2 4 6]
# 예시 2: 1차원 배열과 2차원 배열의 연산
a = np.array([1, 2, 3])
b = np.array([[1, 2, 3], [4, 5, 6]])
print("\n1차원 배열과 2차원 배열의 덧셈:\n", a + b)
# [[2 4 6]
# [5 7 9]]
# 예시 3: 차원이 다른 배열의 연산
a = np.array([[1], [2], [3]]) # 3x1 배열
b = np.array([1, 2, 3]) # 1x3 배열
print("\n차원이 다른 배열의 덧셈:\n", a + b)
# [[2 3 4]
# [3 4 5]
# [4 5 6]]
# 추가 예시: 2차원 배열 간의 브로드캐스팅
a = np.array([[1, 2], [3, 4]]) # 2x2 배열
b = np.array([[10], [20]]) # 2x1 배열
print("\n2차원 배열 간의 덧셈 (브로드캐스팅):\n", a + b)
# [[11 12]
# [23 24]]`
`# 배열 생성
a = np.array([1, 2, 3, 4])
b = np.array([10, 20, 30, 40])
# 요소별 덧셈
addition = a + b
print("요소별 덧셈:\n", addition) # 출력: [11 22 33 44]
# 요소별 뺄셈
subtraction = a - b
print("\n요소별 뺄셈:\n", subtraction) # 출력: [-9 -18 -27 -36]
# 요소별 곱셈
multiplication = a * b
print("\n요소별 곱셈:\n", multiplication) # 출력: [ 10 40 90 160]
# 요소별 나눗셈
division = b / a
print("\n요소별 나눗셈:\n", division) # 출력: [10. 10. 10. 10.]
# 요소별 비교 (a가 b보다 작은지)
comparison = a < b
print("\n요소별 비교 (a < b):\n", comparison) # 출력: [True True True True]
- element-wise operations
- NumPy 배열 간의 연산은 배열의 요소별(element-wise) 연산을 기반으로 함
- 동일한 위치에 있는 요소끼리 연산을 수행한다는 의미
- 두 배열이 동일한 모양(shape)을 가질 때 직접적으로 적용될 수 있음
- 내부적으로 최적화된 C 코드를 사용하여 배열의 요소별 연산을 매우 빠르게 수행
- broadcasting
- 서로 다른 모양(shape)을 가진 배열 간의 연산을 가능하게 해주는 강력한 메커니즘
- NumPy는 모양이 맞지 않는 배열들을 자동으로 ‘늘리거나'(broadcast) 적절한 모양으로 변환하여 연산을 수행
- 규칙
- 두 배열의 차원 수가 다를 경우, 더 작은 차원의 배열의 형상(shape) 앞(왼쪽)에 1을 추가하여 차원 수를 맞춥니다.
- 특정 차원에서 크기가 1인 배열은 그 차원에서 크기가 더 큰 배열의 크기와 일치하도록 늘어납니다. 각 차원에서 크기가 일치하거나 배열 중 하나의 크기가 1일 때만 두 배열은 호환됩니다.
Transpose
# 기본 사용법
# axes: 축의 순서를 지정하는 정수의 시퀀스
numpy.transpose(a, axes=None)
# 2차원 배열
a = np.array([[1, 2], [3, 4], [5, 6]])
# 원본 배열:
# [[1 2]
# [3 4]
# [5 6]]
np.transpose(a)
# 전치 배열:
# [[1 3 5]
# [2 4 6]]
# 더 높은 차원
a = np.arange(12).reshape(2, 3, 2)
# 원본 배열:
# [[[ 0 1]
# [ 2 3]
# [ 4 5]]
#
# [[ 6 7]
# [ 8 9]
# [10 11]]]
# 축을 (1, 0, 2)로 전치
np.transpose(a, (1, 0, 2))
# [[[ 0 1]
# [ 6 7]]
#
# [[ 2 3]
# [ 8 9]]
#
# [[ 4 5]
# [10 11]]]
- NumPy 배열의 축을 재배열하는 기능을 제공
- 전치 연산은 배열의 데이터를 복사하지 않고, 원본 배열의 뷰(view)를 반환합니다.
- 전치 후의 배열에서 요소를 수정하면 원본 배열에도 반영됩니다.
Comparisons
# 배열 생성
a = np.array([1, 2, 3, 4, 5])
b = np.array([5, 4, 3, 2, 1])
# 동등 비교
equal = a == b
equal # 출력: [False False True False False]
# 부등 비교
not_equal = a != b
not_equal # 출력: [ True True False True True]
# 크기 비교
greater = a > b
less_equal = a <= b
greater # 출력: [False False False True True]
less_equal # 출력: [ True True True False False]
# 브로드캐스팅을 활용한 비교
c = np.array([[1, 2, 3], [4, 5, 6]])
broadcast_equal = a == c
broadcast_equal
# 출력:
# [[ True True True]
# [False False False]]
# 비교 결과를 이용한 조건부 인덱싱
filtered = a[a > 3]
filtered # 출력: [4 5]
- 두 배열의 같은 위치에 있는 요소들을 비교하여 결과를 불리언 배열로 반환
==
,!=
,<
,<=
,>
,>=
등의 비교 연산자를 사용
All()
# 기본 사용법
numpy.all(a, axis=None, out=None, keepdims=np._NoValue)
# 모든 요소가 참인 경우
arr_true = np.array([True, True, True])
np.all(arr_true) # 출력: True
# 하나라도 거짓인 요소가 있는 경우
arr_false = np.array([True, False, True])
np.all(arr_false) # 출력: False
# 2차원 배열 예시
arr2d = np.array([[True, False], [True, True]])
np.all(arr2d, axis=0) # 출력: [ True False]
np.all(arr2d, axis=1 # 출력: [False True]
- 주어진 배열의 모든 요소가 참(True)인지를 검사
- 배열 내 모든 값이 조건을 만족하는지 확인할 때 자주 사용
- 선택적으로 축(axis) 매개변수를 통해 특정 축을 따라 연산을 수행할 수도 있음
Any()
# 기본 사용법
numpy.any(a, axis=None, out=None, keepdims=np._NoValue)
# 모든 요소가 거짓인 경우
arr_false = np.array([False, False, False])
np.any(arr_false) # 출력: False
# 적어도 하나의 참인 요소가 있는 경우
arr_mixed = np.array([False, True, False])
np.any(arr_mixed) # 출력: True
# 2차원 배열 예시
arr2d = np.array([[False, True], [False, False]])
np.any(arr2d, axis=0) # 출력: [False True]
np.any(arr2d, axis=1) # 출력: [ True False]
- 주어진 배열 내에서 적어도 하나의 요소가 참(True)인지 검사
- 선택적으로 축(axis) 매개변수를 통해 특정 축을 따라 연산을 수행할 수 있음
Where()
# 기본 사용법
indices = numpy.where(condition)
# 조건에 따라 배열 선택
# 조건이 참일 경우 x, 거짓을 경우 y
result = numpy.where(condition, x, y)
# 조건에 따른 인덱스 찾기
a = np.array([1, 2, 3, 4, 5])
np.where(a > 3) # 출력: (array([3, 4]),)
# 조건에 따라 배열 선택하기
b = np.array([1, 2, 3, 4, 5])
c = np.array([10, 20, 30, 40, 50])
result = np.where(b > 3, b, c) # 출력: [10 20 30 4 5]
- 조건에 따라 배열에서 요소를 선택하는 데 사용
- 아무것도 작성하지 않으면 index 값 반환
isnan
# 기본 사용법
numpy.isnan(x)
# NaN 값을 포함하는 배열 생성
arr = np.array([1, np.nan, 3, 4, np.nan])
# 각 요소가 NaN인지 검사
isnan_arr = np.isnan(arr)
isnan_arr # 출력: [False True False False True]
# NaN 값을 0으로 대체
arr[np.isnan(arr)] = 0
arr # 출력: [1. 0. 3. 4. 0.]
- 배열의 각 요소가 ‘Not a Number’ (NaN)인지 여부를 검사
- 입력 배열과 동일한 모양의 불리언 배열을 생성
argmax
# 기본 사용법
numpy.argmax(a, axis=None)
arr = np.array([1, 3, 2, 7, 4])
max_index = np.argmax(arr)
max_index # 출력: 3
arr2d = np.array([[1, 2, 3], [4, 6, 5]])
# 각 열에서 최대값의 인덱스 찾기
max_index_col = np.argmax(arr2d, axis=0)
max_index_col # 출력: [1 1 1]
# 각 행에서 최대값의 인덱스 찾기
max_index_row = np.argmax(arr2d, axis=1)
max_index_row # 출력: [2 1]
- NumPy 배열에서 최대값을 가지는 요소의 인덱스를 반환
- 배열 전체, 또는 지정된 축(axis)을 따라 최대값의 위치를 찾는 데 사용
- 다차원 배열에서 축을 지정하면, 해당 축을 따라 각 부분 배열에서 최대값을 가진 요소의 인덱스를 찾을 수 있음
argmin
# 기본 사용법
numpy.argmin(a, axis=None)
# 1차원 배열에서 최소값의 인덱스 찾기
arr = np.array([4, 2, 3, 1, 5])
min_index = np.argmin(arr)
min_index # 출력: 3
arr2d = np.array([[2, 4, 1], [3, 0, 5]])
# 각 열에서 최소값의 인덱스 찾기
min_index_col = np.argmin(arr2d, axis=0)
min_index_col # 출력: [0 1 0]
# 각 행에서 최소값의 인덱스 찾기
min_index_row = np.argmin(arr2d, axis=1)
min_index_row # 출력: [2 1]
- NumPy 배열에서 최소값을 가지는 요소의 인덱스를 반환
- 배열 전체 또는 지정된 축(axis)을 따라 최소값을 가진 요소의 위치를 찾는 데 사용
Boolean index
# 1차원 배열 생성
data_1d = np.array([1, 2, 3, 4, 5])
# 조건: 배열에서 값이 3보다 큰 요소
data_1d[data_1d > 3]
# 출력: [4 5]
# 2차원 배열 생성
data_2d = np.array([[1, 2], [3, 4], [5, 6]])
# 조건: 'data_2d' 배열에서 값이 4보다 큰 요소
data_2d[data_2d > 4]
# 출력: [5 6]
# 조건: 값이 2보다 크고 5보다 작은 요소
data_1d[(data_1d > 2) & (data_1d < 5)]
# 출력: [3 4]
- 배열에서 조건을 만족하는 요소를 선택하는 강력한 방법
- 불리언 인덱싱을 사용할 때는 조건을 만족하는지 여부에 따라
True
또는False
값을 가진 불리언 배열을 인덱스로 사용 - 주어진 조건에 따라 배열에서 값을 필터링하고자 할 때 유용
- 다차원 배열에서도 불리언 인덱싱을 사용할 수 있습니다. 이 경우, 일반적으로 한 축(axis)에 대해 조건을 적용하고 해당 조건을 만족하는 요소를 선택합니다.
- 불리언 인덱싱은 원본 배열에 대한 뷰가 아닌 복사본을 생성합니다. 따라서 불리언 인덱스를 통해 선택된 배열을 수정해도 원본 배열은 변경되지 않습니다.
Fancy index
# 정수 배열 인덱싱
arr_1d = np.array([10, 20, 30, 40, 50])
indices = np.array([3, 0, 2])
arr_1d[indices] # 출력: [40 10 30]
# 2차원 배열에서의 팬시 인덱싱
arr_2d = np.array([[1, 2], [3, 4], [5, 6]])
row_indices = np.array([0, 2])
col_indices = np.array([1, 0])
arr_2d[row_indices, col_indices] # 출력: [2 5]
# 불리언 배열 인덱싱
bool_indices = np.array([True, False, True, False, True])
arr_1d[bool_indices] # 출력: [10 30 50]
- NumPy에서 배열의 특정 위치에 접근하거나 배열의 일부를 선택할 때 사용하는 방법
- 인덱스 배열을 전달하여 여러 위치의 데이터를 동시에 조회하거나 변경할 수 있음
- 특징
- 여러 인덱스를 동시에 지정하여 배열의 특정 요소에 접근할 수 있음
- 결과는 인덱스 배열의 형태를 따르며, 원본 배열과 다를 수 있음
- 팬시 인덱싱을 사용하여 배열의 일부를 선택하면 항상 원본 데이터의 복사본이 생성됌
- 정수 배열 인덱싱과 불리언 배열 인덱싱 두 가지 방식이 있습니다.
- numpy array를 index value로 사용해서 값을 추출하는 방법
- 표현 방식
- a[b]
- a.take(b)
Numpy data i/o
loadtxt()
# 기본 사용법
# fname: 읽을 파일의 이름이나 파일 객체입니다.
# dtype: 반환되는 배열의 데이터 타입입니다. 기본값은 float입니다.
# delimiter: 각 데이터를 구분하는 문자입니다. 기본값은 공백입니다. CSV 파일의 경우 ,를 delimiter로 지정합니다.
# skiprows: 파일의 시작부터 무시할 행의 수입니다. 주로 파일의 헤더를 건너뛸 때 사용됩니다.
# usecols: 읽을 열의 번호나 이름을 지정하는 튜플입니다. 이 매개변수를 사용하면, 필요한 열만 선택적으로 로드할 수 있습니다.
# unpack: True일 경우, 반환된 배열을 전치(transpose)합니다. 이는 열 단위로 변수에 데이터를 할당하고자 할 때 유용합니다.
# ndmin: 반환될 배열의 최소 차원 수입니다.
# encoding: 파일을 읽을 때 사용할 인코딩입니다.
# max_rows: 읽을 최대 행 수입니다.
numpy.loadtxt(fname, dtype=float, delimiter=None, skiprows=0, usecols=None, unpack=False, ndmin=0, encoding='bytes', max_rows=None)
# 가정: 'data.csv' 파일에는 3열의 데이터가 콤마로 구분되어 있음
# 예: 1,2,3
# 4,5,6
# 7,8,9
data = np.loadtxt('data.csv', delimiter=',')
# 첫 번째와 세 번째 열만 로드
data = np.loadtxt('data.csv', delimiter=',', usecols=(0, 2))
- 텍스트 파일로부터 데이터를 불러와 NumPy 배열로 변환하는 데 사용
- 주로 CSV(Comma-Separated Values) 파일이나 탭, 공백 등으로 구분된 데이터를 로드할 때 유용하게 사용
savetxt()
# fname: 출력 파일 이름이나 파일 객체입니다.
# X: 저장할 데이터를 포함한 배열입니다.
# fmt: 파일에 쓰여질 숫자의 포맷을 지정하는 문자열 또는 문자열의 시퀀스입니다. 예를 들어, '%.2f'는 소수점 아래 두 자리까지의 부동소수점 형태로 숫자를 포맷합니다.
delimiter: 열 간 구분자입니다. CSV 파일을 만들기 위해서는 콤마(',')를 지정할 수 있습니다.
# newline: 개행 문자를 지정합니다.
# header, footer: 파일의 시작과 끝에 추가할 텍스트입니다. comments 인자로 지정된 문자로 시작됩니다.
# comments: 주석을 위한 접두사로, header와 footer에 사용됩니다.
# encoding: 파일을 저장할 때 사용할 인코딩입니다.
# 기본 사용법
numpy.savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='', footer='', comments='# ', encoding=None)
# 예제 데이터 생성
data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# CSV 파일로 저장
np.savetxt('example.csv', data, fmt='%d', delimiter=',')
# 헤더와 함께 CSV 파일로 저장
np.savetxt('example_with_header.csv', data, fmt='%d', delimiter=',', header='Column1,Column2,Column3', comments='')
- NumPy 배열을 텍스트 파일로 저장하는 데 사용
- 주로 배열 데이터를 CSV(Comma-Separated Values) 파일이나 탭, 공백 등으로 구분된 텍스트 파일 형태로 저장할 때 유용하게 사용
pickle
# NumPy 배열 생성
arr = np.array([1, 2, 3, 4, 5])
# 배열을 .npy 파일로 저장
np.save('array.npy', arr)
# .npy 파일로부터 배열 로드
loaded_arr = np.load('array.npy')
- NumPy는 자체적으로 객체를 바이너리 형식으로 저장하고 로드할 수 있는 메커니즘을 제공합니다. 이때 내부적으로 Python의 pickle 프로토콜이 사용됩니다. 따라서 NumPy 배열을 파일에 저장하거나 파일로부터 배열을 로드할 때, 실제로는 pickle을 사용하는 것입니다.
- Python 객체를 바이트 스트림으로 직렬화(serialize)하고, 이를 다시 객체로 역직렬화(deserialize)하는 과정을 가능하게 하는 Python의 표준 라이브러리
- 직렬화란 메모리에 있는 객체의 상태를 그대로 파일에 저장하거나 네트워크를 통해 전송할 수 있는 형태로 변환하는 과정을 의미하며, 역직렬화는 그 반대 과정을 말함