세미나

세미나

Seminar

220404

Classification strategies in machine learning techniques predicting regime changes and durations in the Lorenz system

Google Drive

원드라이브

축약 가능 공간

Contractible Space



누적 평균 공식

Cummulative Average Formula

주어진 샘플 $x_{1} , \cdots , x_{n}$ 의 표본평균이 $y_{n}$ 이라면, 샘플 $x_{n+1}$ 가 새로이 주어졌을 때 전체의 표본평균 $y_{n+1}$ 은 다음과 같다. $$ y_{n+1} := {{ n } \over {n + 1}} y_{n} + {{1} \over {n+1}} x_{n+1} $$

설명

누적 평균Cummulative Average이동 평균Moving Average러닝 애버리지Running Average라 불리기도 한다.

누구나 초중학교 시절 한번쯤 해볼 수 있는 실수인데, 필자는 채점을 하면서 중간에 미리 구해놓은 평균을 그냥 나머지 과목에다 때려넣고 평균을 내곤 했다.(이 당시엔 내가 훗날 통계학과에 진학할 거라곤 꿈에도 몰랐다.) 이를테면 국어, 영어가 각각 90, 80점이고 아직 수학을 매기지 않았다고 하자. 이 시점에서 내 평균은 $$ y_{2} = (90+80)/2 = 85 $$ 인데, 수학을 70점 받았다면 전체 평균은 $$ y_{3} = (90+80+70)/3 = 80 $$ 이어야하는데 그냥 $$ (85 + 70)/2 = 77.5 $$ 점으로 계산하는 식이었다. 정확히 이유는 모르겠지만, 전체를 다 더하고 나누는 것과 그냥 계속 한과목씩 때려넣어서 평균을 구하는 방법에는 차이가 있다는 걸 안 뒤론 늘 기존의 결과를 버리고 처음부터 다 더하고 나누었던 것 같다. 포스트에서 소개된 공식은 정확히 그 바보짓을 막을 수 있는 방법이다. 다시 숫자를 풀어헤쳐서 계산할 게 아니라 그냥 기존 평균과 새 데이터에 $n, 1$ 를 곱하는 가중 평균Weighted Average를 구하면 된다.

별것 아닌 것처럼 보이지만 의외로 많은 비전공자들이 이 공식을 모르고 비슷한 실수를 저지르며, 데이터 스트림Data Stream과 같은 걸 다루는 인공지능 분야 등에서 아무런 설명 없이 갑자기 등장하기도 한다. 이 때 누적 평균 공식의 역할은 주로 새로운 데이터가 주어졌을 때 효율적으로 학습에 관련된 수치를 업데이트하는 것이다.

유도

$$ \begin{align*} y_{n+1} =& {{ x_{1} + \cdots + x_{n} + x_{n+1} } \over {n + 1}} \\ =& {{ n {{x_{1} + \cdots + x_{n}} \over {n}} + x_{n+1} } \over {n + 1}} \\ =& {{ n y_{n} + x_{n+1} } \over {n + 1}} \end{align*} $$



줄리아에서 2차원 배열과 행렬 간 전환하는 법 [eachrow(M)...], hcat(A...)

How to Convert between 2d Array and Matrix in julia

개요 1

줄리아에서 2차원 배열과 행렬 사이를 전환하는 팁을 소개한다. 아마 줄리아 1.7 이하의 환경에서는 가장 줄리아다운 구현이면서 간단하고, 빠르고, 아름다운 방법일 것이다.

코드

여기서 소개된 방법이 아니라도 행렬과 2차원 배열을 넘나드는 방법은 무수히 많다. 막코딩을 하든 뭘하든 목표자체가 어렵지 않기 때문이다. 글을 제대로 읽으려면 단순히 목표만 신경쓸 게 아니라 줄리아 특유의 문법이 어떻게 쓰였는지를 고민하면서 보는 게 좋다.

행렬을 2차원배열로

julia> M = rand(0:9, 3, 10)
3×10 Matrix{Int64}:
 2  4  0  1  8  0  9  2  5  7
 5  2  1  5  4  3  7  2  7  3
 7  8  1  9  0  3  2  4  1  3

위와 같은 행렬을 2차원 배열로 바꿔보자.

julia> [eachrow(M)...]
3-element Vector{SubArray{Int64, 1, Matrix{Int64}, Tuple{Int64, Base.Slice{Base.OneTo{Int64}}}, true}}:
 [2, 4, 0, 1, 8, 0, 9, 2, 5, 7]
 [5, 2, 1, 5, 4, 3, 7, 2, 7, 3]
 [7, 8, 1, 9, 0, 3, 2, 4, 1, 3]

julia> [eachcol(M)...]
10-element Vector{SubArray{Int64, 1, Matrix{Int64}, Tuple{Base.Slice{Base.OneTo{Int64}}, Int64}, true}}:
 [2, 5, 7]
 [4, 2, 8]
 [0, 1, 1]
 [1, 5, 9]
 [8, 4, 0]
 [0, 3, 3]
 [9, 7, 2]
 [2, 2, 4]
 [5, 7, 1]
 [7, 3, 3]

eachrow()eachcol()는 행렬의 행과 열 단위로 한 줄씩 뽑아주는 생성자Generator를 리턴하고2 스플랫 오퍼레이터를 통해 이들을 가변 배열로 취급해서3 각괄호 [] 안에 넣어주면 자연스럽게 배열이 된다.

2차원배열을 행렬로

julia> A = [rand(0:9,3) for _ in 1:10]
10-element Vector{Vector{Int64}}:
 [5, 4, 9]
 [9, 7, 6]
 [9, 9, 6]
 [5, 9, 0]
 [0, 2, 8]
 [3, 9, 5]
 [1, 6, 0]
 [5, 7, 7]
 [1, 3, 5]
 [5, 4, 1]

위와 같은 2차원 배열을 행렬로 만들어보자.

julia> hcat(A...)
3×10 Matrix{Int64}:
 5  9  9  5  0  3  1  5  1  5
 4  7  9  9  2  9  6  7  3  4
 9  6  6  0  8  5  0  7  5  1

julia> hcat(A...)'
10×3 adjoint(::Matrix{Int64}) with eltype Int64:
 5  4  9
 9  7  6
 9  9  6
 5  9  0
 0  2  8
 3  9  5
 1  6  0
 5  7  7
 1  3  5
 5  4  1

julia> vcat(A...)
30-element Vector{Int64}:
 5
 4
 9
 9
 7
 6
 9
 9
 ⋮
 7
 1
 3
 5
 5
 4
 1

배열을 병합하는 hcat() 함수를 사용하면 된다. 4 기본적으로 hcat()vcat()폴드 함수이면서 가변 인자 함수기 때문에 마찬가지로 스플랫 오퍼레이터를 통해 2차원 배열의 원소인 1차원 배열들을 직접 인자로써 전달해야한다.

전체 코드

# matrix to 2d array

M = rand(0:9, 3, 10)

[eachrow(M)...]
[eachcol(M)...]

# 2d array to matrix

A = [rand(0:9,3) for _ in 1:10]

hcat(A...)
hcat(A...)'
vcat(A...)

환경

  • OS: Windows
  • julia: v1.7.0

  1. https://discourse.julialang.org/t/plots-efficient-scatter-plot-of-a-2xn-array/31803/6 ↩︎

  2. https://docs.julialang.org/en/v1/base/arrays/#Base.eachcol ↩︎

  3. https://docs.julialang.org/en/v1/base/base/#… ↩︎

  4. https://docs.julialang.org/en/v1/base/arrays/#Base.cat ↩︎

댓글