Saltar al contenido principal

Fundamentos de NumPy 📊

NumPy(Numerical Python)는 파이썬에서 과학 계산을 위한 핵심 라이브러리입니다. 강력한 다차원 배열 객체와 빠른 연산 기능을 제공합니다.

¿Qué es NumPy?

NumPy는 대규모 다차원 배열과 행렬 연산을 지원하며, 수학 함수 라이브러리를 포함합니다.

Características Principales

  • 빠른 성능: C로 구현되어 순수 Python보다 10~100배 빠름
  • 메모리 효율: 연속된 메모리 블록 사용
  • 브로드캐스팅: 다른 크기의 배열 간 연산 가능
  • 벡터화: 반복문 없이 배열 전체 연산

Instalación

pip install numpy
import numpy as np

# 버전 확인
print(np.__version__) # 1.24.3

Crear ndarray

Métodos de Creación Básicos

import numpy as np

# 리스트에서 생성
arr1 = np.array([1, 2, 3, 4, 5])
print(arr1) # [1 2 3 4 5]
print(type(arr1)) # <class 'numpy.ndarray'>

# Arrays 2D
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr2)
# [[1 2 3]
# [4 5 6]]

# 3차원 배열
arr3 = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
print(arr3.shape) # (2, 2, 2)

Crear Arrays Especiales

# 0으로 채워진 배열
zeros = np.zeros((3, 4))
print(zeros)
# [[0. 0. 0. 0.]
# [0. 0. 0. 0.]
# [0. 0. 0. 0.]]

# 1로 채워진 배열
ones = np.ones((2, 3))
print(ones)
# [[1. 1. 1.]
# [1. 1. 1.]]

# 특정 값으로 채우기
full = np.full((2, 2), 7)
print(full)
# [[7 7]
# [7 7]]

# 단위 행렬
identity = np.eye(3)
print(identity)
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]

# 범위 배열
range_arr = np.arange(0, 10, 2)
print(range_arr) # [0 2 4 6 8]

# 균등 간격 배열
linspace = np.linspace(0, 1, 5)
print(linspace) # [0. 0.25 0.5 0.75 1. ]

# 랜덤 배열
random_arr = np.random.rand(3, 3) # 0~1 사이 균등 분포
print(random_arr)

random_int = np.random.randint(1, 100, size=(3, 3)) # 정수 랜덤
print(random_int)

Propiedades del Array

arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])

print(arr.shape) # (2, 4) - 배열의 형태
print(arr.ndim) # 2 - 차원 수
print(arr.size) # 8 - 전체 요소 개수
print(arr.dtype) # int64 - 데이터 타입
print(arr.itemsize) # 8 - 각 요소의 바이트 크기

Indexación y Slicing

Arrays 1D

arr = np.array([10, 20, 30, 40, 50])

print(arr[0]) # 10 - 첫 번째 요소
print(arr[-1]) # 50 - 마지막 요소
print(arr[1:4]) # [20 30 40] - 슬라이싱
print(arr[::2]) # [10 30 50] - 2칸씩 건너뛰기
print(arr[::-1]) # [50 40 30 20 10] - 역순

Arrays 2D

arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

print(arr[0, 0]) # 1 - 첫 번째 행, 첫 번째 열
print(arr[1, 2]) # 6 - 두 번째 행, 세 번째 열
print(arr[0]) # [1 2 3] - 첫 번째 행 전체
print(arr[:, 1]) # [2 5 8] - 두 번째 열 전체
print(arr[0:2, 1:3]) # [[2 3] [5 6]] - 부분 배열

Indexación Condicional

arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

# 조건을 만족하는 요소만 선택
print(arr[arr > 5]) # [6 7 8 9 10]
print(arr[arr % 2 == 0]) # [2 4 6 8 10]

# 여러 조건
print(arr[(arr > 3) & (arr < 8)]) # [4 5 6 7]

Operaciones de Arrays

Operaciones Aritméticas Básicas

arr1 = np.array([1, 2, 3, 4])
arr2 = np.array([10, 20, 30, 40])

print(arr1 + arr2) # [11 22 33 44]
print(arr1 - arr2) # [-9 -18 -27 -36]
print(arr1 * arr2) # [10 40 90 160]
print(arr1 / arr2) # [0.1 0.1 0.1 0.1]
print(arr1 ** 2) # [1 4 9 16]

# 스칼라 연산
print(arr1 + 10) # [11 12 13 14]
print(arr1 * 2) # [2 4 6 8]

Funciones Matemáticas

arr = np.array([1, 4, 9, 16])

print(np.sqrt(arr)) # [1. 2. 3. 4.]
print(np.exp(arr)) # 지수 함수
print(np.log(arr)) # 자연 로그
print(np.sin(arr)) # 삼각 함수

# 최대/최소
arr = np.array([3, 1, 4, 1, 5, 9, 2, 6])
print(np.max(arr)) # 9
print(np.min(arr)) # 1
print(np.argmax(arr)) # 5 - 최댓값의 인덱스
print(np.argmin(arr)) # 1 - 최솟값의 인덱스

Broadcasting

다른 크기의 배열 간 연산을 자동으로 처리합니다.

# Arrays 1D + 스칼라
arr = np.array([1, 2, 3])
print(arr + 5) # [6 7 8]

# Arrays 2D + 1차원 배열
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
arr1d = np.array([10, 20, 30])
print(arr2d + arr1d)
# [[11 22 33]
# [14 25 36]]

# Arrays 2D + 열 벡터
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
col_vec = np.array([[10], [20]])
print(arr2d + col_vec)
# [[11 12 13]
# [24 25 26]]

Funciones de Agregación

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

print(np.sum(arr)) # 21 - 전체 합
print(np.mean(arr)) # 3.5 - 평균
print(np.std(arr)) # 1.707... - 표준편차
print(np.var(arr)) # 2.916... - 분산
print(np.median(arr)) # 3.5 - 중앙값

# 축 지정
print(np.sum(arr, axis=0)) # [5 7 9] - 열 방향 합
print(np.sum(arr, axis=1)) # [6 15] - 행 방향 합

print(np.mean(arr, axis=0)) # [2.5 3.5 4.5] - 열 평균
print(np.mean(arr, axis=1)) # [2. 5.] - 행 평균

Cambiar Forma del Array

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

# reshape - 형태 변경
reshaped = arr.reshape(2, 3)
print(reshaped)
# [[1 2 3]
# [4 5 6]]

# flatten - 1차원으로 펼치기
flattened = reshaped.flatten()
print(flattened) # [1 2 3 4 5 6]

# transpose - 전치
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
print(arr2d.T)
# [[1 4]
# [2 5]
# [3 6]]

# 차원 추가
arr = np.array([1, 2, 3])
expanded = np.expand_dims(arr, axis=0)
print(expanded.shape) # (1, 3)

Combinar Arrays

arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[5, 6], [7, 8]])

# 수직 결합
vstack = np.vstack([arr1, arr2])
print(vstack)
# [[1 2]
# [3 4]
# [5 6]
# [7 8]]

# 수평 결합
hstack = np.hstack([arr1, arr2])
print(hstack)
# [[1 2 5 6]
# [3 4 7 8]]

# concatenate
concat = np.concatenate([arr1, arr2], axis=0) # 행 방향
print(concat)

Ejemplos Prácticos

예제 1: 학생 성적 통계

import numpy as np

# 학생 5명의 3과목 성적 (행: 학생, 열: 과목)
scores = np.array([
[85, 90, 78], # 학생 1
[92, 88, 95], # 학생 2
[78, 85, 80], # 학생 3
[95, 92, 88], # 학생 4
[88, 86, 92] # 학생 5
])

# 각 학생의 평균 점수
student_avg = np.mean(scores, axis=1)
print("학생별 평균:", student_avg)
# [84.33 91.67 81. 91.67 88.67]

# 각 과목의 평균 점수
subject_avg = np.mean(scores, axis=0)
print("과목별 평균:", subject_avg)
# [87.6 88.2 86.6]

# 전체 평균
total_avg = np.mean(scores)
print(f"전체 평균: {total_avg:.2f}") # 87.47

# 최고 점수와 학생
max_score = np.max(scores)
max_position = np.unravel_index(np.argmax(scores), scores.shape)
print(f"최고 점수: {max_score} (학생 {max_position[0]+1}, 과목 {max_position[1]+1})")

# 90점 이상 받은 횟수
high_scores = np.sum(scores >= 90)
print(f"90점 이상: {high_scores}회") # 6회

예제 2: 행렬 연산과 선형대수

import numpy as np

# 행렬 곱셈
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

# 행렬 곱 (내적)
C = np.dot(A, B)
# 또는 C = A @ B
print("행렬 곱:")
print(C)
# [[19 22]
# [43 50]]

# 역행렬
inv_A = np.linalg.inv(A)
print("역행렬:")
print(inv_A)
# [[-2. 1. ]
# [ 1.5 -0.5]]

# 역행렬 검증
identity = A @ inv_A
print("A × A^(-1):")
print(np.round(identity, 2)) # 단위 행렬

# 고유값과 고유벡터
eigenvalues, eigenvectors = np.linalg.eig(A)
print("고유값:", eigenvalues)
print("고유벡터:")
print(eigenvectors)

# 행렬식
det = np.linalg.det(A)
print(f"행렬식: {det}") # -2.0

예제 3: 이동 평균 계산

import numpy as np

# 주식 가격 데이터
prices = np.array([100, 102, 98, 105, 107, 103, 110, 108, 112, 115])

def moving_average(data, window_size):
"""이동 평균 계산"""
weights = np.ones(window_size) / window_size
return np.convolve(data, weights, mode='valid')

# 3일 이동 평균
ma_3 = moving_average(prices, 3)
print("3일 이동 평균:", np.round(ma_3, 2))

# 5일 이동 평균
ma_5 = moving_average(prices, 5)
print("5일 이동 평균:", np.round(ma_5, 2))

# 수익률 계산
returns = (prices[1:] - prices[:-1]) / prices[:-1] * 100
print("일일 수익률(%):", np.round(returns, 2))

예제 4: 이미지 처리 기초

import numpy as np

# 간단한 이미지 (8x8 그레이스케일)
image = np.random.randint(0, 256, size=(8, 8))

print("원본 이미지:")
print(image)

# 이미지 반전
inverted = 255 - image
print("\n반전 이미지:")
print(inverted)

# 밝기 조정 (+50)
brightened = np.clip(image + 50, 0, 255)
print("\n밝게:")
print(brightened)

# 대비 증가 (×1.5)
contrasted = np.clip(image * 1.5, 0, 255).astype(np.uint8)
print("\n대비 증가:")
print(contrasted)

# 이진화 (임계값 128)
binary = np.where(image > 128, 255, 0)
print("\n이진화:")
print(binary)

Comparación de Rendimiento

import numpy as np
import time

# 순수 Python vs NumPy
size = 1000000

# Python 리스트
python_list = list(range(size))
start = time.time()
result = [x * 2 for x in python_list]
python_time = time.time() - start

# NumPy 배열
numpy_array = np.arange(size)
start = time.time()
result = numpy_array * 2
numpy_time = time.time() - start

print(f"Python 리스트: {python_time:.4f}초")
print(f"NumPy 배열: {numpy_time:.4f}초")
print(f"NumPy가 {python_time/numpy_time:.1f}배 빠름")

Preguntas Frecuentes

NumPy 배열과 Python 리스트의 차이는?

NumPy 배열:

  • 같은 타입의 데이터만 저장
  • 메모리 효율적
  • 빠른 연산 (C로 구현)
  • 벡터화 연산 지원

Python 리스트:

  • 다양한 타입 혼합 가능
  • 동적 크기 조정 용이
  • 느린 연산 (순수 Python)

axis=0과 axis=1의 차이는?

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

# axis=0: 행 방향 (↓)
print(np.sum(arr, axis=0)) # [5 7 9]

# axis=1: 열 방향 (→)
print(np.sum(arr, axis=1)) # [6 15]

reshape에서 -1의 의미는?

-1은 자동으로 크기를 계산하라는 의미입니다.

arr = np.arange(12)

# 자동으로 4 계산
reshaped = arr.reshape(3, -1) # (3, 4)

# 자동으로 3 계산
reshaped = arr.reshape(-1, 4) # (3, 4)

# 1차원으로 펼치기
flattened = arr.reshape(-1) # (12,)

복사 vs 뷰?

arr = np.array([1, 2, 3, 4, 5])

# 뷰 (원본 영향)
view = arr[1:4]
view[0] = 999
print(arr) # [1 999 3 4 5]

# 복사 (원본 안전)
copy = arr[1:4].copy()
copy[0] = 777
print(arr) # [1 999 3 4 5] (변경 없음)

Próximos Pasos

NumPy를 익혔다면 다음을 학습해보세요:

  1. Pandas: NumPy 기반의 데이터 분석 라이브러리
  2. SciPy: 과학 계산 고급 기능
  3. Matplotlib: NumPy 배열 시각화
  4. 머신러닝: scikit-learn으로 ML 시작

Referencias