-
Numpy
- 숫자 배열을 효과 적으로 저장하고 가공하는 전문도구
- 파이썬 데이터 과학 도구 생태계의 핵심
- Numpy 배열을 연속된 메모리 블록에 데이터를 저장한다.
- 벡터화 연산 : 루프 없이 데이터 처리 작업이 가능하다
ndarray 배열 생성
np.array() 함수를 써서, 배열을 생성한다.
np.zeros(10, dtype=int) #0으로 채운 배열 np.ones((3,5), dtype=float) #1로 채운 배열 np.full((3,5), 3.14) #같은 값으로 채운 배열 np.arange(0, 20, 2) #선형 수열로 채운 배열(step), range()와 유사 np.linspace(0, 1, 5) #일정한 간격으로 채운 배열(개수) np.random.seed(0) #재현을 위한 씨드값 np.random.random((3,3)) #[0,1)난수로 채운 배열 np.random.normal(0, 1, (3,3)) #정규분포 난수로 채운 배열 np.random.randint(0, 10, (3,3)) #정수 난수로 채운 배열 [low, high) np.eye(3) #항등행렬(identity matrix) np.empty(3) #초기화되지 않은 배열(메모리에 남아 있는 값)
배열 인덱싱
단일 원소(특정 원소)에 접근하는 법
다차원 배열에서는 콤마로 구분된 인덱스 튜플 사용
x[2] x[-1] y[0, 0] y[1, 2] = 100
배열 슬라이싱(slicing) : 부분배열(subarray)에 접근하기
x[start:stop:step] #디폴트 start=0, stop=차원크기, step=1
- 배열 슬라이스는 원래 배열의 사본(copy)이 아니라 뷰(view)를 반환하므로 슬라이스를 수정하면 원래 배열이 변경된다.
- 데이터를 명시적으로 복사하고 싶으면, copy() 메서드 사용
reshape() 매서드
1차원 배열을 2차원 행렬로 전환할 수 있다.
z = np.array([1,2,3]) #1차원 배열 z.reshape((1,3)) #z[np.newaxis, :]와 동일 z.reshape((3,1)) #z[:, np.newaxis]와 동일
배열 연결
np.concatenate 함수 : array 리스트를 인수 한다.
x = np.array([1,2,3]) y = np.array([3,2,1]) np.concatenate([x, y]) #x+y는 원소별 합 grid = np.array([[4,5,6], [7,8,9]]) np.concatenate([grid, grid]) #행(axis=0)결합 np.concatenate([grid, grid], axis = 1) #열(axis=1)결합 np.vstack & np.hstack 함수 : array 리스트를 인수로 함 np.vstack([x,grid]) #수직으로 쌓기 z = np.array([[99],[99]]) np.hstack([grid, z]) #수평으로 쌓기 np.r_ & np.c_ 루틴 : 배열을 행(열)로 연결 a = np.full((2,2), 1) b = np.full((2,2), 2) np.r_[a,b] #수평으로 쌓기 np.c_[a,b] #수직으로 쌓기
배열 분할
np.split, np.hsplit, np.vsplit 함수로 구현
x = [1,2,3,99,99,3,2,1] x1, x2, x3 = np.split(x, [3,5]) grid = np.arange(16).reshape((4, 4)) upper, lower = np.vsplit(grid, [2]) left, right = np.hsplit(grid, [2])
백터화 연산
백터화 연산은 루프 없이 배열의 각 요소에 연산을 적용한다.
구현
- 유니버설 함수(UFuncs : universal functions)
- 브로드캐스팅(broadcasting)
NumPy UFuncs
- 배열의 각 원소(element)에 유니버설 함수를 적용
- 산술 연산자는 NumPy의 ufunc로 구현 ex) a + b ⇔ np.add(a, b)
- 유니버설 수학 함수 : np.abs(), np,sin(), np.exp(), np.log(), np.power(), ... 등이 있다.
브로드캐스팅
차원이 다른 두 배열의 연산을 확장하는 방식
차원이 더 큰 배열에 맞춰 더 작은 차원의 배열의 shape을 확장np.arange(3) + 5 np.ones((3,3)) + np.arange(3) np.arange(3).reshape(3,1) + np.arange(3) np.ones((3,2)) + np.arange(3) #ValueError : 브로드캐스트 불가
인터넷에 좋은 이미지들이 많다.
배열 집계
Numpy 함수가 빠르다.
브로드캐스팅 & 집계 예제
- 데이터 표준화(standardization)
- 데이터 센터링(centering) : 각 열의 평균을 빼기
- 데이터 스케일링(scaling) : 각 열의 표준편차로 나누기
비교, 마스크, 부울 로직
비교
비교 연산자도 NumPy의 ufunc로 구현 ex) x < 3 ⇔ np.less(x, 3)
비교 연산자 : ==, !=, <, <=, >, >=
연산 결과는 부울 타입의 배열x = np.array([1,2,3,4,5]) x < 3 (2 * x) == (x ** 2)
조건식 : np.where(조건, x, y)
a = np.arange(10) np.where(a < 5, a, 10*a)
부울 마스킹(masking)
- 특정 기준에 따라 배열을 값을 추출하거나, 수정, 계산, 조작할 때 사용
- 마스킹 연산 : 부울 배열을 인덱스로 사용하여 배열에서 조건에 맞는 값을 선택
x[x<3]
팬시 인덱싱(fancy indexing)
- 팬시 인덱싱 : 단일 스칼라 대신 인덱스 배열을 전달
- 원래 배열을 복사해 처리하므로 값을 변경해도 원래 배열의 값은 변경되지 않음
rand = np.random.RandomState(1) x = rand.randint(10, size=10) #array([5,8,9,5,0,0,1,7,6,9]) ind = [3, 7, 4] x[ind] #array([5,7,0]) M = np.arange(12).reshape((3,4)) row = np.array([0,1,2]) col = np.array([2,1,3]) M[row, col]
벡터/행렬 곱
벡터의 외적 vs 내적
x = np.arange(3) y = np.full(3,1) np.outer(x, x) #외적 np.inner(x, x) #내적 <=> np.dot(x, x) np.outer(x, y) #외적 np.inner(x, y) #내적 행렬 곱셈 : dot product 연산(함수) 혹은 @ 연산자 a = np.array([[0,1],[2,3]], float) b = np.array([2,3], float) c = np.array([[1,1],[4,0]], float) np.dot(a, b) # a @ b <=> a.dot(b) np.dot(a, c) # a @ c <=> a.dot(c)