벡터를 파이썬으로 표현하기

벡터를 파이썬으로 표현하는 다양한 방법이 있다. 리스트를 쓸 수도 있고, 튜플을 쓸 수도 있고, 딕셔너리를 사용할 수도 있다.

vector_a = [1, 2, 10]
vector_b = (1, 2, 10)
vector_c = {'x': 1, 'y': 1, 'z': 10}

가장 보편적인 방법은 리스트를 사용하는 것이다.


벡터의 계산

벡터의 합을 구현하는 가장 단순한 방법은 다음과 같다.

>>> u = [2, 2]
>>> v = [2, 3]
>>> z = [3, 5]
>>> result = []
>>> for i in range(len(u)):
...     result.append(u[i] + v[i] + z[i])
... 
>>> print(result)
[7, 10]

그러나 위 코드는 파이썬스럽지 못하다. 더 제대로 된 코드를 보자.

>>> u = [2, 2]
>>> v = [2, 3]
>>> z = [3, 5]
>>> result = [sum(t) for t in zip(u, v, z)]
>>> print(result)
[7, 10]

어떤가? List comprehension, zip()을 사용해서 더 파이썬스럽게 구현했다. 덜 복잡하고, 제3자가 봐도 그 원리를 이해하기 쉽다.

스칼라 값이 곱해지는 경우도 크게 다르지 않다.

>>> u = [2, 2]
>>> v = [2, 3]
>>> z = [3, 5]
>>> alpha = 2   # 스칼라 값 지정
>>> result = [alpha * sum(t) for t in zip(u, v, z)]
>>> print(result)
[14, 20]


행렬을 파이썬으로 표현하기

행렬 역시 리스트, 튜플, 딕셔너리로 표현할 수 있다. 특히, 딕셔너리로 표현하는 방법은 무궁무진하다.

matrix_a = [[3, 6], [4, 5]]
matrix_b = [(3, 6), (4, 5)]
matrix_c = {(0, 0): 3, (0, 1): 6, (1, 0): 4, (1, 1): 5}

가장 기본적인 방법인 이중 리스트를 사용해보자.


행렬의 계산

행렬을 더하는 계산은 아래와 같이 구현할 수 있다.

>>> matrix_a = [[3, 6], [4, 5]]
>>> matrix_b = [[5, 8], [6, 7]]
>>> result = [[sum(row) for row in zip(*t)] for t in zip(matrix_a, matrix_b)]
>>> print(result)
[[8, 14], [10, 12]]

차근차근 이해해보자. 먼저 zip(matrix_a, matrix_b)를 통해 matrix_amatrix_b의 요소(행)들이 각각 하나씩 나와 t에 묶이게 된다(([3, 6], [5, 8]), ([4, 5], [6, 7])). 그리고 그 t는 다시 list comprehension 안에 들어가서 for문을 돈다. t의 각 요소(행)들은 *에 의해 unpack이 되며, 그 행이 zip을 통해 각 위치에 맞게 더해진다.

전치(transpose)를 구현하는 방법도 있다.

>>> matrix_a = [[1, 2, 3], [4, 5, 6]]
>>> result = [[element for element in t] for t in zip(*matrix_a)]
>>> print(result)
[[1, 4], [2, 5], [3, 6]]

먼저, matrix_a의 요소(행)들이 *에 의해 unpack되고, zip에 의해 t에 하나씩 묶인다. 묶인 결과는 (1, 4), (2, 5), (3, 6)일 것이다. 그리고 그 t들이 list comprehension으로 들어가서 리스트가 된다.

마지막으로 획기적인 행렬 곱셉을 살펴보자. List comprehension과 zip(), 별표를 잘 사용하면 기가 막힌 행렬 곱셈 코드가 탄생한다.

>>> matrix_a = [[1, 1, 2], [2, 1, 1]]
>>> matrix_b = [[1, 1], [2, 1], [1, 3]]
>>> result = [[sum(a * b for a, b in zip(row_a, column_b)) for column_b in zip(*matrix_b)] for row_a in matrix_a]
>>> print(result)
[[5, 8], [5, 6]]

가장 기본적인 행렬 곱셈 방식(행 $\times$ 열)을 구현하였다. 코드가 길지만 가장 집중해야할 포인트는 ‘행으로 표현된 matrix_b에서 어떻게 열을 추출하는가?이다. 그냥 반복문으로 구현했으면 머리가 터질 부분을 zip과 *가 완벽하게 구현하는 것(for column_b in zip(*matrix_b))을 확인할 수 있다.



별도의 출처 표시가 있는 이미지를 제외한 모든 이미지는 강의자료에서 발췌하였음을 밝힙니다.

댓글남기기