벡터화 연산
NumPy가 지원하는 벡터화 연산을 사용하면 반복문을 명시적으로 사용하지 않아도 배열의 모든 원소에 대한 반복 연산을 할 수 있다. 이로 인해 선형 대수 공식과 동일한 형태로 Python 코드를 작성할 수 있게 된다.
선형 대수에서 두 벡터의 합은 다음과 같이 구한다.
$$
x = \begin{bmatrix}1 \\ 2 \\ 3 \\ \vdots \\ 10000 \end{bmatrix}, \;\;\;\;
y = \begin{bmatrix}10001 \\ 10002 \\ 10003 \\ \vdots \\ 20000 \end{bmatrix},
$$
일 때, 두 벡터의 합
$$ z = x + y $$
은 다음과 같이 구한다.
$$
\begin{bmatrix}1 \\ 2 \\ 3 \\ \vdots \\ 10000 \end{bmatrix} +
\begin{bmatrix}10001 \\ 10002 \\ 10003 \\ \vdots \\ 20000 \end{bmatrix}
= \begin{bmatrix}1+10001 \\ 2+10002 \\ 3+10003 \\ \vdots \\ 10000+20000 \end{bmatrix}
= \begin{bmatrix}10002 \\ 10004 \\ 10006 \\ \vdots \\ 30000 \end{bmatrix}
$$
만약 벡터화 연산을 사용하지 않으면 반복문 또는 리스트 컴프리헨션을 사용해 연산해야한다.
%%time # 셀 코드의 실행 시간을 측정하는 IPython Magic 명령
z = np.array([x[i] + y[i] for i in range(10000)])
z
실행 결과
CPU times: total: 0 ns
Wall time: 2 ms
array([10002, 10004, 10006, ..., 29996, 29998, 30000])
벡터화 연산을 사용하면 단순 덧셈 연산으로 해결할 수 있다.
%%time
z = x + y
z
실행 결과
CPU times: total: 0 ns
Wall time: 0 ns
array([10002, 10004, 10006, ..., 29996, 29998, 30000])
벡터화 연산을 사용하지 않았을 때와 사용했을 때의 결과는 동일하지만, 실행 속도는 벡터화 연산을 사용한 것이 더 빠르다. 벡터화 연산은 사칙 연산 뿐만 아니라 논리 연산, 지수 함수, 로그 함수도 지원한다.
a == b
a >= b
np.exp(a)
10 ** a
np.log(a + 1)
배열의 각 원소를 일일히 비교하는 게 아니라 배열의 모든 원소가 다 같은지 알고 싶다면 numpy.all 함수를 사용하면 된다.
a = np.array([1, 2, 3, 4])
b = np.array([4, 2, 2, 4])
c = np.array([1, 2, 3, 4])
np.all(a == b), np.all(a == c)
실행 결과
(False, True)
스칼라와 벡터/행렬의 곱셈
스칼라와 벡터/행렬의 곱셈도 선형 대수에서 사용하는 식과 동일하게 코딩한다.
x = np.arange(10)
100 * x
실행 결과
array([ 0, 100, 200, 300, 400, 500, 600, 700, 800, 900])
브로드캐스팅
벡터, 행렬끼리 덧셈, 뺄셈 연산을 하기 위해서는 두 벡터, 행렬의 크기가 같아야 하지만 NumPy에서는 브로드캐스팅(broadcasting)이라는 기능을 이용해 서로 다른 크기를 가진 두 배열을 사칙연산할 수 있다. 브로트캐스팅은 크기가 작은 배열을 자동으로 반복 확장하여 크기가 큰 배열에 맞추는 방법이다.
예로 들어 다음과 같은 벡터와 스칼라의 덧셈 연산을 하는 경우가 있다고 하자.
$$
x = \begin{bmatrix}0 \\ 1 \\ 2 \\ 3 \\ 4 \end{bmatrix}, \;\;\;\;
x + 1 = \begin{bmatrix}0 \\ 1 \\ 2 \\ 3 \\ 4 \end{bmatrix} + 1 = ?
$$
브로드캐스틴은 스칼라를 벡터와 같은 크기로 확장시켜 연산하는 것이다.
$$
\begin{bmatrix}0 \\ 1 \\ 2 \\ 3 \\ 4 \end{bmatrix} + 1 =
\begin{bmatrix}0 \\ 1 \\ 2 \\ 3 \\ 4 \end{bmatrix} + \begin{bmatrix}1 \\ 1 \\ 1 \\ 1 \\ 1 \end{bmatrix} =
\begin{bmatrix}1 \\ 2 \\ 3 \\ 4 \\ 5 \end{bmatrix}
$$
x = np.arange(5)
x
x + 1
실행 결과
array([0, 1, 2, 3, 4])
array([1, 2, 3, 4, 5])
브로드캐스팅은 차원이 더 높은 경우에도 적용할 수 있다.
참고 문서