Numpy 라이브러리 기초

강의

https://cs231n.github.io/python-numpy-tutorial

Numpy란?

  1. Numerical Python의 줄임말
  2. 파이썬의 고성능 과학 계산용 패키지
  3. Matrix와 Vector와 같은 Array 연산의 사실상의 표준

Numpy 특징

  1. 다차원 배열 객체: NumPy의 핵심 기능 중 하나는 ndarray라 불리는 다차원 배열을 제공하는 것입니다.
  2. 브로드캐스팅 기능: 서로 다른 크기의 배열 간에도 산술 연산이 가능하게 해줍니다.
  3. 효율적인 수학 함수: 고성능의 다양한 수학적 연산을 수행할 수 있는 함수를 제공합니다. 이 함수들은 배열의 각 요소별 연산을 지원하며, 수학, 통계, 선형대수 등의 분야에 활용될 수 있습니다.
  4. 배열 인덱싱: 데이터의 일부를 선택하거나 조작할 때 유용한 다양한 인덱싱 방법을 제공합니다. 슬라이싱, 마스킹, 정수 인덱싱 등을 포함합니다.
  5. 메모리 효율성: NumPy 배열은 기본 Python 리스트에 비해 더 적은 메모리를 사용하며, 배열 간의 연산 속도도 훨씬 빠릅니다.
  6. C/C++ 및 Fortran 코드 통합: NumPy는 C나 C++, Fortran 등 다른 언어로 작성된 코드와 통합할 수 있는 기능을 제공합니다.
  7. 파일 입출력: 데이터를 파일에 저장하고 불러오는 기능을 제공합니다. NumPy 자체의 바이너리 형식 뿐만 아니라, 텍스트 파일이나 다른 파일 형식을 지원합니다.

Numpy 호출 방법

# numpy 설치하기
pip install numpy

# numpy 호출하기
# np는 넘파이를 사용할 때 일반적으로 사용되는 관례적인 약칭
import numpy as np

ndarray

ndarray란?

  1. NumPy에서 제공하는 N-dimensional array의 약자
  2. 파이썬에서 고성능의 다차원 배열을 구현한 것
  3. 모든 원소가 동일한 데이터 타입
  4. 고정된 크기의 다차원 그리드 형태로 데이터를 저장
  5. 과학 계산을 위한 다양한 연산과 함께 빠른 배열 처리를 가능하게 하는 기능을 제공

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)
  1. 주어진 범위 내에서 일정한 간격의 값을 갖는 배열을 생성
  2. 반복문에서 사용할 인덱스 배열을 생성하거나, 기본적인 순차적 데이터를 빠르게 생성할 때 유용.
  3. 또한, 시각화에서 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. 모든 요소가 1인 NumPy 배열을 생성
  2. 특정 모양(shape)과 데이터 타입(dtype)을 가진 배열을 초기화할 때 유용
  3. 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)
  1. 모든 요소가 0인 NumPy 배열을 생성하는 데 사용
  2. 특정 모양(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)
  1. ndarray의 데이터 타입을 설명하는 객체
  2. NumPy에서는 배열 내의 모든 요소가 동일한 타입을 가져야 하며, dtype은 해당 타입을 명시적으로 정의
  3. 정수형
    • int8, int16, int32, int64: 각각 8, 16, 32, 64비트 크기의 정수를 나타냅니다. 부호가 있는 정수형입니다.
    • uint8, uint16, uint32, uint64: 각각 8, 16, 32, 64비트 크기의 부호 없는 정수(양의 정수)를 나타냅니다.
  4. 부동소수점
    • float16, float32, float64: 각각 16, 32, 64비트 크기의 부동소수점 수를 나타냅니다. 이들은 실수를 표현합니다.
    • float128: 일부 시스템에서는 128비트 부동소수점 수를 지원합니다.
  5. 복소수형
    • complex64, complex128: 각각 64, 128비트 크기의 복소수를 나타냅니다. 이들은 실수부와 허수부를 갖는 수입니다.
    • complex256: 일부 시스템에서는 256비트 복소수를 지원합니다.
  6. 기타 타입
    • 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
  1. 배열의 구조를 나타냄
  2. 각 차원(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
  1. 배열의 차원 수
  2. 배열이 가진 차원의 개수를 정수로 반환

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
  1. NumPy 배열에 포함된 전체 요소의 개수
  2. 즉, 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)
  1. NumPy 배열이 메모리에서 차지하는 총 바이트 수
  2. 배열의 dtypesize에 따라 결정됩니다.

reshape()

# 1차원 배열 생성
arr = np.arange(6)

# 1차원 배열을 2x3 2차원 배열로 재구성
reshaped_arr = arr.reshape((2, 3))

# 자동으로 크기를 계산하여 재구성
auto_reshaped_arr = arr.reshape((-1, 3))
  1. NumPy 배열의 형태를 변경하는 데 사용
  2. 배열의 총 요소 수를 유지하면서, 지정된 새로운 형태로 배열의 차원과 크기를 재구성
  3. 배열의 데이터 자체를 변경하지 않고, 배열의 뷰(view)를 변경하여 새로운 형태를 제공
  4. 데이터를 다른 형태로 효율적으로 재해석하고자 할 때 유용
  5. 한 차원을 1로 지정하면, 해당 차원의 크기가 자동으로 계산

flatten

# 2차원 배열 생성
arr2d = np.array([[1, 2, 3], [4, 5, 6]])

# 2차원 배열을 1차원 배열로 평탄화
# 결과 [1, 2, 3, 4, 5, 6]
flattened_arr = arr2d.flatten()
  1. NumPy 배열을 1차원 배열로 변환하는 데 사용
  2. 배열의 복사본을 생성하여 반환하기 때문에, 원본 배열은 변경되지 않음

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)
  1. NumPy 배열의 데이터 타입을 변환하는 데 사용
  2. 타입이 변환된 배열의 새로운 복사본을 생성하여 반환. 원본 배열은 변경되지 않음
  3. 불필요하게 큰 데이터 타입을 더 작은 타입으로 변환함으로써 메모리 사용량을 최적화할 수 있음
  4. 특정 연산이나 알고리즘 요구사항에 맞추어 데이터 타입을 조정할 수 있음

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])
  1. 단일 요소 접근: array[i]
  2. 다차원 배열: 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]
  1. 배열의 부분집합을 선택하는 방법
  2. 원본 배열의 연속적인 요소들을 선택하여 새로운 배열(view)을 생성할 수 있음
    • 슬라이싱은 원본 배열에 대한 뷰를 반환하기 때문에, 슬라이싱을 통해 생성된 배열을 수정하면 원본 배열도 함께 수정됌
    • 원본 데이터를 보존하고 싶다면, 슬라이싱 결과를 .copy() 메서드를 사용하여 복사
  3. 시작 인덱스는 포함되고 종료 인덱스는 포함되지 않음
  4. 간격은 선택적으로 지정할 수 있음
  5. 다차원 배열에서 슬라이싱을 사용할 때는 각 차원별로 슬라이싱을 지정할 수 있음
    • 콤마(,)를 사용하여 각 차원의 슬라이스를 구분

계산 함수

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)
  1. 배열의 요소들을 합하는 연산을 수행
  2. 지정된 축(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)
  1. 주어진 배열의 요소들의 산술 평균(average)을 계산
  2. 특정 축(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)
  1. 주어진 배열의 요소들에 대한 표준편차(standard deviation)를 계산
  2. 표준편차는 데이터의 분산을 측정하는 값으로, 데이터가 평균으로부터 얼마나 퍼져 있는지를 나타냄
  3. 전체 배열 또는 지정된 축을 따라서 표준편차를 계산할 수 있으며, 다차원 배열에서도 사용할 수 있음

그 외 수학 연산자

  1. 기본 수학 연산
    • np.add: 요소별 덧셈
    • np.subtract: 요소별 뺄셈
    • np.multiply: 요소별 곱셈
    • np.divide: 요소별 나눗셈
    • np.sqrt: 요소별 제곱근
    • np.square: 요소별 제곱
    • np.power: 요소별 거듭제곱
    • np.exp: 요소별 지수 함수
    • np.log: 요소별 자연 로그
    • np.log10: 요소별 상용 로그
    • np.log2: 요소별 밑이 2인 로그
  2. 통계 함수
    • np.mean: 평균
    • np.median: 중앙값
    • np.std: 표준편차
    • np.var: 분산
    • np.min: 최솟값
    • np.max: 최댓값
    • np.sum: 합계
    • np.prod: 요소들의 곱
    • np.cumsum: 누적 합
    • np.cumprod: 누적 곱
  3. 비교 및 논리 연산
    • 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 연산
  4. 삼각 함수
    • np.sin: 사인 함수
    • np.cos: 코사인 함수
    • np.tan: 탄젠트 함수
    • np.arcsin, np.arccos, np.arctan: 아크 사인, 아크 코사인, 아크 탄젠트 함수
    • np.sinh, np.cosh, np.tanh: 쌍곡선 사인, 쌍곡선 코사인, 쌍곡선 탄젠트 함수
  5. 선형 대수 연산
    • 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]]
  1. 주어진 축(axis)을 따라 배열들을 연결
  2. 가장 범용적이며, 어떤 축을 따라 배열을 결합할지 직접 지정할 수 있음

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. 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. 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]
  1. element-wise operations
    • NumPy 배열 간의 연산은 배열의 요소별(element-wise) 연산을 기반으로 함
    • 동일한 위치에 있는 요소끼리 연산을 수행한다는 의미
    • 두 배열이 동일한 모양(shape)을 가질 때 직접적으로 적용될 수 있음
    • 내부적으로 최적화된 C 코드를 사용하여 배열의 요소별 연산을 매우 빠르게 수행
  2. 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]]]
  1. NumPy 배열의 축을 재배열하는 기능을 제공
  2. 전치 연산은 배열의 데이터를 복사하지 않고, 원본 배열의 뷰(view)를 반환합니다.
  3. 전치 후의 배열에서 요소를 수정하면 원본 배열에도 반영됩니다.

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]
  1. 두 배열의 같은 위치에 있는 요소들을 비교하여 결과를 불리언 배열로 반환
  2. ==, !=, <, <=, >, >= 등의 비교 연산자를 사용

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]
  1. 주어진 배열의 모든 요소가 참(True)인지를 검사
  2. 배열 내 모든 값이 조건을 만족하는지 확인할 때 자주 사용
  3. 선택적으로 축(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]
  1. 주어진 배열 내에서 적어도 하나의 요소가 참(True)인지 검사
  2. 선택적으로 축(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]
  1. 조건에 따라 배열에서 요소를 선택하는 데 사용
  2. 아무것도 작성하지 않으면 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.]
  1. 배열의 각 요소가 ‘Not a Number’ (NaN)인지 여부를 검사
  2. 입력 배열과 동일한 모양의 불리언 배열을 생성

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]
  1. NumPy 배열에서 최대값을 가지는 요소의 인덱스를 반환
  2. 배열 전체, 또는 지정된 축(axis)을 따라 최대값의 위치를 찾는 데 사용
  3. 다차원 배열에서 축을 지정하면, 해당 축을 따라 각 부분 배열에서 최대값을 가진 요소의 인덱스를 찾을 수 있음

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]
  1. NumPy 배열에서 최소값을 가지는 요소의 인덱스를 반환
  2. 배열 전체 또는 지정된 축(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]
  1. 배열에서 조건을 만족하는 요소를 선택하는 강력한 방법
  2. 불리언 인덱싱을 사용할 때는 조건을 만족하는지 여부에 따라 True 또는 False 값을 가진 불리언 배열을 인덱스로 사용
  3. 주어진 조건에 따라 배열에서 값을 필터링하고자 할 때 유용
  4. 다차원 배열에서도 불리언 인덱싱을 사용할 수 있습니다. 이 경우, 일반적으로 한 축(axis)에 대해 조건을 적용하고 해당 조건을 만족하는 요소를 선택합니다.
  5. 불리언 인덱싱은 원본 배열에 대한 뷰가 아닌 복사본을 생성합니다. 따라서 불리언 인덱스를 통해 선택된 배열을 수정해도 원본 배열은 변경되지 않습니다.

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))
  1. 텍스트 파일로부터 데이터를 불러와 NumPy 배열로 변환하는 데 사용
  2. 주로 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='')
  1. NumPy 배열을 텍스트 파일로 저장하는 데 사용
  2. 주로 배열 데이터를 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')
  1. NumPy는 자체적으로 객체를 바이너리 형식으로 저장하고 로드할 수 있는 메커니즘을 제공합니다. 이때 내부적으로 Python의 pickle 프로토콜이 사용됩니다. 따라서 NumPy 배열을 파일에 저장하거나 파일로부터 배열을 로드할 때, 실제로는 pickle을 사용하는 것입니다.
  2. Python 객체를 바이트 스트림으로 직렬화(serialize)하고, 이를 다시 객체로 역직렬화(deserialize)하는 과정을 가능하게 하는 Python의 표준 라이브러리
  3. 직렬화란 메모리에 있는 객체의 상태를 그대로 파일에 저장하거나 네트워크를 통해 전송할 수 있는 형태로 변환하는 과정을 의미하며, 역직렬화는 그 반대 과정을 말함

Leave a Comment