태그 보관물: moving-average

moving-average

개수와 데이터 합계를 유지하지 않고 이동 평균을 계산하는 방법은 무엇입니까?

지금까지받은 수와 총 데이터를 저장하지 않고 이동 누적 평균을 계산하는 방법을 찾으려고합니다.

두 가지 알고리즘을 생각해 냈지만 둘 다 개수를 저장해야합니다.

  • 새 평균 = ((이전 개수 * 이전 데이터) + 다음 데이터) / 다음 개수
  • 새 평균 = 이전 평균 + (다음 데이터-이전 평균) / 다음 개수

이러한 방법의 문제점은 개수가 점점 커져 결과 평균의 정밀도를 잃는다는 것입니다.

첫 번째 방법은 분명히 1로 떨어져있는 이전 개수와 다음 개수를 사용합니다. 이것은 아마도 카운트를 제거하는 방법이 있다고 생각하게했지만 불행히도 아직 찾지 못했습니다. 그래도 조금 더 나아서 두 번째 방법을 얻었지만 여전히 카운트가 존재합니다.

가능합니까, 아니면 불가능한 것을 찾고 있습니까?



답변

간단하게 다음을 수행 할 수 있습니다.

double approxRollingAverage (double avg, double new_sample) {

    avg -= avg / N;
    avg += new_sample / N;

    return avg;
}

N평균화하려는 샘플 수는 어디에 있습니까 ? 이 근사는 지수 이동 평균과 동일합니다. 참조 : C ++에서 롤링 / 이동 평균 계산


답변

New average = old average * (n-1)/n + new value /n

이것은 카운트가 하나의 값만큼만 변경되었다고 가정합니다. M 값으로 변경된 경우 :

new average = old average * (n-len(M))/n + (sum of values in M)/n).

이것은 수학적 공식입니다 (가장 효율적인 공식이라고 생각합니다). 스스로 추가 코드를 작성할 수 있다고 믿습니다.


답변

에서 블로그 평균도 계산됩니다 표본 분산의 계산, 실행에 대한 Welford의 방법 :

안타깝게도 SVG 이미지를 업로드 할 수 없습니다.


답변

Muis , Abdullah Al-AgeelFlip 의 답변이 다르게 쓰여진 것을 제외하고 는 모두 수학적으로 동일한 방법에 대한 주석을 제공하는 또 다른 답변 이 있습니다.

물론, 반올림 오류가 각각에 약간 다른 영향을 미치는 방식을 설명하는 José Manuel Ramos 의 분석이 있지만 이는 구현에 따라 다르며 각 답변이 코드에 어떻게 적용되었는지에 따라 변경됩니다.

그러나 다소 큰 차이가 있습니다

그것은 Muis ‘s N, Flip ‘s kAbdullah Al-Ageel ‘s에 n있습니다. 압둘라 알 – Ageel은 매우 무엇인지 설명하지 않습니다 n해야하지만 N하고 k있다는 점에서 차이가 N있다 ” 당신이 평균 이상으로 원하는 샘플 수는 “동안은 k샘플링 값의 수입니다. ( N 샘플 수를 호출 하는 것이 정확한지 의심 스럽지만 )

그리고 여기에서 우리는 아래의 답을 얻습니다. 본질적으로 다른 것들 과 동일한 오래된 지수 가중 이동 평균 이므로 대안을 찾고 있다면 여기에서 중지하십시오.

지수 가중 이동 평균

처음에는 :

average = 0
counter = 0

각 값에 대해 :

counter += 1
average = average + (value - average) / min(counter, FACTOR)

차이점은 min(counter, FACTOR)부분입니다. 이것은 말하는 것과 같습니다 min(Flip's k, Muis's N).

FACTOR평균이 최신 추세를 “따라 잡는”속도에 영향을주는 상수입니다. 숫자가 작을수록 빠릅니다. ( 1더 이상 평균이 아니며 단지 최신 값이됩니다.)

이 대답에는 실행 카운터가 필요합니다 counter. 문제가있는 경우 min(counter, FACTOR)를로 대체하여 Muis 의 대답 FACTOR으로 바꿀 수 있습니다 . 이 작업의 문제는 이동 평균 이 초기화되는 항목의 영향을 받는다는 것입니다. 로 초기화 된 경우 해당 0이 평균을 벗어나는 데 오랜 시간이 걸릴 수 있습니다.average0

어떻게 보이는지


답변

Flip의 대답은 Muis보다 계산적으로 더 일관 적입니다.

이중 숫자 형식을 사용하면 Muis 접근 방식에서 반올림 문제를 볼 수 있습니다.

나누고 빼면 이전에 저장된 값에 반올림이 나타나 변경됩니다.

그러나 Flip 접근 방식은 저장된 값을 보존하고 분할 수를 줄여서 반올림을 줄이고 저장된 값으로 전파되는 오류를 최소화합니다. 추가 할 항목이있는 경우에만 반올림이 표시됩니다 (N이 크면 추가 할 항목이 없음).

큰 값의 평균을 만들 때 이러한 변화는 그 평균이 0이되는 경향이 있습니다.

스프레드 시트 프로그램을 사용하여 결과를 보여드립니다.

첫째, 결과는 다음과 같습니다.

A 및 B 열은 각각 n 및 X_n 값입니다.

C 열은 Flip 접근 방식이고 D 열은 Muis 접근 방식이며 그 결과는 평균에 저장됩니다. E 열은 계산에 사용 된 중간 값에 해당합니다.

다음은 짝수 값의 평균을 보여주는 그래프입니다.

보시다시피 두 접근 방식에는 큰 차이가 있습니다.


답변

비교를 위해 자바 스크립트를 사용하는 예 :

https://jsfiddle.net/drzaus/Lxsa4rpz/

function calcNormalAvg(list) {
    // sum(list) / len(list)
    return list.reduce(function(a, b) { return a + b; }) / list.length;
}
function calcRunningAvg(previousAverage, currentNumber, index) {
    // [ avg' * (n-1) + x ] / n
    return ( previousAverage * (index - 1) + currentNumber ) / index;
}
(function(){
  // populate base list
var list = [];
function getSeedNumber() { return Math.random()*100; }
for(var i = 0; i < 50; i++) list.push( getSeedNumber() );

  // our calculation functions, for comparison
function calcNormalAvg(list) {
  	// sum(list) / len(list)
	return list.reduce(function(a, b) { return a + b; }) / list.length;
}
function calcRunningAvg(previousAverage, currentNumber, index) {
  	// [ avg' * (n-1) + x ] / n
	return ( previousAverage * (index - 1) + currentNumber ) / index;
}
  function calcMovingAvg(accumulator, new_value, alpha) {
  	return (alpha * new_value) + (1.0 - alpha) * accumulator;
}

  // start our baseline
var baseAvg = calcNormalAvg(list);
var runningAvg = baseAvg, movingAvg = baseAvg;
console.log('base avg: %d', baseAvg);

  var okay = true;

  // table of output, cleaner console view
  var results = [];

  // add 10 more numbers to the list and compare calculations
for(var n = list.length, i = 0; i < 10; i++, n++) {
	var newNumber = getSeedNumber();

	runningAvg = calcRunningAvg(runningAvg, newNumber, n+1);
	movingAvg = calcMovingAvg(movingAvg, newNumber, 1/(n+1));

	list.push(newNumber);
	baseAvg = calcNormalAvg(list);

	// assert and inspect
	console.log('added [%d] to list at pos %d, running avg = %d vs. regular avg = %d (%s), vs. moving avg = %d (%s)'
		, newNumber, list.length, runningAvg, baseAvg, runningAvg == baseAvg, movingAvg, movingAvg == baseAvg
	)
results.push( {x: newNumber, n:list.length, regular: baseAvg, running: runningAvg, moving: movingAvg, eqRun: baseAvg == runningAvg, eqMov: baseAvg == movingAvg } );

if(runningAvg != baseAvg) console.warn('Fail!');
okay = okay && (runningAvg == baseAvg);
}

  console.log('Everything matched for running avg? %s', okay);
  if(console.table) console.table(results);
})();

답변

Java8에서 :

LongSummaryStatistics movingAverage = new LongSummaryStatistics();
movingAverage.accept(new data);
...
average = movingAverage.getAverage();

당신은 또한 가지고 IntSummaryStatistics, DoubleSummaryStatistics