[파이썬] 파이썬 데이터 사이언스 핸드북 정리(1일차)
파이썬 데이터 사이언스 핸드북 -제이크 밴더플래스- -위키북스- P40 ~ P72까지(앞에 페이지는 쭉 읽어봄)
NumPy 소개
- 배열속성 지정(차원의 개수, 각차원의 크기, 배열의 크기)
- 배열 인덱싱 : 개별 배열 요솟값을 가져오고 설정
- 배열 슬라이싱 : 큰 배열 내에 있는 작은 하위 배열을 가져오고 설정한다.
- 배열 재구조화
- 배열 결합 및 분할
배열 인덱싱 : 단일 요소에 접근
: 파이썬 리스트와 달리 넘파이 배열은 고정 타입을 가진다.
import numpy as np
np.random.seed(0)
x1 = np.random.randint(10, size=6) # 1차원 배열
x2 = np.random.randint(10, size=(3,4)) # 2차원 배열
x3 = np.random.randint(10, size=(3, 4, 5)) # 3차원 배열
x1
array([5, 0, 3, 3, 7, 9])
x1[4]
7
# 다차원 배열에서는 인덱스 튜플을 이용하여 배열 항목에 접근
x2[0,0]
3
배열 슬라이싱 : 하위 배열에 접근
(:)은 어디서 어디까지
(::)은 어디서 몇칸씩
일차원 하위 배열 슬라이싱
x = np.arange(10)
x
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x[:5]
array([0, 1, 2, 3, 4])
x[1::3] # 1부터 3칸씩 가라
array([1, 4, 7])
다차원 하위 배열 슬라이싱
x2
array([[3, 5, 2, 4],
[7, 6, 8, 8],
[1, 6, 7, 7]])
x2[:2, :3]
array([[3, 5, 2],
[7, 6, 8]])
x2[:3, ::2] # 3행까지 / 0에서 2칸씩 열 뽑기
array([[3, 2],
[7, 8],
[1, 7]])
x2[::-1, ::-1] # 완전 역으로 변환 가능
array([[7, 7, 6, 1],
[8, 8, 6, 7],
[4, 2, 5, 3]])
print(x2)
[[3 5 2 4]
[7 6 8 8]
[1 6 7 7]]
사본이 아닌 뷰로서의 하위 배열
: 배열 슬라이스는 새로운걸 카피하는게 아니고 뷰(view)를 반환하는 것임
전혀 상상도 못함….새롭게 카피했다고 생각했는데, 그 부분만 짜른 내용이었다니
print(x2)
[[3 5 2 4]
[7 6 8 8]
[1 6 7 7]]
x2_sub = x2[:2, :2]
print(x2_sub)
[[3 5]
[7 6]]
x2_sub[0,0] = 99
print(x2_sub)
[[99 5]
[ 7 6]]
print(x2)
[[99 5 2 4]
[ 7 6 8 8]
[ 1 6 7 7]]
배열의 사본 만들기
이런 뷰의 기능에서도 복사하는 방법이 유용할 때가 당연히 있음. 이럴떈 copy() 메서드를 사용
x2_sub_copy = x2[:2, :2].copy()
print(x2_sub_copy)
[[99 5]
[ 7 6]]
x2_sub_copy[0,0] = 42
print(x2_sub_copy)
[[42 5]
[ 7 6]]
print(x2)
[[99 5 2 4]
[ 7 6 8 8]
[ 1 6 7 7]]
배열 재구조화
쉽게말하면 np.arange(range문같은거)에 reshape() 메서드를 사용해서 행렬에 집어 넣는것
grid = np.arange(1, 10).reshape((3, 3))
print(grid)
[[1 2 3]
[4 5 6]
[7 8 9]]
행으로 긴 행렬을 열로 긴 행렬로 만들때
reshape을 쓸 수도 있고, np.newaxis를 쓸 수도 있고
x = np.array([1,2,3])
x.reshape((3,1))
array([[1],
[2],
[3]])
x[:, np.newaxis]
array([[1],
[2],
[3]])
배열 연결 및 분할
배열 연결
Numpy에서는 주로 np.concatenate, np.vstack, np.hstack루틴을 이용해서 배열을 결합 연결한다.
x = np.array([1, 2, 3])
y = np.array([3, 2, 1])
np.concatenate([x,y])
array([1, 2, 3, 3, 2, 1])
grid = np.array([[1,2,3],
[4,5,6]])
# axis = 0 이면 아래로 / axis = 1 이면 옆으로
np.concatenate([grid, grid], axis = 0)
array([[1, 2, 3],
[4, 5, 6],
[1, 2, 3],
[4, 5, 6]])
# 혼합 차원 배열을 작업할때는 np.vstack(수직 스택) np.hstack(수평 스택)함수를 사용하는 것이 더 명확하다.
x = np.array([1,2,3])
grid = np.array([[9,8,7],[6,5,4]])
np.vstack([x, grid])
array([[1, 2, 3],
[9, 8, 7],
[6, 5, 4]])
y = np.array([[99],
[99]])
np.hstack([grid, y])
array([[ 9, 8, 7, 99],
[ 6, 5, 4, 99]])
배열 분할하기
결합의 반대로 분할은 np.split, np.hsplit, np.vsplit 함수로 구현
x = [1, 2, 3, 99, 99, 3, 2,1]
x1, x2, x3 = np.split(x, [3, 5]) # 숫자에 따라 분할 함.
print(x1, x2, x3)
[1 2 3] [99 99] [3 2 1]
grid = np.arange(16).reshape((4,4))
grid
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
upper, lower = np.vsplit(grid, [2])
print(upper)
print(lower)
[[0 1 2 3]
[4 5 6 7]]
[[ 8 9 10 11]
[12 13 14 15]]
left, right = np.hsplit(grid, [2])
print(left)
print(right)
[[ 0 1]
[ 4 5]
[ 8 9]
[12 13]]
[[ 2 3]
[ 6 7]
[10 11]
[14 15]]
NumPy 배열 연산: 유니버설 함수
NumPy 배열의 연산은 아주 빠르거나 아주 느릴 수 있다. 이 연산을 빠르게 만드는 핵심은 벡터화(vectorized) 연산을 사용하는 것
일반적으로 NumPy이 유니버설 함수(universal functions, ufuncs)를 통해 구현된다.
루프는 느리다.
파이썬이 동적인 인터프리터 언어이기 때문이다. 그래서 파이파이 프로젝트도 하고 그런다.
여튼 역수를 계산하는 함수를 만들어 쓰면 느리다!! 어떻게 빠르게 할지 알아보자!
import numpy as np
np.random.seed(0)
def compute_reciprocals(values) :
output = np.empty(len(values))
for i in range(len(values)) :
output[i] = 1.0 / values[i]
return output
values = np.random.randint(1, 10, size = 5)
compute_reciprocals(values)
array([0.16666667, 1. , 0.25 , 0.25 , 0.125 ])
big_array = np.random.randint(1, 100, size = 1000000)
%timeit compute_reciprocals(big_array)
1.91 s ± 32.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
UFuncs 소개
Numpy는 여러 종류의 연산에 대해 정적 타입 체계를 가진 컴파일된 루틴에 편리한 인터페이스를 제공
이를 벡터화라고함. 벡터화 연산은 간단히 배열에 연산을 수행해 각 요소에 적용함으로써 수행함.
print(compute_reciprocals(values))
print(1.0 / values)
[0.16666667 1. 0.25 0.25 0.125 ]
[0.16666667 1. 0.25 0.25 0.125 ]
%timeit (1.0 / big_array) # 훨씬 빠르다.
3 ms ± 60.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
### NumPy 유니버설 함수(UFuncs)
# 덧셋 이런거는 그냥 귀찮..ㅜ
x = np.arange(4)
print(x//2)
[0 0 1 1]
np.add(x,2) # add함수 등도 가능
array([2, 3, 4, 5])
# 절대값, 삼각함수, 지수/로그, 감마/오차/보수/역수 등 가능 (p62~65참조)
고급 Ufunc 기능
출력 지정
x = np.arange(5)
y = np.empty(5)
np.multiply(x, 10, out=y)
print(y)
[ 0. 10. 20. 30. 40.]
집계
x = np.arange(1, 6)
np.add.reduce(x)
15
외적
집계: 최소값, 최댓값 그리고 그사이의 모든것
# np.sum이 sum보다 빠르다.
# np.min, np.max도 빠르다
다차원 집계
import numpy as np
M = np.random.random((3,4))
print(M)
[[0.18421529 0.62406157 0.40068999 0.87145467]
[0.00360315 0.91047105 0.85724196 0.01109841]
[0.2326382 0.78671143 0.61034444 0.04097096]]
M.sum()
5.5335011128370475
M.min(axis=0) # 축에 따라 집계
array([0.00360315, 0.62406157, 0.40068999, 0.01109841])
np.sum(M)
5.5335011128370475
M.max(axis=1)
array([0.87145467, 0.91047105, 0.78671143])
기타 집계함수
np.sum, np.prod 등등 있다.