Vector는 힘의 크기(magnitude)와 방향(direction)을 갖는 물리량을 의미한다. 예컨대 속도, 가속도, 힘, 응력 등이 해당한다.
Scalar는 힘의 크기만 가지는 물리량(only magnitude, but not direction)을 의미한다. 예컨대 질량, 시간, 면적 등이 해당한다.
참고자료 1 참고자료 2
numpy 연산은 같은 위치의 원소끼리(element-wise) 연산하므로, 축의 shape가 동일해야 한다.
>>> arr = np.arange(24).reshape(3, 2, 4) >>> arr array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7]], [[ 8, 9, 10, 11], [12, 13, 14, 15]], [[16, 17, 18, 19], [20, 21, 22, 23]]]) >>> arr_2 = (np.arange(24) * 100).reshape(3, 2, 4) >>> arr_2 array([[[ 0, 100, 200, 300], [ 400, 500, 600, 700]], [[ 800, 900, 1000, 1100], [1200, 1300, 1400, 1500]], [[1600, 1700, 1800, 1900], [2000, 2100, 2200, 2300]]]) >>> arr + arr_2 array([[[ 0, 101, 202, 303], [ 404, 505, 606, 707]], [[ 808, 909, 1010, 1111], [1212, 1313, 1414, 1515]], [[1616, 1717, 1818, 1919], [2020, 2121, 2222, 2323]]])
# x축의 shape가 동일할 때. >>> arr_3 = np.array([100, 200, 300, 400]) >>> arr_3 array([100, 200, 300, 400]) >>> arr + arr_3 array([[[100, 201, 302, 403], [104, 205, 306, 407]], [[108, 209, 310, 411], [112, 213, 314, 415]], [[116, 217, 318, 419], [120, 221, 322, 423]]]) # y축의 shape가 동일할 때. >>> arr_4 = np.array([-1000, -2000]).reshape(2, 1) >>> arr_4 array([[-1000], [-2000]]) >>> arr - arr_4 array([[[1000, 1001, 1002, 1003], [2004, 2005, 2006, 2007]], [[1008, 1009, 1010, 1011], [2012, 2013, 2014, 2015]], [[1016, 1017, 1018, 1019], [2020, 2021, 2022, 2023]]]) # z축의 shape가 동일할 때. >>> arr_5 = np.array([10, 20, 30]).reshape(3, 1, 1) >>> arr_5 array([[[10]], [[20]], [[30]]]) >>> arr * arr_5 array([[[ 0, 10, 20, 30], [ 40, 50, 60, 70]], [[160, 180, 200, 220], [240, 260, 280, 300]], [[480, 510, 540, 570], [600, 630, 660, 690]]])
list의 연산과는 차이가 존재한다.
# list 연산 >>> a = [0, 1, 2, 3] >>> b = [100, 110, 220, 330] >>> a + b [0, 1, 2, 3, 100, 110, 220, 330] >>> a * b TypeError: can't multiply sequence by non-int of type 'list' >>> a - b TypeError: unsupported operand type(s) for -: 'list' and 'list' >>> a / b TypeError: unsupported operand type(s) for /: 'list' and 'list' # property를 활용한 vectorize @np.vectorize def plus(x, y): return (x + y) >>> plus(a, b) array([100, 111, 222, 333])
Matrix(행렬)의 연산은 array의 연산과 다른 점이 있어 주의가 필요하다. 수학 시간에 행렬의 연산을 배운 기억이 있을 것이다. 덧셈과 뺄셈 그리고 나눗셈은 array 연산처럼 같은 위치의 원소끼리 연산한다.
그러나, 행렬의 곱셈과 그 외의 행렬 연산은 배열의 연산과 다르다. 행렬 사이의 곱셈 연산은 아래와 같다. 따라서 곱셈의 순서가 중요하다.()
matrix 곱셈 >>> mat = np.matrix(np.arange(6).reshape(2, 3)) >>> mat matrix([[0, 1, 2], [3, 4, 5]]) >>> print(type(mat)) <class 'numpy.matrix'> # matrix의 덧셈은 shape가 완전히 동일해야 함. >>> mat2 = np.matrix([[10, 20], [100, 200]]) >>> mat + mat2 ValueError: operands could not be broadcast together with shapes (2,3) (2,2) # matrix의 곱셈은 [a, b] * [x, y]일 때 b와 x가 동일해야 한다. # (2,3) * (2,2) >>> mat * mat2 ValueError: shapes (2,3) and (2,2) not aligned: 3 (dim 1) != 2 (dim 0) # matrix 곱셈은 순서가 중요하다. # (2,2) * (2,3) >>> mat2 * mat matrix([[ 60, 90, 120], [ 600, 900, 1200]]) >>> mat3 = np.matrix([[1, 2], [10, 20], [100, 200]]) # (2,3) * (3,2) >>> mat * mat3 matrix([[ 210, 420], [ 543, 1086]]) # (3,2) * (2,3) >>> mat3 * mat matrix([[ 6, 9, 12], [ 60, 90, 120], [ 600, 900, 1200]])
numpy는 @
를 사용해 array 또한 행렬 곱을 할 수 있다.
>>> arr = np.arange(6).reshape(2, 3) >>> arr2 = np.array([[1, 2], [10, 20], [100, 200]]) >>> arr * arr2 ValueError: operands could not be broadcast together with shapes (2,3) (3,2) >>> arr @ arr2 array([[ 210, 420], [ 543, 1086]])
a와 b array를 행렬 곱셈 한다.
>>> arr = np.arange(4).reshape(2, 2) >>> arr array([[0, 1], [2, 3]]) >>> arr2 = np.arange(10, 18).reshape(2, 4) >>> arr2 array([[10, 11, 12, 13], [14, 15, 16, 17]]) >>> np.dot(arr, arr2) array([[14, 15, 16, 17], [62, 67, 72, 77]])
연산이 불가한 서로 다른 shape의 array를, 특정 조건이 만족할 때 연산이 가능하게 해주는 기능을 의미한다.
>>> a = np.arange(24).reshape(2, 3, 4) >>> a array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]) # (2, 3, 4) + (4,) >>> a + np.array([0, 10, 100, 1000]) array([[[ 0, 11, 102, 1003], [ 4, 15, 106, 1007], [ 8, 19, 110, 1011]], [[ 12, 23, 114, 1015], [ 16, 27, 118, 1019], [ 20, 31, 122, 1023]]]) # (2, 3, 4) + (3, 1) >>> a + np.array([[10], [100], [1000]]) array([[[ 10, 11, 12, 13], [ 104, 105, 106, 107], [1008, 1009, 1010, 1011]], [[ 22, 23, 24, 25], [ 116, 117, 118, 119], [1020, 1021, 1022, 1023]]]) # (2, 3, 4) + (2, 1, 1) >>> a + np.array([[[10]], [[100]]]) array([[[ 10, 11, 12, 13], [ 14, 15, 16, 17], [ 18, 19, 20, 21]], [[112, 113, 114, 115], [116, 117, 118, 119], [120, 121, 122, 123]]]) # (2, 3, 4) + (3, 4) >>> a + np.array([[1, 10, 100, 1000], [2, 20, 200, 2000], [3, 30, 300, 3000]]) array([[[ 1, 11, 102, 1003], [ 6, 25, 206, 2007], [ 11, 39, 310, 3011]], [[ 13, 23, 114, 1015], [ 18, 37, 218, 2019], [ 23, 51, 322, 3023]]]) # (2, 3, 4) + (2, 1, 4) >>> a + np.array([[[1, 10, 100, 1000]], [[2, 20, 200, 2000]]]) array([[[ 1, 11, 102, 1003], [ 5, 15, 106, 1007], [ 9, 19, 110, 1011]], [[ 14, 33, 214, 2015], [ 18, 37, 218, 2019], [ 22, 41, 222, 2023]]])
>>> a = np.array([1, 2, 3]) >>> a + 1 array([2, 3, 4]) >>> a + np.array(10) array([11, 12, 13])