Lecture 강의

Undergraduates 학부 Graduates 대학원 Lecture 역학 Lecture 설계 Lecture IT(IoT, AI) Lecture SAP2000 Lecture 아바쿠스 Lecture 파이썬 Lecture 엑셀 VBA Lecture 마이다스 Lecture 이탭스

[03. 패키지 - NumPy] (3) 연산(*,@), (4) 브로드캐스트(matmul), (5) 복사(깊은 복사 vs 얕은 복사)

작성자 : kim2kie

(2023-02-19)

조회수 : 1019

[참조]

 

NumPy는 과학 컴퓨팅을 위한 기본 패키지이다. 
다차원 배열 외에도 이산 푸리에 변환, 선형대수, 통계, 난수(random number) 등 다양한 기능을 가지고 있다.

 

 (3) 연산
  1) 요소별 연산
  2) Universal(범용) 함수
  3) 행렬 연산
  4) 정렬과 탐색

 (4) 브로드캐스트 
  1) 브로드캐스트(broadcast)
  2) 행렬 연산 함수 호출시 주의사항

 (5) 복사
  1) 얕은 복사와 깊은 복사
  2) 부분행렬은 얕은 복사이다.

 


 

 

(3) 연산

1) 요소별 연산

  • Ex)
    import numpy as np

    A = np.array([1,2])
    B = np.array([4,5])
    A+B   # array( [5,7] )
    A*B   # array( [4,10])
    A**2  # array( [1,4] )
    A+2   # array( [3,4] ); 각 요소에 2를 더함
    10*np.sin(A)  # 각 요소에 sin() 적용; array( [8.41470985,9.09297427] )
    A<3   # array([ True,True ], dtype=bool)
    A *= B # A = A*B와 동일; B와 곱한 다음에 A에 저장; array( [4,10] )
    A[0:2,] # array( [4,10] )

     

2) Universal(범용) 함수

  • np.sin(), np.cos() 등 다양한 수학함수를 제공한다. 

  • 스칼라값을 입력으로 하는 math 패키지와 달리 배열에 대해 elementwise로(즉, 각 요소에 대해) 적용된다.

  • Ex)
    import numpy as np

    x = np.arange(0.,np.pi,1.) # array( [0.,1.,2.,3.] )
    y = np.sin(x) # array( [0., 0.84147098, 0.90929743, 0.14112001] )

     

3) 행렬 연산

  • Ex)
    import numpy as np

    A = np.arange(4).reshape(2,2)      # (2,2); array( [[0,1],[2,3]] )
    B = np.arange(5,5+4).reshape(2,2)  # (2,2); array( [[5,6],[7,8]] )

    X = np.arange(2)                   # (2,); array( [0,1] )
    Y = np.arange(2).reshape(2,1)      # (2,1); array( [[0],[1]] )
    Z = np.arange(2).reshape(1,2)      # (1,2); array( [[0,1]] )

    # A*B, (2,2)*(2*2) = (2,2), 같은 결과
    C1 = np.dot(A,B)     # array( [[7,8],[31,36]] )
    C2 = np.matmul(A,B)  # array( [[7,8],[31,36]] )
    C3 = A@B             # array( [[7,8],[31,36]] )

    # A*X, (2,2)*(1*2) = (1,2), 같은 결과
    AX1 = np.dot(A,X)    # array( [1,3] )
    AX2 = np.matmul(A,X) # array( [1,3] )
    AX3 = A@X            # array( [1,3] )

    # A*Y, (2,2)*(2*1) = (2,1), 같은 결과 
    AY1 = np.dot(A,Y)    # array( [[1],[3]] )
    AY2 = np.matmul(A,Y) # array( [[1],[3]] ) 
    AY3 = A@Y            # array( [[1],[3]] ) 

    # A*Z, (2,2)*(1*2) = (1,2), 행렬 차수 에러
    AZ1 = np.dot(A,Z)     
    AZ2 = np.matmul(A,Z)  
    AZ3 = A@Z            

    # X*Y, (1,2)*(2*1) = (1,2)
    XY = X@Y   # array([1])

    #전치행렬(transpose matrix)
    A.T             # array( [[0, 2],[1, 3]] )
    np.transpose(A) # array( [[0, 2],[1, 3]] )

    # 선형대수함수
    A = np.array( [[1,2],[3,7]] )
    [D,V] = np.linalg.eig(A)   # D = eigenvalues, V = eigen vectors

    #언팩킹(unpacking): *(asterisk)를 사용
    np.array([0,60,40,20,0,np.zeros(n-5)])  --> array([0, 60, 40, 20, 0, array([0., 0., 0., ..., 0., 0., 0.])], dtype=object)
    np.array([0,60,40,20,0,*np.zeros(n-5)]) --> array([ 0., 60., 40., ...,  0.,  0.,  0.])

     

4) 정렬과 탐색 

  • Ex)
    import numpy as np

    X = np.array( [9.1,8.2,2.3] )

    np.amin(X) # 최솟값, 2.3
    np.amax(X) # 최댓값, 9.1

    np.argmin(X) # 최솟값 위치, 2
    np.argmax(X) # 최댓값 위치, 0

    np.sort(X) # 오름차순 정렬, array( [2.3,8.2,9.1] )
    np.argsort(X) # 오름차순 정렬 위치, array([2, 1, 0], dtype=int64)

    np.argsort(X)[0]  # 가장 작은 값의 위치, 2
    np.argsort(X)[-1] # 가장 큰 값의 위치, 0
    np.argsort(X)[-2] # 두 번째로 큰 값의 위치, 1


     

(4) 인덱싱(indexing)과 합치기

1) 브로드캐스트(broadcast) 

  • 형태가 다른 행렬의 연산

  • Ex)
    import numpy as np

    A = np.arange(4.).reshape(2,2) # 2D array, (2,2), array( [[0.,1.],[2.,3.]] )
    X = np.array( [1.,0.] )        # 1D array, (2,) , array( [1.,0.] )
    Y = X.reshape(1,2)             # 2D array, (1,2), array( [[1.,0.]] )
    Z = X.reshape(2,1)             # 2D array, (2,1), array( [[1.],[0.]] )

    A+1  # (2,2) + scalar*I = (2,2); array( [[1.,2.],[3.,4.]] )
    A+X  # (2,2) + (2,) = (2,2); array( [[1.,1.], [3.,3.]])
    A+Y  # (2,2) + (1,2) = (2,2); array( [[1.,1.], [3.,3.]])
    A+Z  # (2,2) + (2,1) = (2,2); array( [[1.,2.], [2.,3.]])

 

           

https://blog.finxter.com/numpy-broadcasting-a-simple-tutorial/
https://gomguard.tistory.com/146


 

2) 행렬 연산 함수 호출시 주의사항 

  • Ex)
    import numpy as np

    A = np.arange(4.).reshape(2,2) # 2D array, (2,2), array( [[0.,1.],[2.,3.]] )
    X = np.array( [1.,0.] )        # 1D array, (2,) 
    Y = X.reshape(1,2)             # 2D array, (1,2)
    Z = X.reshape(2,1)             # 2D array, (2,1)

    np.matmul(A,Y)   # (2,2)*(1,2) = Dimension Error
    np.matmul(A,Z)   # (2,2)*(2,1) = (2,1), array( [[0.],[2.]] )
    np.matmul(A,X)   # (2,2)*(2,) = (2,), array( [0.,2.] )

     

(5) 복사

1) 얕은 복사와 깊은 복사 

  • 깊은 복사(deep copy): 서로 값만 같을 뿐 본질적으로 서로 다르기 때문에 한 변수가 수정될 시 다른 변수가 수정되지 않는다.
    얕은 복사(shallow copy): 서로 다른 변수명이지만 본질적으로 서로 같은 대상을 의미하므로 하나의 변수 역시 수정이 된다.

  • Ex)
    import numpy as np

    A = [1,2,3]     # [1, 2, 3]
    X = np.array(A) # array( [1, 2, 3] )

    Z = X.copy()    # deep copy
    Z is X          # False

    Y = X           # shallow copy
    Y[0] = 10       # 

    X               # array( [10, 2, 3] )
    Y               # array( [10, 2, 3] )

    Y is X          # True
    X is Y          # True

     

2) 부분행렬은 얕은 복사이다. 

  • Ex)
    import numpy as np
    X = np.array( [1,2,3] )

    Y = X[0:2]      # shallow copy
    Y[0] = 10       #

    Y               # array( [10,2] )
    X               # array( [10,2,3] )