NumPy
import numpy as npdata = [[1,2,3], [4,5,6], [7,8,9]]data * 2산술연산 수행을 위해서는 제어 구문이 필요합니다.
data2 = []
for row in data:
data2.append([n*2 for n in row])
data2행 선택은 쉽지만, 열 선택은 어렵습니다.
data2[0]data2[0][0], data2[1][0], data2[2][0]import arrayx = array.array('d', [1, 2, 3])x.append(4.5)xtry:
x.append('오')
except TypeError as e:
print('TypeError:', e)try:
x - x
except TypeError as e:
print('TypeError:', e)import numpy as nparr2d = np.array(data)type(arr2d)arr2d데이터의 자료형
arr2d.dtypeNumPy 배열은 한 가지 자료형의 데이터만 저장할 수 있습니다.
np.array([1, '2', 3.14])파이썬의 표준 자료구조보다 훨씬 빠르게 연산을 수행합니다.
arr = np.arange(1e7)
nums = arr.tolist()%timeit [n*1.1 for n in nums]%timeit arr * 1.11산술연산¶
산술연산이 기본적으로 원소별로 수행됩니다.
arr2d * 2arr2d - arr2d2색인과 슬라이스¶
행열 단위 접근이 가능합니다.
arr2d[0]arr2d[:, 0]arr2d[0:2]arr2d[:, 0:2]arr2d[1:, 1:]3팬시 색인¶
datadata[0], data[2]arr2d[[0, 2]]arr2d[[2, 0]]arr2d[[-1, -2]]arr2d[:, [0,2]]arr2d[:, [2, 0]]4불리언 색인¶
arr = np.array([0, 1, 2, 3, -4, -5])arr[[True, True, True, False, False, False]]arr > 0arr[arr > 0]원소별 논리연산
~(arr > 0)(arr > 0) & (arr < 3)(arr < 0) | (arr > 1)5배열 전치¶
arr2darr2d.T6유니버설 함수¶
data = list(range(1, 11))datafrom math import sqrt[sqrt(n) for n in data]arr = np.array(data)np.sqrt(arr)이항 유니버설 함수
x = np.array([0, 1])x[::-1]np.maximum(x, x[::-1])7벡터 단위 연산¶
data = [[1, -1], [-2, 2]]data2 = []
for row in data:
new_row = []
for n in row:
n2 = n if n > 0 else 0
new_row.append(n2)
data2.append(new_row)
data2arr = np.array(data)np.where(arr > 0, arr, 0)7.1산술통계¶
arr = np.random.randn(3,2)arrarr.mean()np.mean(arr)arr.sum()arr.sum(axis=0)arr.sum(axis=1)7.2집합 함수¶
arr = np.array([0, 1, 2, 3] * 2)arrnp.unique(arr)np.in1d(arr, [1, 2])arr[np.in1d(arr, [1,2])]x = np.array([0,1,2,3])y = np.array([1,2,3,4])np.intersect1d(x, y)np.union1d(x, y)np.setdiff1d(x, y)np.setxor1d(x, y)7.3선형대수¶
x = np.array([[1, 1], [2, 2]])xy = np.array([[1, -1], [-1, 1]])yx*ynp.dot(x, y)행렬로 방정식 해 구하기
A = np.array([[3, 6, -5], [1, -3, 2], [5, -1, 4]])
B = np.array([12, -2, 10])np.linalg.inv(A)np.dot(np.linalg.inv(A), B)8난수 생성¶
import randomrandom.randint(0, 10)np.random.seed(0)np.random.randint(0, 11, size=10)np.random.randint(0, 11, size=(4,4))%timeit [random.randint(0, 10) for _ in range(10**6)]%timeit np.random.randint(0, 11, size=10**6)배열 섞기
x = np.arange(10)xnp.random.shuffle(x)xnp.random.permutation(x)x난수 생성 확률 모델
np.random.rand(5)np.random.randn(5)np.random.normal(0, 1, size=5)from scipy.stats import norm, uniform
from pandas import Series%matplotlib inlinex = np.linspace(-3, 3, 100)
Series(norm.pdf(x), x).plot()x = np.linspace(-1, 2, 100)
Series(uniform.pdf(x), x).plot()9BLAS¶
import numpy as np
print(np.__config__.show())Output
import numpy as np
import time
a = np.random.rand(2000, 2000)
b = np.random.rand(2000, 2000)
t = time.time()
c = a @ b
print(f"Time: {(time.time() - t) * 1000:.0f} ms")10연산 속도¶
"""
파이썬 리스트 vs NumPy 배열 연산 속도 비교 스크립트
- 1차원: 원소별 덧셈
- 2차원(행렬): 원소별 덧셈 + 행렬 곱
실행 예시:
python compare_list_numpy.py
"""
import time
import random
import numpy as np
def benchmark_1d(n=5_000_000):
print(f"\n=== 1차원 벡터 원소별 덧셈: 길이 n = {n:,} ===")
# 데이터 생성
py_list_a = [random.random() for _ in range(n)]
py_list_b = [random.random() for _ in range(n)]
np_a = np.array(py_list_a)
np_b = np.array(py_list_b)
# 파이썬 리스트: for 루프
start = time.perf_counter()
py_result = [a + b for a, b in zip(py_list_a, py_list_b)]
end = time.perf_counter()
py_time = end - start
print(f"Python 리스트 덧셈: {py_time:.4f}초")
# NumPy: 벡터화 연산
start = time.perf_counter()
np_result = np_a + np_b
end = time.perf_counter()
np_time = end - start
print(f"NumPy 배열 덧셈: {np_time:.4f}초")
print(f"→ NumPy가 약 {py_time / np_time:,.1f}배 빠름 (1차원 벡터 덧셈)")
def benchmark_2d_elementwise(n=2000, m=2000):
print(f"\n=== 2차원 행렬 원소별 덧셈: 크기 {n:,} x {m:,} ===")
# 데이터 생성 (리스트의 리스트)
py_mat_a = [[random.random() for _ in range(m)] for _ in range(n)]
py_mat_b = [[random.random() for _ in range(m)] for _ in range(n)]
np_a = np.array(py_mat_a)
np_b = np.array(py_mat_b)
# 파이썬 리스트: 이중 for 루프
start = time.perf_counter()
py_result = [
[a + b for a, b in zip(row_a, row_b)]
for row_a, row_b in zip(py_mat_a, py_mat_b)
]
end = time.perf_counter()
py_time = end - start
print(f"Python 리스트 행렬 덧셈: {py_time:.4f}초")
# NumPy: 벡터화 연산
start = time.perf_counter()
np_result = np_a + np_b
end = time.perf_counter()
np_time = end - start
print(f"NumPy 배열 행렬 덧셈: {np_time:.4f}초")
print(f"→ NumPy가 약 {py_time / np_time:,.1f}배 빠름 (행렬 원소별 덧셈)")
def benchmark_2d_matmul(n=800, k=800, m=800):
"""
n x k · k x m 행렬 곱 연산 비교.
순수 파이썬 3중 for 루프는 매우 느리므로 크기를 너무 크게 잡지 마세요.
"""
print(f"\n=== 2차원 행렬 곱: ({n:,} x {k:,}) · ({k:,} x {m:,}) ===")
# 리스트의 리스트로 행렬 생성
py_a = [[random.random() for _ in range(k)] for _ in range(n)]
py_b = [[random.random() for _ in range(m)] for _ in range(k)]
np_a = np.array(py_a)
np_b = np.array(py_b)
# 파이썬 리스트: 3중 for 루프 (전형적인 O(n*k*m) 구현)
start = time.perf_counter()
py_c = [[0.0] * m for _ in range(n)]
for i in range(n):
for j in range(m):
s = 0.0
for t in range(k):
s += py_a[i][t] * py_b[t][j]
py_c[i][j] = s
end = time.perf_counter()
py_time = end - start
print(f"Python 리스트 행렬 곱: {py_time:.4f}초")
# NumPy: 고도로 최적화된 BLAS 루틴 사용
start = time.perf_counter()
np_c = np_a @ np_b # 또는 np.dot(np_a, np_b)
end = time.perf_counter()
np_time = end - start
print(f"NumPy 배열 행렬 곱: {np_time:.4f}초")
print(f"→ NumPy가 약 {py_time / np_time:,.1f}배 빠름 (행렬 곱)")
if __name__ == "__main__":
# 필요에 따라 크기를 조절해서 실험해보세요.
benchmark_1d(n=5_000_000) # 1D: 5백만 원소 벡터
benchmark_2d_elementwise(2000, 2000) # 2D: 2000 x 2000 행렬 원소별 덧셈
benchmark_2d_matmul(800, 800, 800) # 2D: 행렬 곱