144

これまでに受信したカウントと合計データを保存せずに、移動累積平均を計算する方法を見つけようとしています。

2 つのアルゴリズムを思いつきましたが、どちらもカウントを格納する必要があります。

  • 新しい平均 = ((古いカウント * 古いデータ) + 次のデータ) / 次のカウント
  • 新しい平均 = 古い平均 + (次のデータ - 古い平均) / 次のカウント

これらの方法の問題は、カウントがどんどん大きくなり、結果として得られる平均の精度が失われることです。

最初の方法は、明らかに 1 離れている古いカウントと次のカウントを使用します。これにより、おそらくカウントを削除する方法があるのではないかと思いましたが、残念ながらまだ見つけていません。しかし、それは私をもう少し先に進め、2番目の方法になりましたが、それでもカウントは存在します。

それは可能ですか、それとも不可能を探しているだけですか?

4

8 に答える 8

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

これは、カウントが 1 つの値だけ変更されたと仮定しています。M 値によって変更された場合:

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

これは数式です (最も効率的な数式だと思います)。自分でさらにコードを作成できると思います

于 2014-05-06T11:41:16.917 に答える
35

サンプル分散計算の実行に関するブログから、平均もウェルフォード法を使用して計算されます。

ここに画像の説明を入力

SVG 画像をアップロードできないのは残念です。

于 2016-06-15T08:35:47.910 に答える
10

比較のために JavaScript を使用した例:

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);
})();

于 2016-08-11T15:57:35.683 に答える