1. NumPy(Numerical Python)
NumPy는 대용량 데이터 배열을 효율적으로 연산할 수 있는 라이브러리
1-1. 다차원 배열 객체 ndarray
ndarray: N차원의 배열 객체로, 대규모 데이터 집합을 담을 수 있는 빠르고 유연한 자료 구조
# ndarray 생성
import numpy as np
data1 = [[1,2,3,4], [5,6,7,8]]
arr1 = np.array(data1)
print(arr1.ndim) # ndim: 차원의 크기를 알려줌
print(arr1.shape) # shape: 각 차원에 대해 크기를 알려줌
print(arr1.dtype) # dtype: 배열에 저장된 자료형을 알려줌
NumPy에는 배열을 생성하는 다양한 함수가 구현되어 있음
# 배열 생성 함수
np.zeros((3, 6))
위 zeros 함수 외에도 아래와 같은 함수들이 존재
array |
입력 데이터를 ndarray로 변환, 입력 데이터는 복사됨 |
asarray |
array와 같은 기능이나 입력 데이터가 이미 ndarray이면 복사 x |
arange |
내장 range 함수와 유사하며 ndarray 반환 |
ones, ones_like |
ones: 배열 내용을 1로 초기화해 생성 ones_like: 주어진 배열과 동일한 모양 dtype을 가지며 내용이 모두 1인 배열 생성 |
zeros, zeros_like |
ones, ones_like와 동일하나 내용을 0으로 채움 |
empty, empty_like |
메모리를 할당해 새로운 배열을 생성하나 ones나 zeros처럼 값을 초기화하지 않음 |
full, full_like |
인자로 받은 값으로 배열을 채움 |
eye, identity |
N*N 크기 단위행렬(or 항등행렬) 생성 |
ndarray의 dtype은 메타데이터(메모리의 특정 데이터를 해석하기 위해 필요한 정보)를 담는 특수한 객체
dtype은 astype 메소드로 명시적 변환도 가능
# 배열의 dtype을 명시적 변환
float_arr1 = arr1.astype(np.float64)
print(float_arr1.dtype)
NumPy 배열의 중요한 특징은 반복문을 작성하지 않아도 데이터를 일괄 처리할 수 있다는 것 -> 벡터화
# 벡터화를 통한 데이터 일괄 연산
arr = np.array([[1.,2.,3.], [4.,5.,6.]])
print(arr*arr)
print(arr-arr)
print(1/arr)
print(arr**0.5)
print(arr>=3)
Boolean 배열은 색인으로도 활용 가능
# Boolean 값을 색인에 활용하기
names = np.array(['Bob', 'Joe', 'Will', 'Bob'])
data = np.random.randn(4, 3)
print(data[names=='Bob'])
print(data[~(names=='Bob')])
팬시 색인(fancy indexing)도 가능
arr = np.empty((8, 4))
for i in range(8):
arr[i] = i;
print(arr)
print(arr[[4,3,0,6]])
print(arr[[-3,-5,-7]])
arr2 = np.arange(32).reshape((8, 4))
print(arr2[[1,5,7,2], [0,3,1,2]]) # [4, 23, 29, 10]
print(arr2[[1,5,7,2]][:, [0,3,1,2]])
배열을 전치하거나 축을 바꿀 수 있음
# 배열 전치와 축 바꾸기
arr = np.arange(15).reshape((3, 5))
print(arr)
print(arr.T)
print(np.dot(arr.T, arr))
arr2 = np.arange(16).reshape((2, 2, 4))
print(arr2)
print(arr2.transpose((1, 0, 2)))
print(arr2.swapaxes(1, 2))
1-2. 유니버설 함수 Universal Function
유니버설 함수는 ndarray 안의 데이터 원소별로 연산을 수행하는 함수
# 단항 유니버설 함수
arr = np.arange(10)
print(np.sqrt(arr))
print(np.exp(arr))
위 함수 외의 단항 유니버설 함수의 예시는 아래와 같음
abs, fabs |
각 원소의 절댓값을 구함, 복소수가 아니라면 더 빠른 연산을 위해 fabs 사용 가능 |
sqrt |
각 원소의 제곱근 계산(=arr**0.5) |
square |
각 원소의 제곱 계산(=arr**2) |
exp |
각 원소에서 지수 $e^{x}$ 계산 |
log, log10, log2, log1p |
자연로그, 십진로그, 이진로그, |
sign |
$ln, log_{2}, log_{10}, ln(x+1)$ |
ceil |
각 원소의 값보다 같거나 큰 정수 중 가장 작은 정수 반환(ex. 2.5->3) |
floor |
각 원소의 값보다 작거나 같은 정수 중 가장 작은 수 반환(ex. 2.5->2) |
rint |
각 원소를 반올림, dtype은 유지 |
modf |
각 원소의 몫과 나머지를 각각의 배열로 반환 |
isnan |
각 원소가 숫자인지에 대해 boolean 배열 반환 |
isfinite, isinf |
각 원소가 유한한지, 무한한지에 대해 boolean 배열 반환 |
cos, cosh, sin, sinh, tan, tanh |
삼각함수와 쌍곡삼각함수 |
arccos, arccosh, arcsin, arcsinh, arctan, arctanh |
역삼각함수 |
logical_not |
각 원소의 논리 부정 값 계산(=~arr) |
# 이항 유니버설 함수
x = np.random.randn(8)
y = np.random.randn(8)
print(np.maximum(x, y))
위 함수 외의 이항 유니버설 함수의 예시는 아래와 같음
add |
두 배열의 같은 위치의 원소끼리 더함 |
subtract |
첫 번째 배열의 원소에서 두 번째 배열의 원소를 뺌 |
multiply |
배열의 원소끼리 곱함 |
divide, floor_divide |
첫 번째 배열의 원소를 두 번째 배열의 원소로 나눔, floor_divide는 몫만 취함 |
power |
첫 번째 배열의 원소를 두 번째 배열의 원소만큼 제곱 |
maximum, fmax |
각 배열의 두 원소 중 큰 값 반환, fmax는 NaN 무시 |
minimum, fmin |
각 배열의 두 원소 중 작은 값 반환, fmin은 NaN 무시 |
mod |
첫 번째 배열의 원소를 두 번째 배열의 원소로 나눈 나머지를 구함 |
copysign |
첫 번째 배열의 원소의 기호를 두 번째 배열의 원소의 기호로 바꿈 |
greater, greater_equal, less, less_equal, equal, not_equal |
각각 두 배열의 원소 간의 >, >=, <, <=, ==, != 비교 연산 결과를 boolean 배열 반환 |
logical_and, logical_or, logical_xor |
각각 두 원소 간의 &, |, ^ 논리 연산 결과 반환 |
# 여러 배열을 반환하는 유니버설 함수
arr = np.random.randn(7)*5
remainder, whole_part = np.modf(arr)
print(arr)
print(remainder)
print(whole_part)
1-3. 배열지향 프로그래밍
값이 놓여 있는 그리드에서 연산을 할 때 배열을 활용할 수 있음
# 그리드
points = np.arange(-5, 5, 0.01)
xs, ys = np.meshgrid(points, points)
z = np.sqrt(xs**2+ys**2) # 그리드 상 두 포인트로 간단히 계산 가능
배열 연산으로 조건절을 표현할 수 있음
# 배열 연산으로 조건절 표현
xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])
result = [(x if c else y) for x, y, c in zip(xarr, yarr, cond)]
print(result)
result = np.where(cond, xarr, yarr)
print(result)
배열 전체 혹은 배열에서 한 축을 따르는 자료에 대해 수학, 통계 메소드 사용 가능
# 수학과 통계 메소드
# - 합, 평균
arr = np.random.randn(5, 4)
print(arr.mean())
print(arr.sum())
print(arr.mean(axis=1))
print(arr.sum(axis=0))
# - 중간 계산값 반환(cumsum, cumprod 등)
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])
print(arr.cumsum())
arr = np.array([[0,1,2], [3,4,5], [6,7,8]])
arr.cumsum(axis=0)
arr.cumprod(axis=1)
많이 사용되는 배열 통계 메소드는 아래와 같음
sum |
배열 전체 혹은 특정 축에 대한 모든 원소의 합 계산 |
mean |
산술 평균 계산(크기가 0인 배열은 NaN 반환) |
std, var |
표준편차와 분산 계산(분모의 기본값은 n, 변형 가능) |
min, max |
최솟값과 최댓값 반환 |
argmin, argmax |
최소 원소의 색인값(index)과 최대 원소의 색인값 반환 |
cumsum |
각 원소의 누적합 |
cumprod |
각 원소의 누적곱 |
boolean 배열의 값을 1(True) 또는 0(False)로 강제하여 메소드를 사용할 수 있음
# Boolean 배열 메소드
arr = np.random.randn(100)
print((arr>0).sum())
bools = np.array([False, False, True, False])
print(bools.any())
print(bools.all())
NumPy 배열 역시 파이썬 내장 리스트처럼 정렬 메소드가 존재
# 정렬
arr = np.random.randn(5, 3)
print(arr)
print(arr.sort(1))
# - 특정 분위 값 계산
large_arr = np.random.randn(1000)
large_arr.sort()
print(large_arr[int(0.05*len(large_arr))]) # 5% 분위
1차원 ndarray를 위한 기본적인 집합 연산 제공
# 집합 관련 함수
np.array(['Bob', 'Joe', 'Will', 'Bob'])
print(np.unique(names))
values = np.array([6, 0, 0, 3, 2, 5, 6])
print(np.in1d(values, [2, 3, 6]))
위 코드 외의 배열 집합 연산 메소드는 아래와 같음
unique(x) |
배열 x에서 중복된 원소를 제거한 뒤 정렬해 반환 |
intersect1d(x, y) |
두 배열의 교집합을 정렬해 반환 |
union1d(x, y) |
두 배열의 합집합을 반환 |
in1d(x, y) |
x의 원소가 y의 원소에 포함되는지 나타내는 boolean 배열 반환 |
setdiff1d(x, y) |
두 배열의 차집합 반환 |
setxor1d(x, y) |
대칭차집합(한 배열에는 포함되나 두 배열 모두에는 포함되지 않는 원소들의 집합) 반환 |
1-4. 배열 데이터의 파일 입출력
압축되지 않은 원시 바이너리 형식의 .npy 파일로 저장 및 불러오기 할 수 있음
# .npy 파일 입출력
arr = np.arange(10)
np.save('some_array', arr) # .npy 파일로 저장
np.load('some_array.npy')
여러 개의 배열을 압축된 형식으로 저장 및 불러오기 할 수 있음
# .npz 파일 입출력
np.savez('array_archive.npz', a=arr, b=arr) # 압축이 잘 되는 형식은 savez_compressed 사용 가능
arch = np.load('array_archive.npz')
arch['b']
1-5. 선형대수
numpy.linalg에는 행렬의 분할과 역행렬 등의 계산이 구현되어 있음
# 행렬 곱셈
x = np.array([[1,2,3], [4,5,6]])
y = np.array([[6, 23], [-1, 7], [8, 9]])
print(x.dot(y))
# numpy.linalg
from numpy.linalg import inv, qr
X = np.random.randn(5, 5)
mat = X.T.dot(X)
print(inv(mat))
q, r = qr(mat)
print(r)
자주 사용하는 선형대수 함수(numpy.linalg)는 아래와 같음
diag |
정사각 행렬의 대각/비대각 원소를 1차원 배열로 반환하거나, 1차원 배열을 대각선 원소로 하고 나머지는 0으로 채운 단위행렬 반환 |
dot |
행렬 곱셈 계산 |
trace |
행렬의 대각선 원소의 합 계산 |
det |
행렬식 계산 |
eig |
정사각 행렬의 고윳값과 고유벡터 계산 |
inv |
정사각 행렬의 역행렬 계산 |
pinv |
정사각 행렬의 무어-펜로즈 유사역원 역행렬 계산 |
qr |
QR 분해 계산 |
svd |
특잇값 분해(SVD) 계산 |
solve |
A가 정사각 행렬일 때 Ax = b를 만족하는 x 계산 |
lstsq |
Ax = b를 만족하는 최소제곱해 계산 |
1-6. 난수 생성
numpy.random 모듈로 다양한 종류의 확률분포로부터 표본값을 생성 가능
# (유사) 난수 생성기
samples = np.random.normal(size=(4, 4))
print(samples)
np.random.seed(1234)
(엄밀하게는 유사 난수라고 부르는데, 난수 생성기의 시드값에 따라 정해진 난수를 알고리즘으로 생성하기 때문)
# 격리된 난수 생성기
rng = np.random.RandomState(1234)
rng.randn(10)
아래는 numpy.random에 포함된 일부 함수들임
seed |
난수 생성기의 시드 지정 |
permutation |
순서를 임의로 바꾸거나 임의의 순열 반환 |
shuffle |
리스트나 배열의 순서 뒤섞기 |
rand |
균등분포에서 표본 추출 |
randint |
주어진 최소/최대 범위 안에서 임의의 난수 추출 |
randn |
표준편차가 1이고 평균값이 0인 정규분포에서 표본 추출 |
bionomial |
이항분포에서 표본 추출 |
normal |
정규분포(가우시안)에서 표본 추출 |
beta |
베타분포에서 표본 추출 |
chisquare |
카이제곱분포에서 표본 추출 |
gamma |
감마분포에서 표본 추출 |
uniform |
균등 [0, 1) 분포에서 표본 추출 |
싸니까 믿으니까 인터파크도서
CHAPTER 1 시작하기 전에 -1.1 이 책에서 다루는 내용 -1.2 왜 데이터 분석에 파이썬을 사용하나 -1.3 필수 파이썬 라이브러리 -1.4 설치 및 설정 -1.5 커뮤니티와 컨퍼런스 -1.6 이 책을 살펴보는 방법 CHAP
book.interpark.com
<Source>
towardsdatascience.com/how-to-create-numpy-arrays-from-scratch-3e0341f9ffea