프로그램을 만들다 보니 별걸 다 하게 되는 상황이다. (납땜하다가 사포질하다가 왜 프로그래밍이냐면, 웃지요 -_-; 내 일이 원래 그렇다. 뭐든지 다 하는...)

실험 결과를 분석하는 프로그램인데, 분석은 별게 아니라 입력값의 평균과 표준편차(분산의 제곱근)를 계산하는 프로그램이다. 문제는 입력값을 적절히 구분해야 한다는 점이다. 즉, 지금 읽어온 입력값이 마지막 값이 아닐 수도 있다는 것이 문제점이다. 원래는 다음과 같이 프로그램을 설계해야 한다.

항목이 여러개 있다. A샘플, B샘플 ...
각 샘플마다 실험 측정값이 있다. 1번, 2번, ...
당연히 각 샘플마다 평균과 분산을 구해야 한다. 문제는 샘플이 순서대로 정렬되어 있지 않고 뒤섞여 있다는 점이다.

1. 샘플을 순서대로 정렬한다.
2. DB에 넣어서 Group by로 묶은 후 평균과 분산을 구한다.

알고리즘은 이게 가장 단순한데 실제 구현은 삽질이다. 왜냐하면 난 VB.net에서 개발을 하려고 하고 있고, 여기서 DB를 쓰려면 MSSQL을 쓰든가 전에 여기서 언급했던 SQLite의 VB 포트를 쓰든가 해야 하는데, 어쨌거나 SQL까지 다루는 건 골치아픈 일이다. 따라서 저 정렬 부분을 직접 구현해야 하나 하는 고민이 들다가 귀찮으니까 그러지 말자고 생각했다.

1. 데이터 테이블을 싹 읽어서 샘플이 어떤 종류가 있는지 목록을 만든다.
2. 목록에서 순서대로 읽어다가 평균과 분산을 구한다. 즉, 데이터 테이블을 읽으면서 A샘플 값만 골라서 평균과 분산을 구하고, 데이터 테이블을 또 읽으면서 B샘플 값만 골라서 구하고 ... 끝날때까지 반복.

그나마 조금 단순하지만 데이터 테이블을 너무 여러번 읽는다. 더군다나, 항목 구분이 샘플로만 이뤄지는게 아니라 실험 날짜와 샘플의 위치에 따라서도 달라진다. 즉, 같은 샘플이라도 다른 날짜라면 따로 분석해야 하고, 다른 위치라고 해도 따로 분석해야 한다. 이러면 항목 구분 목록을 여러개 만든 후 각각의 목록을 이용해서 모든 경우의 수를 다 따지는 루틴을 넣어야 하는데 이건 다시 삽질이다.

그래서

1. 데이터 테이블에서 한줄을 읽어온다.
2. 기존에 없던 항목 구분이면? 새로 항목 구분을 만들어 주고 데이터 분석을 갱신한다
2. 기존에 있던 항목 구분이면? 해당 항목 구분에 데이터 분석을 갱신한다
3. 끝까지 간다.

여기에 데이터 분석을 갱신하는 루틴이 추가되는데 이게 조금 수학적이다. 그래서 이 글은 수학에 구분되어 있다.

지금까지 N개의 자료를 이용해서 평균과 분산을 계산했다고 하자. 이걸 $m$과 $\sigma^2$라고 하자. 그런데 여기에 N+1번째 자료인 $x_{N+1}$가 새로 들어왔다. 어쩌지?

새로운 평균 $m'$은 다음과 같이 구할 수 있다. (왜 그런가는 암산으로 해보자.)
$m' = \frac{mN+x_{N+1}}{N+1}$

그리고 새로운 분산 $\sigma ' ^2$은 다음과 같이 구할 수 있다. 왜 그런가는 직접 계산해 보자.

$\sigma ' ^2= \frac{N(\sigma ^2 + m^2) + x_{N+1}^2}{N+1} - m'^2$

어쨌든 위와 같은 간단한 계산으로 자료가 추가될 때마다 평균과 분산을 갱신할 수 있다. 물론 이게 위에서 여러번 읽어오는 알고리즘보다 더 계산양이 적을지 어떨지는 모르겠다. 난 단지 이런 방식으로 프로그램을 만들고 싶었을 뿐이다.

-------------
최근에 이 알고리즘을 다시 사용해야 해서 생각해보니, 그냥 단순하게 계산해도 된다.
N개의 자료의 평균과 분산을 알고 싶으면, x(i)의 합과 x(i)의 제곱의 합을 일단 다 계산한다.
그리고 자료를 출력하라고 요청하는 시점에 평균과 분산을 한번만 계산하면 된다.

처음에 생각한 공식은 점화식으로 주어진 공식이었고 좀 더 흥미로운 계산이지만, 컴퓨터한테 일 시키려면 새로 생각한 방법이 좀 더 나을 것 같다. (물론, 처음의 공식도 쓸모가 있긴 하다.)

by snowall 2011. 7. 9. 09:42