logo

줄리아, 파이썬(넘파이, 파이토치) 배열 차원의 차이점 📂줄리아

줄리아, 파이썬(넘파이, 파이토치) 배열 차원의 차이점

개요

줄리아와 넘파이, 파이토치(이하 이 둘을 퉁쳐서 그냥 파이썬이라고 하겠다)의 고차원 배열을 다룰 때 각 차원이 의미하는 바가 다르므로 주의를 요한다. 이러한 차이는 줄리아의 배열은 열우선이고, 파이썬의 배열은 행우선이기 때문에 나타난다. 참고로 같은 열우선인 매트랩은 줄리아와의 차이점이 없으므로 매트랩에 익숙한 사용자는 딱히 조심해야할 필요가 없겠지만, 파이썬에 익숙한 사람들은 인덱싱 실수를 하지않게 주의하자.

  • 배열의 차원과 벡터의 차원을 혼용해서 쓰고 있으니 찰떡같이 알아먹도록 하자.

설명

1차원 배열

줄리아에서 크기가 $n$인 배열은 $n$차원 열벡터를 의미한다.

julia> ones(3)
3-element Vector{Float64}:
 1.0
 1.0
 1.0

파이썬에서 크기가 $n$인 배열은 $n$차원 행벡터를 의미한다.

>>> import numpy as np
>>> np.ones(3)
array([1., 1., 1.])

열이냐 행이냐의 차이는 있지만, 1차원 배열이기 때문에 인덱싱에서 딱히 주의해야할 점은 없다.

2차원 배열

2차원까지는 겉으로 봤을 땐 다르지 않아보인다. 하지만 그 의미는 다르니 주의가 필요하다. 우선 줄리아에서는 배열의 차원이 뒤쪽으로 늘어난다. 이게 무슨말인가하면 $(m,n)$ 배열이라고 하면, 크기가 $m$인 1차원 배열(열벡터)이 $n$개 있다는 것이다. 구체적으로 $(3,2)$ 배열은 3차원 열벡터가 2개 있다는 뜻이다.

julia> ones(3,2)
3×2 Matrix{Float64}:
 1.0  1.0
 1.0  1.0
 1.0  1.0

또한 줄리아는 '열우선'이므로 성분의 인덱스는 위에서 아래로 먼저, 그리고 왼쪽에서 오른쪽으로 커진다.

julia> A = reshape(range(1,6), (3,2))
3×2 reshape(::UnitRange{Int64}, 3, 2) with eltype Int64:
 1  4
 2  5
 3  6

julia> for i ∈ 1:6
           println(A[i])
       end
1
2
3
4
5
6

반면에 파이썬 배열의 새로운 차원은 앞쪽으로 늘어난다. 다시말해 $(m,n)$ 배열이라고 하면, 크기가 $n$인 1차원 배열(행벡터)이 $m$개 있다는 것이다. 아래의 결과를 보면 배열이 행단위로 구분되어있는 것을 알 수 있다.

>>> np.ones([3,2])
array([[1., 1.],
       [1., 1.],
       [1., 1.]])

즉 겉으로만 봤을 땐 줄리아와 파이썬에서 $(m,n)$ 배열은 모두 $m \times n$ 행렬이나, 열우선/행우선의 차이 때문에 인덱스의 순서가 달라진다. 인덱스 방향은 줄리아에서는 상하좌우, 파이썬에서는 좌우상하이다.

# julia에서 2차원 배열의 인덱싱은 위에서 아래로, 그 다음 좌에서 우로
julia> A = reshape(range(1,6), (3,2))
3×2 reshape(::UnitRange{Int64}, 3, 2) with eltype Int64:
 1  4
 2  5
 3  6

# python에서 2차원 배열의 인덱싱은 좌에서 우로, 그 다음 위에서 아래로 
>>> np.arange(6).reshape(3,2)
array([[0, 1],
       [2, 3],
       [4, 5]])

3차원 배열

줄리아에서는 배열의 새로운 차원이 뒤로 추가된다고 했다. 따라서 $(m,n,k)$ 배열은 $(m,n)$ 배열이 $k$개 있는 것이다.

julia> ones(3,2,4)
3×2×4 Array{Float64, 3}:
[:, :, 1] =
 1.0  1.0
 1.0  1.0
 1.0  1.0

[:, :, 2] =
 1.0  1.0
 1.0  1.0
 1.0  1.0

[:, :, 3] =
 1.0  1.0
 1.0  1.0
 1.0  1.0

[:, :, 4] =
 1.0  1.0
 1.0  1.0
 1.0  1.0

반면에 파이썬에서 $(m,n,k)$ 배열은 $(n,k)$ 배열이 $m$개 있는 것이다.

>>> np.ones([3,2,4])
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.]]])

머신러닝에서

이미지 데이터에서 $H=\text{hieht}$를 세로, $W=\text{width}$를 가로 $C=\text{channel}$를 채널 수, $B=\text{batch size}$를 배치사이즈라고 하면, 파이토치에서는 $(B,C,H,W)$ 배열이고, 줄리아에서는 $(H,W,C,B)$이다.

환경

  • OS: Windows11
  • Version: Julia 1.7.1, Python 3.9.2, numpy 1.19.5