728x90
import numpy as np
스칼라와 벡터
- 벡터와 행렬은 특정 텐서(tensor)를 부르는 이름
- 텐서의 이름을 부여하는 원칙은 차원인 축(axis)을 기준으로 지정
- 텐서가 0차원인 경우(축이 없는 경우) : 스칼라(scalar)
- 1차원인 하나의 축을 가진 경우: 벡터(vector)
- 2차원인 2개의 축을 가진 경우: 행렬(matrix)
- 3차원인 3개의 축을 가진 경우: 큐브(cube) 또는 3차원 텐서
- 더 차원이 높은 경우는 차원을 기준으로 n차원 텐서 라고 부름
스칼라
- 0차원 배열
- 크기를 표현
- 가장 기본적인 값
- 수학에서 배운 정수나 실수는 하나의 물리량인 크기를 표현하는데, 이 값을 스칼라 라고 함
scalar_arr = np.array(43)
# array에서 스칼라는 대괄호 없이 숫자만 표시
# 대괄호는 벡터(1차원 배열) 부터 사용
scalar_arr
array(43)
type(scalar_arr)
numpy.ndarray
# 스칼라는 0차원
scalar_arr.ndim
0
# 축이 없기 때문에 빈 튜플
scalar_arr.shape
()
# array로 스칼라를 만들어도 dtype을 가짐
scalar_arr.dtype
dtype('int32')
벡터
- 1차원 배열
vector = np.array([43])
vector
array([43])
type(vector)
numpy.ndarray
# 차원수
vector.ndim
1
# 데이터 개수
vector.shape
(1,)
배열 생성 함수
zeros
- 크기가 정해져 있고 모든 값이 0인 배열 생성
- 인수로는 배열의 크기를 전달
# 1차원 배열
zero_arr = np.zeros(5)
zero_arr
array([0., 0., 0., 0., 0.])
# 2차원 배열
zero_arr2 = np.zeros((2, 3))
zero_arr2
array([[0., 0., 0.],
[0., 0., 0.]])
- dtype 인수를 명시하면 해당 자료형 원소 배열을 생성
zero_arr3 = np.zeros((5, 2), dtype = int)
zero_arr3
array([[0, 0],
[0, 0],
[0, 0],
[0, 0],
[0, 0]])
ones
- 모든 값이 1인 배열 생성
one_arr = np.ones((2, 3, 4), dtype = int)
one_arr
array([[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]],
[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]])
zeros_like, ones_like
- 다른 배열과 같은 크기의 배열을 생성
zero_arr4 = np.zeros_like(one_arr)
zero_arr4
array([[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]],
[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]])
one_arr2 = np.ones_like(zero_arr3)
one_arr2
array([[1, 1],
[1, 1],
[1, 1],
[1, 1],
[1, 1]])
np.ones_like(zero_arr2)
array([[1., 1., 1.],
[1., 1., 1.]])
arange
- 파이썬의 range와 유사한 함수
- range와 같이 시작점, 종료점, 증감값을 인자로 전달
- 종료점은 필수
vector = np.arange(10)
vector
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
vector.dtype
dtype('int32')
인자로 실수를 지정할 수 있음
range(10.5, 20.5, 0.5)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[71], line 1
----> 1 range(10.5, 20.5, 0.5)
TypeError: 'float' object cannot be interpreted as an integer
vector1 = np.arange(10.5, 20.5, 0.5)
vector1
array([10.5, 11. , 11.5, 12. , 12.5, 13. , 13.5, 14. , 14.5, 15. , 15.5,
16. , 16.5, 17. , 17.5, 18. , 18.5, 19. , 19.5, 20. ])
vector1.dtype
dtype('float64')
# 1차원 배열을 생성하면서 바로 2차원 배열로 형상 변경
vector2 = np.arange(60).reshape(6, 10)
vector2
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, 24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59]])
vector2.shape
(6, 10)
vector3 = np.arange(60).reshape(3, 4, 5)
vector3
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, 24],
[25, 26, 27, 28, 29],
[30, 31, 32, 33, 34],
[35, 36, 37, 38, 39]],
[[40, 41, 42, 43, 44],
[45, 46, 47, 48, 49],
[50, 51, 52, 53, 54],
[55, 56, 57, 58, 59]]])
linspace
- arange와의 차이점
- 종료점도 포함해서 원소를 생성
- 세 번째 인자로 간격 대신 원소의 개수를 전달
- 초기값은 50
- 기본으로 실수를 가진 원소를 만듦
lin = np.linspace(1, 10, 10)
lin
array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.])
lin.dtype
dtype('float64')
# 값의 간격을 표시하는 증분(incremental)을 확인할 수 있음
lin2 = np.linspace(1, 2, 10, retstep = True)
lin2
(array([1. , 1.11111111, 1.22222222, 1.33333333, 1.44444444,
1.55555556, 1.66666667, 1.77777778, 1.88888889, 2. ]),
0.1111111111111111)
# 종료값을 제외할 수도 있음
lin3 = np.linspace(1, 10, 10, endpoint = False, retstep = True)
lin3
(array([1. , 1.9, 2.8, 3.7, 4.6, 5.5, 6.4, 7.3, 8.2, 9.1]), 0.9)
벡터의 크기 및 단위 벡터 구하기
- 선형대수의 벡터는 크기와 방향성을 가짐
- 벡터의 크기는 노름(norm)이라고 부름
- 벡터는 평면 좌표의 점을 표시하듯이 2개의 원소를 가진 것을 대표적으로 사용
- 벡터의 크기는 피타고라스의 정리를 사용
벡터의 크기 계산
# 두 개의 원소를 가지는 1차원 배열 생성
v = np.array([3, 4])
v
array([3, 4])
# 벡터의 크기를 구하기 위해 각 원소를 제곱하여 합산한 후 제곱근 계산
v_p = np.power(v, 2)
v_p
array([ 9, 16], dtype=int32)
v_r = np.sqrt(np.sum(v_p))
v_r
5.0
# 피타고라스 정리를 구하는 hypot 함수를 사용할 수도 있음
np.hypot(v[0], v[1])
5.0
# 더 많은 원소를 가진 벡터를 가지고 크기를 구할 때는 np.linalg.norm 함수를 사용하면 간단함
np.linalg.norm(v)
5.0
단위 벡터(unit vector)
- 벡터의 크기가 항상 1인 경우를 단위 벡터라고 함
- 표준 단위벡터(standard unit vector)는 원소 중에 하나가 1이고 나머지 원소가 0인 경우
# 표준 단위벡터의 예시
e1 = np.array([1, 0, 0])
print(np.linalg.norm(e1))
1.0
e2 = np.array([0, 1, 0])
print(np.linalg.norm(e2))
1.0
- 일반적인 단위 벡터를 구할 때는 벡터의 크기를 구하고 각 원소를 벡터의 크기로 나누어서 구함
# 1차원 배열을 생성하고 이 배열의 크기를 계산
v_3 = np.array([1, 2, 3])
v_3
array([1, 2, 3])
v_3_n = np.linalg.norm(v_3)
v_3_n
3.7416573867739413
# 해당 벡터를 벡터의 크기로 나눈 후에 norm을 계산하면 1이 나옴
# 벡터의 크기가 1인 경우를 단위 벡터라고 함
v_3_u = v_3 / v_3_n
v_3_u
array([0.26726124, 0.53452248, 0.80178373])
np.linalg.norm(v_3_u)
1.0
벡터 상등과 벡터간 거리
- 벡터의 상등(equality) : 벡터의 크기와 방향이 같은 경우
- 크기는 같지만 방향이 다른 경우는 상등이 아님
# 두 벡터가 동일한 경우
a = np.array([3, 4])
b = np.array([3, 4])
# np.array_equal() : 두 배열이 동일한지 확인하는 함수
np.array_equal(a, b)
True
# 동일한 두 개의 배열의 크기를 구하여 크기가 동일한지 비교
a_1 = np.linalg.norm(a)
b_1 = np.linalg.norm(b)
a_1 == b_1
True
b_2 = np.linalg.norm(-b)
b_2
5.0
a_1
5.0
# 방향은 반대지만 크기는 같음
a_1 == b_2
True
# 하지만 방향이 반대이기 때문에 동일한 벡터는 아님
np.array_equal(a, -b)
False
- 두 벡터의 거리는 두 벡터 간의 차를 계산한 후에 제곱을 합산한 후 제곱근 계산
# 두 개의 벡터 생성
c = np.arange(10, 13)
d = np.arange(0, 3)
c
array([10, 11, 12])
d
array([0, 1, 2])
np.sqrt(np.sum(np.square(c - d)))
17.320508075688775
# norm 함수에 두 벡터의 차를 인자로 전달하는 방법도 있음
np.linalg.norm(c-d)
17.320508075688775
행렬(Matrix)
- 벡터는 하나의 차원이 축을 가져서 1차원 배열로 표시했지만 행렬은 두 개의 축인 차원을 가짐
- 이 차원의 수평 방향을 행(row), 수직 방향을 열(column)이라고 함
- 보통 선형대수는 대괄호 내에 행과 열의 인덱스 위치에 숫자를 나열해서 표시
- 행렬을 부를 때는 보통 m개 행, n개 열로 이루어져서 m x n 행렬이라고 함
a = np.array([[43], [44]])
a
array([[43],
[44]])
type(a)
numpy.ndarray
# a 변수에 저장된 것도 하나의 배열이므로 하나의 자료형을 가짐
a.dtype
dtype('int32')
# 배열의 차원 확인
a.ndim
2
a.shape
(2, 1)
# np.full(형상, 채워질 값, 자료형) : 다차원 배열의 원소의 값을 동일하게 채움
b = np.full((3, 4), 7, "int64")
b
array([[7, 7, 7, 7],
[7, 7, 7, 7],
[7, 7, 7, 7]], dtype=int64)
2차원을 1차원으로 축소
x = np.array([[1, 4, 5],
[4, 5, 6],
[7, 8, 9]])
x
array([[1, 4, 5],
[4, 5, 6],
[7, 8, 9]])
# flatten() : 1차원 배열을 반환. 배열의 복사본을 반환
x.flatten()
array([1, 4, 5, 4, 5, 6, 7, 8, 9])
x
array([[1, 4, 5],
[4, 5, 6],
[7, 8, 9]])
# ravel() : 1차원 배열을 반환. 원본 배열의 뷰를 제공
x.ravel()
array([1, 4, 5, 4, 5, 6, 7, 8, 9])
x
array([[1, 4, 5],
[4, 5, 6],
[7, 8, 9]])
# flatten() 은 원본 배열에는 영향을 미치지 않음
np.may_share_memory(x.flatten(), x)
False
# ravel()은 원본 배열에 영향을 미칠 수 있음
np.may_share_memory(x.ravel(), x)
True
행렬의 종류
정사각행렬(Square Matrix)
- 동일한 행과 열을 가져서 n x n 행렬인 경우를 정사각행렬이라고 함
- 정사각행렬의 차수(order)가 n이면 n차 정사각행렬이라고 부름
행렬의 궤적(Trace)
- 정사각행렬은 가장 일반적인 행렬
- 정사각행렬의 행과 열의 동일한 인덱스에 있는 원소들은 대각선상에 위치함
- 이 대각선상의 원소들의 합을 행렬의 궤적(Trace)이라고 부름
- 행렬의 궤적은 정사각행렬의 전치를 사용해도 대각선의 원소는 변하지 않아 궤적의 합이 항상 동일
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
a
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
a.shape
(3, 3)
# np.trace() : 행렬의 궤적을 계산
np.trace(a)
15
a.trace()
15
대각행렬(Diagonal Matrix)
- 정사각행렬일 때 대각선의 원소(인덱스가 같은값)를 제외한 모든 원소가 0으로 구성되는 행렬을 대각행렬 이라고 함
b = np.array([[1, 0, 0],
[0, 3, 0],
[0, 0, 5]])
b
array([[1, 0, 0],
[0, 3, 0],
[0, 0, 5]])
# np.diagonal() : 대각선의 원소만 추출
b.diagonal()
array([1, 3, 5])
np.diagonal(b)
array([1, 3, 5])
대각행렬의 위치(diag)
- 대각행렬은 행과 열의 인덱스가 같을 때 대각선의 원소에 값을 넣어서 만드는데, 이 대각선을 주 대각선이라고 함
- 주 대각선 이외의 대각선의 위치는 주 대각선을 기준0으로 하고 상위는 양수로, 하위는 음수로 표시
# np.diag(1차원배열, 대각선의 위치) : 대각행렬 생성
# 1차원 배열을 대각선에 위치시킨 후, 행렬의 나머지는 0으로 채움
c = np.diag(np.arange(1, 4))
c
array([[1, 0, 0],
[0, 2, 0],
[0, 0, 3]])
# 주 대각선보다 한칸 위에 대각선을 구성
d = np.diag(np.arange(1, 4), k = 1)
d
array([[0, 1, 0, 0],
[0, 0, 2, 0],
[0, 0, 0, 3],
[0, 0, 0, 0]])
# 주 대각선보다 한칸 아래에 대각선을 구성
e = np.diag(np.arange(1, 4), k = -1)
e
array([[0, 0, 0, 0],
[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0]])
단위행렬(Unit Matrix)
- 대각행렬 중에 주 대각선의 원소가 모두 1인 행렬을 단위행렬이라고 부름
- 임의의 수에 1을 곱하면 임의의 수에 변화가 없는 것처럼 행렬에 다른 행렬곱을 수행해도 항상 동일한 행렬을 반환하는 행렬임
- 보통 단위 행렬은 대문자 I로 표시
# np.eye(행의 개수, 열의 개수) : 단위 행렬 만들기
h = np.eye(3, 3)
h
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
# np.eye() 메서드는 대각선의 위치를 조정할 수 있도록 매개변수 k를 제공
i = np.eye(3, 3, k = 1)
i
array([[0., 1., 0.],
[0., 0., 1.],
[0., 0., 0.]])
항등행렬(Identity Matrix)
- 단위행렬은 항등행렬 이라고도 부름
# 단위행렬을 만들어주는 함수
I = np.identity(3)
I
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
# 항등행렬을 다른 배열과 곱하면 배열의 값은 변경되지 않음
s = np.arange(1, 10).reshape(3, 3)
s
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
s @ I
array([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.]])
삼각행렬
- 정사각행렬에서 주 대각선을 기준으로 위나 아래의 원소의 값이 전부 0이고 나머지 부분에는 값이 들어있는 행렬을 삼각행렬(Triangular Matrix)라고 함
- 삼각행렬은 주 대각선을 기준으로 원소의 값이 들어간 위치에 따라 이름을 다르게 부여함
- 대각선 위 부분만 0이 아닌 원소로 구성하면 상삼각행렬(Upper triangular matrix)
- 주 대각선 아래 부분만 0이 아닌 원소로 구성하면 하삼각행렬(Lower triangular matrix)
a = np.arange(1, 10).reshape(3, 3)
a
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# np.tril(): 만들어진 행렬을 인자로 전달하면 하삼각행렬을 반환
np.tril(a)
array([[1, 0, 0],
[4, 5, 0],
[7, 8, 9]])
# np.tril()의 매개변수 k에 대각선의 위치를 이동하는 것도 가능
np.tril(a, k = -1)
array([[0, 0, 0],
[4, 0, 0],
[7, 8, 0]])
# np.triu(): 만들어진 행렬을 인자로 전달하면 상삼각행렬을 반환
np.triu(a)
array([[1, 2, 3],
[0, 5, 6],
[0, 0, 9]])
np.triu(a, k = 1)
array([[0, 2, 3],
[0, 0, 6],
[0, 0, 0]])
삼각행렬의 전치관계
- 삼각행렬의 전치관계는 하삼각행렬은 상삼각행렬로, 상삼각행렬은 하삼각행렬로 변함
b = np.triu(a)
b
array([[1, 2, 3],
[0, 5, 6],
[0, 0, 9]])
b.T
array([[1, 0, 0],
[2, 5, 0],
[3, 6, 9]])
c = np.tril(a)
c
array([[1, 0, 0],
[4, 5, 0],
[7, 8, 9]])
c.T
array([[1, 4, 7],
[0, 5, 8],
[0, 0, 9]])
- 상삼각행렬과 하삼각행렬의 동일 인덱스 요소의 곱은 주 대각선만 곱한 결과임
b * c
array([[ 1, 0, 0],
[ 0, 25, 0],
[ 0, 0, 81]])
대칭행렬(symmetric matrix)
- 주 대각선을 기준으로 아래의 원소와 위의 원소가 동일한 값을 가진 행렬
- 대칭행렬을 가지고 전치행렬을 만들어도 동일한 형태를 유지함
- 따라서 대칭행렬의 원소 간의 관계를 수식으로 표현하면 (aij)=(aji)
$(a_{ij}) = (a_{ji})$ (lateX(레이텍)으로 표시)
# 대칭행렬
x = np.array([[1, 2, 3],
[2, 3, 5],
[3, 5, 6]])
x
array([[1, 2, 3],
[2, 3, 5],
[3, 5, 6]])
# 대칭행렬의 전치행렬을 확인해도 동일함
x.T
array([[1, 2, 3],
[2, 3, 5],
[3, 5, 6]])
- 대칭 행렬과 해당 행렬의 전치행렬을 더하면 원소들의 값이 두 배로 변하지만 항상 대칭행렬임
- @ 연산을 해도 대칭행렬
x + x.T
array([[ 2, 4, 6],
[ 4, 6, 10],
[ 6, 10, 12]])
x @ x.T
array([[14, 23, 31],
[23, 38, 51],
[31, 51, 70]])
반 대칭행렬(Skew Symmetric Matrix)
- 주대각 성분을 기준으로 값은 같지만 부호가 반대의 원소를 가진 행렬
- 이 행렬과 전치행렬 간의 덧셈을 하면 전체 값이 0이 나옴
- 원소들이 대칭이지만 부호가 반대이므로 동일한 값을 빼는 것과 같음
y = np.array([[0, 2, -3],
[-2, 0, 5],
[3, -5, 0]])
y
array([[ 0, 2, -3],
[-2, 0, 5],
[ 3, -5, 0]])
y + y.T
array([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
# 전치행렬과 원 행렬에 부호를 변경하면 모든 원소는 동일한 값임
y.T == -y
array([[ True, True, True],
[ True, True, True],
[ True, True, True]])
# 반 대칭행렬과 이 행렬의 전치행렬 간의 뺄셈을 계산하면 반 대칭행렬을 그대로 유지함
y - y.T
array([[ 0, 4, -6],
[ -4, 0, 10],
[ 6, -10, 0]])
# 반 대칭행렬과 이 행렬의 전치행렬을 행렬곱 연산으로 계산하면 대칭행렬로 변경됨
y @ y.T
array([[ 13, -15, -10],
[-15, 29, -6],
[-10, -6, 34]])728x90
'06_Numpy' 카테고리의 다른 글
| Numpy(넘파이)_연습문제 (0) | 2025.03.11 |
|---|---|
| 01_넘파이(Numpy)_기초 (0) | 2025.03.10 |
| 넘파이(NumPy) documentation 확인 방법 (0) | 2025.03.10 |