파이썬입문 겨울방학 특강 (3)
import numpy as np
- 넘파이의 위력
l=[1,2,3]
a=np.array(l) ## list()
- 사칙연산 브로드캐스팅
a+1
l+1
a*2
l*2
a-2
l-2
a/2
l/2
- 기타수학연산가능
np.sqrt(a), np.sqrt(l)
np.log(a), np.log(l)
- 아래의 연립방정식 고려
$\begin{cases} x + y = 2 \\ y + z = 2 \\ x + z = 2 \end{cases}$
- 행렬표현은?
$\begin{bmatrix} 1 &1& 0 \\ 0 & 1 & 1 \\ 1 & 0 & 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ z \end{bmatrix} =\begin{bmatrix} 2 \\ 2 \\ 2 \end{bmatrix} $
A = [[1,1,0],[0,1,1],[1,0,1]]
A
A2=np.array(A)
A2
- A의 원소인덱싱
A[0][0], A[0][1], A[0][2]
A[1][0], A[1][1], A[1][2]
A[2][0], A[2][1], A[2][2]
- A2에서의 원소인덱싱
A2[0][0], A2[0][1], A2[0][2]
A2[1][0], A2[1][1], A2[1][2]
A2[2][0], A2[2][1], A2[2][2]
- A2에서의 원소에 접근하는 또다른 방법 (numpy 신기술)
A2[0,0], A2[0,1], A2[0,2]
A2[1,0], A2[1,1], A2[1,2]
A2[2,0], A2[2,1], A2[2,2]
- 슬라이싱!
A2[0,:] ## R의 경우라면 A2[0,]
A2[1,:]
A2[2,:]
- 연립방정식 문제를 다시 풀어보자.
$\begin{bmatrix} 1 & 1 & 0 \\ 0 & 1 & 1 \\ 1 & 0 & 1 \end{bmatrix} \begin{bmatrix} x_1 \\ x_2 \\ x_3 \end{bmatrix} =\begin{bmatrix} 2 \\ 2 \\ 2 \end{bmatrix} \quad \Longleftrightarrow \quad {\bf A} {\bf x} = {\bf b} $
b=np.array([2,2,2])
np.linalg.inv(A2) @ b ## R로 치면 solve(A2) %*% b
- 선언
l=[11,22,33,44,55,66]
a=np.array(l)
a
- 인덱스로 접근
l[0],l[1],l[2],l[3],l[4],l[5]
a[0],a[1],a[2],a[3],a[4],a[5]
- : 이용 (슬라이싱)
l[2:4] # index=2, index=3 (4는 포함되지 않음)
a[2:4]
너무 헷갈림.. 특히 마지막 원소를 포함해야할때!
l[2:6]
a[2:6]
다행스럽게도 마지막의 6은 생략가능하다. 따라서 보통 아래와 같이 쓴다.
l[2:]
a[2:]
동일한 논리로 처음 인덱스도 생략가능하다.
a[0:3], a[:3]
처음과 마지막을 둘다 생략한다면?
a[:]
- 부울값을 이용한 인덱싱
l=[11,22,33,44,55,66]
a=np.array(l)
a
a[ [False, True, False, True, False, True] ]
a<33
a[a<33]
리스트는 안된다.
l<33 ## 일단 여기서 막힘
- reshape
l = [11,22,33,44,55,66]
a = np.array(l)
a
a.reshape(2,3)
a ## reshape은 a자체가 변화하지 않음
b = a.reshape(2,3)
b
- b를 다시 a처럼 바꾸고 싶다면?
b.reshape(6)
b.flatten()
b.ravel()
b.reshape(-1)
- 2차원 array a,b를 선언하자.
a=np.array([[11,22,33,44]]).reshape(2,2)
a
b=np.array([[11,22,33,44,55,66]]).reshape(2,3)
b
- a. + TAB, b. + TAB
a.shape, b.shape
a.size, b.size
a.itemsize, b.itemsize
- ?
a.strides, b.strides
- ?
a의 형태
a
b의 형태
b
- itemsize와 strides의 의미를 유추하기 위해서 c,d를 더 만들어보자.
c = np.array([11,22,33,44]).reshape(4,1)
d = np.array([11,22,33,44])
c의 형태
c
d의 형태
d
- a,b,c,d 속성비교
a.shape, b.shape, c.shape, d.shape ## 차원
a.size, b.size, c.size, d.size ## 원소의 수
a.itemsize, b.itemsize, c.itemsize, d.itemsize ## 항상 8?
a.strides, b.strides, c.strides, d.strides ## 차원이랑 관련이 있어보임.. + 8의 배수
a
- itemsize, strides는 무엇?
- itemsize: 숫자하나를 저장하는 필요한 메모리 공간
- strides: (다음 행으로 가기위해서 JUMP해야하는 메모리 공간수, 다음 열로 가기위해서 JUMP해야하는 메모리 공간수)
- strides에 대한 추가해설
(오브젝트b)
b
b.reshape(-1)
b.strides
- itemsize는 항상 8이다?
e=np.array([11,22,33,44,55,66],dtype='int32')
e
e.itemsize
e=e.reshape(2,3)
e
e.strides
- a를 선언, b는 a의 참조
a=np.array([[1,2],[3,4]])
b=a ## 참조
a
b
a.shape
b.shape
- a의 shape을 바꾸어보자 $\to$ b도 같이 바뀐다
a.shape = (4,)
a
b
id(a),id(b)
- a를 선언, b는 a의 view
a=np.array([[1,2],[3,4]])
b=a.view() ## shallow copy
a
b
a.shape
b.shape
a.shape= (4,1)
a
b
id(a), id(b)
- 그런데..
a[0]=100
a
b
- 출생의 비밀
b
b.base
- ? 이거 바뀐 a아니야?
id(b.base)
id(a)
- View
- b가 a의 뷰라는 의미는, b가 a를 소스로하여 만들어진 오브젝트란 의미이다.
- 따라서 이때 b.base는 a가 된다.
- b는 자체적으로 데이터를 가지고 있지 않으며 a와 공유한다.
- 이러한 의미에서 view를 shallow copy 라고 부른다. (가장 껍데기 구조만 복사하므로)
note1 원본 ndarray의 일 경우는 .base가 None으로 나온다.
a.base
note2 b.base의 shpae과 b의 shape은 아무 관련없다.
b.shape
b.base.shape
- a를 선언, b는 a의 copy
a=np.array([[1,2],[3,4]])
b=a.copy()
id(a),id(b)
- a의 shape을 바꿔도 b에는 적용되지 않음
a.shape = (4,1)
a
b
- 그리고 a[0]의 값을 바꿔도 b에는 적용되지 않음.
a[0]=100
a
b
- b의 출생을 조사해보니..
a.base,b.base
출생의 비밀은 없었다. 둘다 원본.
.copy의 한계(?)
a=np.array([1,[1,2]],dtype='O')
a
b=a.copy()
b
a[0]=222
a
b
a[1][0]=333
a
b
해결책: 더 깊은 복사
import copy
a=np.array([1,[1,2]],dtype='O')
b=copy.deepcopy(a)
a
b
a[0]=100
a,b
a[1][0]=200
a,b
일반적으로 넘파이를 이용할때 자주 사용하는 데이터 구조인 행렬, 텐서등을 이용하면 위와 같은 copy모듈은 불필요함
- test 함수 작성
def test(a,b):
if id(a) == id(b):
print("별명")
elif id(a) == id(b.base) or id(a.base)==id(b):
print("뷰")
elif (id(a.base)!=id(None) and id(b.base)!=id(None)) and id(a.base) == id(b.base):
print("공통의 base를 가짐")
else:
print("카피, 혹은 아무 관련없는 오브젝트")
- 잘 동작하나?
(테스트1)
a=np.array([1,2,3,4])
b=a
test(a,b)
(테스트2)
a=np.array([1,2,3,4])
b=a.view()
test(a,b)
(테스트3)
a=np.array([1,2,3,4])
b=a.view()
c=a.view()
test(b,c)
test(a,b)
test(a,c)
(테스트4)
a=np.array([1,2,3,4])
b=a.copy()
test(a,b)
- 우리가 사용했던 어떠한 것들이 뷰가 나올지 카피가 나올지 사실 잘 모른다.
a=np.array([1,2,3,4])
b=a[:3]
a
b
test(a,b)
c=a[[0,1,2]]
c
test(a,c)
-
a=np.array([[1,2],[3,4]])
a
b=a.flatten()
c=a.ravel()
d=a.reshape(-1)
test(a,b)
test(a,c)
test(a,d)
test(c,d)
test(b,c)