컴퓨터그래픽스에서 왜 NumPy를 사용하는 가에 대해서는 이전 포스팅(클릭)을 참고하자.
Numpy array vs Python list
구분 | Numpy array | Python list |
type | 각 요소가 모두 같은 타입을 가져야 함 | 각 요소가 서로 다른 타입을 가질 수 있음. |
size | 각 요소가 모두 같은 크기를 가져야 함 | 각 요소가 서로 다른 크기를 가질 수 있음. |
비교 | 더 빠른 연산이 가능 |
사용
<pre>import numpy</pre>
Interpreter에서 다음과 같이 import함으로써 <pre>np</pre>을 통해 NumPy을 사용할 수 있다.
선언
기본 형태 : vector
가장 기본적인 형태는 다음과 같이 사용할 수 있다.
이는 1차원 배열의 형태로 vector라고도 한다.
<pre>a = np.array([0, 1, 2, 3])</pre>
다차원 배열
여러 차원의 배열은 아래와 같이 사용할 수 있다.
<pre>a = np.array([[0, 1, 2, 3], [10, 11, 12, 13]])</pre>
단, 각 row의 요소 개수(row의 column의 개수)가 같아야 한다.
만약 다를 경우, 각 row는 numpy의 ndarray가 아닌 python의 list로 선언이 된다.
다양한 선언 방법
- <pre>identity(n [, dtype])</pre>
- n*n의 2차원 matrix을 생성한다.
- 좌상우하 방향의 대각선 요소는 1이고, 나머지는 0이다.
- 기본 <pre>dtype</pre>은 float64이고, dtype을 지정해줄 수 있다.
- 예시 1
<pre>np.identity(4)</pre>
☞결과 :
array([[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]]) - 예시 2
<pre>np.identity(2, dtype=int)</pre>
☞결과 :
array([[1, 0],
[0, 1]])
- <pre>ones(size [, dtype])</pre>
- 모든 요소가 1인 배열을 생성할 수 있다. 배열의 크기는 size에 의해 결정된다.
- <pre>size</pre>
- 필수적으로 지정해줘야 한다.
- type : tuple이나 단일 숫자(scala)
- <pre>dtype</pre>의 default는 float64이다.
- 예시 1
<pre>np.ones(2)</pre>
☞결과 :
array([1., 1.]) - 예시 2
<pre>np.ones((2, 3), dtype=int)</pre>
☞결과 :
array([[1, 1, 1],
[1, 1, 1]])
- <pre>zeros(size [, dtype])</pre>
- 모든 요소가 0인 배열을 생성할 수 있다. 배열의 크기는 size에 의해 결정된다.
- <pre>size</pre>
- 필수적으로 지정해줘야 한다.
- type : tuple이나 단일 숫자(scala)
- <pre>dtype</pre>의 default는 float64이다.
- 예시 1
<pre>np.zeros(2)</pre>
☞결과 :
array([0., 0.]) - 예시 2
<pre>np.zeros((2, 3), dtype=int)</pre>
☞결과 :
array([[0, 0, 0],
[0, 0, 0]])
- <pre>linspace(start, stop, cnt)</pre>
- start부터 stop까지 균등하기 나눠서 cnt개의 요소를 가진 배열을 생성한다.
- stop는 포함된다.
- 예시
<pre>np.linspace(0, 1, 5)</pre>
☞결과 :
array([0. , 0.25, 0.5 , 0.75, 1. ])
- <pre>arange([start,], stop [,step], dtype)</pre>
- start부터 stop까지 균등하기 나눠서 cnt개의 요소를 가진 배열을 생성한다.
- stop는 포함되지 않는다.
- non-integer step을 사용할 경우 finit machine precision으로 인해 결과가 일정하지 않다. 따라서 non-integer step일 경우, <pre>linspace()</pre>을 사용하는 것이 더 낫다.
- 예시 1
<pre>np.arange(4)</pre>
☞결과
array([0, 1, 2, 3]) - 예시 2
<pre>np.arange(1.5, 2.1, 0.3)</pre>
☞결과
array([1.5, 1.8, 2.1])
연산
<pre>+, -, *, /, **, @</pre> 등의 연산을 지원한다.
<pre>+, -, *, /</pre>
- 기존의 배열에서 각 요소별 연산을 수행한다.
- Matrix와 vector의 곱에서도 각 요소끼리만 곱해진다.(dot product 수행 아님)
- 예시1
<pre>a = np.array([1, 2, 3, 4])
b = np.array([2, 3, 4, 5])
a + b
</pre>
결과 : <pre>[3, 5, 7, 8]</pre> - 예시2
<pre>M = np.array([[0, 1], [2, 3]])
print(M * M)
</pre>
결과 : [[0, 1], [4, 9]]] - 예시3
<pre>M = np.array([[0, 1], [2, 3]])
v = np.array([0, 1])
print(M * v)
</pre>
<pre>**</pre>
- 각 요소마다 거듭제곱을 실시한다.
- 예시
<pre>a = np.array([1, 2, 3, 4])
b = np.array([2, 3, 4, 5])
a ** b
</pre>
결과 : <pre>[1, 8, 81, 1024]</pre>
<pre>@</pre>
- dot product를 수행한다.
- vector의 경우 연산 가능성에 따라 가로/세로가 결정된다.
- 예시
<pre>M = np.array([[0, 1], [2, 3]])
v = np.array([0, 1])
print(M @ v)
</pre>
결과 : <pre>[1, 3]</pre>
☞ 원래는 (2*2)와 (1*2) 이기 때문에 계산을 하지 못하지만 numpy는 v를 (2*1)로 바꾸어 생각해서 연산이 가능해진다.
접근(Get, Set)
접근
각 요소의 접근은 C와 유사하게 할 수 있다.
단, 파이썬의 경우 negative index도 지원하기 때문에 편의성이 높다.
negative index
처음부터 0으로 접근할 수도 있지만, 끝에서부터 -1로 접근할 수도 있다.
예시
<pre>a = np.array([1, 2, 3, 4])
a[0] = 10
print(a)
print(-1)
</pre>
☞ 결과
[10, 1, 2, 3]
4
다차원 배열에 접근은 여러 방법이 있다.
<pre>a = np.array([[0, 1, 2, 3], [10, 11, 12, 13]])
print(a[0][0]) #결과 : 0 (C style)
print(a[0, 0]) #결과 : 0 (Python style)
</pre>
두 개의 결과는 동일하지만 연산 등에서는 속도 차이는 아래의 python style이 더 빠르다.
Type 확인
array을 담고 있는 변수의 타입 확인은 다음과 같이 한다.
<pre>type(a) // 결과 : numpy.ndarray</pre>
array의 요소의 타입은 다음과 같이 한다.
<pre>a.dtype // 결과 : dtype('int64')</pre>
이 결과가 dtype('int32') 와 같이 나올 수도 있다. int32는 4바이트, int54는 8바이트라는 차이가 있다.
배열 정보 확인
- Diemsion 확인(차원 확인)
- <pre>a.ndim</pre> : 배열이 몇 차원인지 확인한다.
- 예시
<pre>a = np.array([0, 1, 2, 3]) // a.ndim : 1
a = np.array([[0, 1, 2, 3], [10, 11, 12, 13]]) // a.ndim : 2
</pre>
- 요소 개수(Element count)
- <pre>a.size</pre> : 전체 요소의 개수를 확인한다.
- 예시
<pre>a = np.array([[0, 1, 2, 3], [10, 11, 12, 13]])
print(a.size)
</pre>
결과 : 8
- <pre>a.size</pre> : 전체 요소의 개수를 확인한다.
- Row, Column 수
- <pre>shape</pre> : 배열의 모양(row * column)을 확인한다.
- 결과는 tuple(순서쌍)으로 나타난다. 3차원 배열의 경우 (x, y, z)의 형태로 나타난다.
- 예시
row = 2, column = 4 인 배열의 경우 (2, 4)로 나타난다.
<pre>a = np.array([[0, 1, 2, 3], [10, 11, 12, 13]])
print(a.shape)
</pre>
결과 : (2, 4)
- <pre>shape</pre> : 배열의 모양(row * column)을 확인한다.
Slicing
사용
<pre>var[lower:upper:step]</pre>
시작 index(lower), 끝 index(upper), 단계(step)을 지정하여 slicing 할 수 있다.
단, upper-bound element는 포함되지 않는다.
예시
<pre># [10, 11, 12, 13, 14, 15]
print(a[1:3])</pre>
☞ 결과 : [11, 12]
<pre>print(a[1:-2])</pre>
☞ 결과 : [11, 12, 13]
<pre>print(a[1:5:2])</pre>
☞ 결과 : [11, 13]
다차원 배열의 연산
Transpose
- 대각선으로 기준으로 요소를 뒤집는다.
- 사용 : <pre>a.T</pre> 혹은 <pre>a.transpose()</pre>
- 원본에 영향을 주지 않는다.
- 예시
<pre>a = np.array([[0, 1, 2, 3], [10, 11, 12, 13]])
print(a.T) # 혹은 print(a.transpose())
</pre>
☞결과
array([[ 0, 10],
[ 1, 11],
[ 2, 12],
[ 3, 13]])
☞ cf. 원래 a의 모습
array([[ 0, 1, 2, 3],
[10, 11, 12, 13]])
Reshape
- 배열의 모양을 바꾼다. 단, 요소의 순서는 그대로 유지된다.
- 원본에는 영향을 주지 않는다.
- 전체 사이즈는 전과 후가 동일해야한다. reshape한 것의 요소의 개수가 기존의 요소의 개수와 다르면 에러를 발생시킨다.
- 예시
<pre>a = np.array([[0, 1, 2], [3, 4, 5]])
a.reshape(3, 2)
</pre>
☞결과
array([[0, 1],
[2, 3],
[4, 5]])
참고
본 포스트는 한양대학교 이윤상 교수님의 수업을 정리한 내용입니다.
출처: 한양대학교 이윤상 교수님 컴퓨터그래픽스 강의 강의자료 - https://cgrhyu.github.io/courses/2022-spring-cg.html
CGR LAB
Computer Graphics - 2022 Spring Instructor: Yoonsang Lee Teaching Assistant: Chaejun Sohn Undergraduate Mentor: Bokyoung Jang Time / Location: Mon 09:00-11:00 / Online (originally 207 IT.BT Building) - Lab Wed 09:00-11:00 / 508 IT.BT Building - Lecture Cou
cgrhyu.github.io
'Computer Science > Computer Graphics' 카테고리의 다른 글
[GLFW] Input handling (0) | 2021.03.13 |
---|---|
[OpenGL] Vertex의 기본 (0) | 2021.03.12 |
[OpenGL] OpenGL이란? (0) | 2021.03.10 |
[GLFW][실습] import GLFW 에러 해결 방법 (Failed to load GLFW3 shared library.) (0) | 2021.03.09 |
컴퓨터그래픽스와 도구 (0) | 2021.03.08 |
댓글