NumPy 기초: 배열 생성부터 파일 입출력까지

NumPy 소개

NumPy는 Python에서 과학 계산을 위한 핵심 라이브러리로, 동일한 데이터 타입의 요소들로 구성된 다차원 배열(ndarray)을 효율적으로 처리할 수 있게 해줍니다. 배열 내 모든 요소는 동일한 크기의 메모리 블록을 차지하며, 벡터 및 행렬 연산, 선형 대수, 푸리에 변환, 난수 생성 등 다양한 수치 연산 기능을 제공합니다.

배열 생성 방법

numpy.array() — 기본 배열 생성

가장 일반적인 배열 생성 함수입니다. 리스트, 튜플, 반복 가능한 객체 등을 입력으로 받아 ndarray를 반환합니다.

import numpy as np

# 리스트 및 튜플로부터 생성
arr1 = np.array([0, 1, 2, 3])
arr2 = np.array((4, 5, 6))

# 자료형 명시 (dtype)
arr_float = np.array([1.1, 2.9], dtype='int32')  # 정수로 변환됨
arr_str = np.array(['a', 'b'], dtype='U10')     # 유니코드 문자열

특수 배열 생성 함수

  • np.zeros(shape): 주어진 형태의 0으로 채워진 배열 생성
  • np.ones(shape): 주어진 형태의 1로 채워진 배열 생성
  • np.arange(start, stop, step): 일정 간격의 숫자 배열 생성 (stop 미포함)
  • np.linspace(start, stop, num): 시작과 끝 사이를 균등하게 나눈 num개의 값 생성 (기본 포함)
  • np.logspace(start, stop, num, base=10): 로그 스케일 상에서 균등한 간격의 배열 생성
# 예시
zeros_2d = np.zeros((2, 3))
linear_seq = np.linspace(0, 1, 5)        # [0.0, 0.25, 0.5, 0.75, 1.0]
log_seq = np.logspace(0, 2, 3, base=2)  # [1.0, 2.0, 4.0]

난수 배열 생성

np.random 모듈을 통해 다양한 분포의 난수 생성 가능:

# [0, 1) 구간 균일분포
uniform = np.random.rand(2, 3)

# 표준정규분포 (평균 0, 표준편차 1)
normal = np.random.randn(2, 3)

# 지정된 범위의 정수 난수
integers = np.random.randint(10, 20, size=(2, 3))

# 시드 고정 (재현성 보장)
np.random.seed(123)

배열 속성 확인

생성된 배열의 구조와 정보는 다음 속성들을 통해 확인할 수 있습니다:

  • ndim: 차원 수 (랭크)
  • shape: 각 차원의 크기를 담은 튜플
  • size: 전체 요소 개수
  • dtype: 요소의 데이터 타입
  • itemsize: 각 요소의 바이트 크기
  • nbytes: 전체 배열이 차지하는 바이트 수 (size × itemsize)
arr = np.ones((3, 4), dtype=np.float64)
print(arr.shape)   # (3, 4)
print(arr.dtype)   # float64
print(arr.nbytes)  # 96 (3*4*8)

배열 형태 변경

reshape()

요소 수를 유지한 채 배열의 형상을 재구성합니다. -1을 사용하면 해당 차원을 자동 추론합니다.

arr = np.arange(6)
reshaped = arr.reshape(2, 3)       # 2x3 배열
flattened = arr.reshape(-1)        # 1차원으로 펼침

resize()

원본 배열의 크기를 직접 변경하거나, 새 배열을 만들어 크기를 조정합니다. 원래 크기보다 클 경우 반복해서 채우고, 작을 경우 잘라냅니다.

arr = np.array([1, 2, 3])
resized = np.resize(arr, (5,))     # [1, 2, 3, 1, 2]
arr.resize((5,))                   # 원본 배열 수정

flatten() vs ravel()

둘 다 다차원 배열을 1차원으로 만듭니다.

  • flatten(): 항상 새로운 배열(사본)을 반환
  • ravel(): 가능하면 원본 배열의 뷰(view)를 반환하여 메모리 효율적
arr_2d = np.array([[1, 2], [3, 4]])
flat_copy = arr_2d.flatten()
view_like = arr_2d.ravel()

전치 (transpose / T)

행과 열을 교환하거나 고차원 배열의 축 순서를 변경합니다.

matrix = np.array([[1, 2], [3, 4]])
transposed = matrix.T              # 또는 np.transpose(matrix)

인덱싱과 슬라이싱

기본 인덱싱

단일 요소 접근은 정수 인덱스로 가능하며, 음수 인덱스는 뒤에서부터 참조합니다.

arr = np.array([10, 20, 30, 40])
print(arr[2])      # 30
print(arr[-1])     # 40

슬라이싱

부분 배열 추출. [start:stop:step] 형식 사용.

arr = np.arange(10)
print(arr[2:7:2])   # [2, 4, 6]
print(arr[::-1])    # 역순 [9, 8, ..., 0]

고급 인덱싱

  • 정수 배열 인덱싱: 특정 위치의 요소들을 선택 (사본 반환)
  • 불리언 인덱싱: 조건에 맞는 요소만 필터링 (사본 반환)
data = np.array([10, 15, 20, 25, 30])

# 정수 인덱싱
selected = data[[0, 2, 4]]         # [10, 20, 30]

# 불리언 인덱싱
filtered = data[data > 20]         # [25, 30]

수학 및 통계 연산

기본 산술 연산

배열 간 요소별(element-wise) 연산 지원:

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

addition = a + b           # [5, 7, 9]
multiplication = a * b     # [4, 10, 18]
power = a ** 2             # [1, 4, 9]

행렬 연산

  • np.dot(): 벡터 내적 또는 행렬 곱셈
  • @ 연산자 또는 np.matmul(): 배치 행렬 곱셈에 적합
  • np.linalg.inv(): 역행렬 계산
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

matmul_result = A @ B                    # 행렬 곱
A_inv = np.linalg.inv(A)                 # 역행렬

브로드캐스팅 (Broadcasting)

형상이 다른 배열 간 연산 시, 작은 배열이 자동으로 확장되어 연산됩니다. 메모리 복사 없이 효율적입니다.

matrix = np.array([[1, 2], [3, 4]])     # (2, 2)
vector = np.array([10, 20])               # (2,)
result = matrix + vector                # [[11, 22], [13, 24]]

통계 함수

배열 전체 또는 특정 축을 따라 통계값 계산 가능:

  • sum(), mean(), std(), var(): 합, 평균, 표준편차, 분산
  • min(), max(): 최솟값, 최댓값
  • median(): 중앙값 (배열 메서드 아님)
values = np.array([[1, 2], [3, 4]])

total_sum = values.sum()                  # 10
column_mean = values.mean(axis=0)         # [2.0, 3.0]
std_dev = values.std(ddof=1)              # 표본 표준편차

배열 수정 및 검색

  • np.append(): 배열 끝에 요소 추가 (새 배열 반환)
  • np.insert(): 지정 위치에 요소 삽입
  • np.delete(): 특정 인덱스 제거
  • np.argwhere(): 조건을 만족하는 요소의 인덱스 반환
arr = np.array([1, 2, 3])
appended = np.append(arr, 4)               # [1, 2, 3, 4]
indices = np.argwhere(arr > 1)             # [[1], [2]]

기타 유용한 기능

중복 제거 및 정렬

  • np.unique(): 중복 제거 후 정렬된 배열 반환
  • np.sort(): 정렬된 사본 반환
  • arr.sort(): 원본 배열을 제자리에서 정렬
data = np.array([3, 1, 2, 2, 3])
unique_vals = np.unique(data)            # [1, 2, 3]
sorted_vals = np.sort(data)              # [1, 2, 2, 3, 3]

데이터 타입 변환

astype() 메서드로 안전하게 타입 변환 가능:

float_arr = np.array([1.5, 2.7])
int_arr = float_arr.astype('int32')      # [1, 2] (절삭)
bool_arr = np.array([True, False]).astype('int8')  # [1, 0]

파일 입출력

텍스트 파일 읽기

np.loadtxt()는 CSV나 공백으로 구분된 텍스트 파일을 배열로 로드합니다.

# 예: data.csv
# 1,2,3
# 4,5,6

loaded = np.loadtxt('data.csv', delimiter=',', dtype='int32')

태그: NumPy python 배열연산 과학계산 데이터처리

6월 14일 19:27에 게시됨