2013-05-23 4 views
2

말 확대에 평균 수를 계산하는 말 :공식은, 데이터 배열을

{1, 5, 7, 2} 

그들에 대한 평균이 될 것입니다 :

(1 + 5 + 7 + 2)/4; //Or, sum of all elements, divided by their number 

하지만 경우 내 배열은 지속적으로 증가하고 있으며 전체 배열을 아직 알지 못하는 시점에서 현재 평균 수를 알아야합니다. 어떻게 계산하나요?

내가 현재 데이터 전송 속도를 표시하려고 할 때처럼 말하십시오.

+2

는 데이터 전송 속도를 들어 당신이 정말로 전체 전송을 통해 직선 평균 가중 이동 평균 및하지를 사용하고 싶습니다. – Yaur

+1

가능한 복제본 [C#에서 간단한 이동 평균을 더 빨리 계산하는 방법] (http://stackoverflow.com/questions/12884600/how-to-calculate-simple-moving-average-faster-in-c) – Yuck

답변

2

나는 일정한 공간 복잡성 (1)을 가지고 running total (누적)을 갖는 간단한 접근법을 사용한다. 그리고 avg의 요청에 따라 running total/total number of item이라는 결과를 반환하십시오. 누적 합계를 찾기 위해 나중에 배열을 반복하지 않기 때문에 확장 된 시간 복잡성이 없습니다.

+1

감사합니다. 이 개념의 한 가지 명백한 단점은'누적 합계 '를 보유하는 변수의 오버 플로우입니다. 어떻게 해결할 수 있니? – ahmd0

+0

@ ahmd0 그런 다음 결과를 * 큰 * 유형, long, double, decimal, Biginteger 등으로 저장하십시오. – I4V

+0

@ I4V : 이미'double'을 사용하고 있지만 시간이 지남에 따라 문제가 발생할 수 있습니다. 나는 그것이 커지면 커질수록 정밀도가 떨어지는 것 같아요. – ahmd0

1

내가 원하는 것은 빠른 것을 원한다는 것입니다. 그렇지 않으면 이미 답을 얻을 수 있습니다. 이미 가지고있는 배열의 길이만큼 이미 가지고있는 모든 수를 합산하십시오. 이것은 매우 간단합니다.

그러나 때로는 배열이 바운드되는지 여부를 알 수 없으며 마이크에서 오는 데이터와 같이 무한 할 수도 있습니다. 이 경우에는 이동 평균을 제안하는 것이 좋습니다. 즉, 배열에서 마지막 x 값을 가져 와서 해당 값의 평균 만 계산해야합니다. 결과 값을 계산하는 데 필요한 알고리즘과 시간은 x 값 또는 1000x 값에 상관없이 동일하게 유지됩니다.

편집 :

x 대 1000x는 복잡도에서 비롯됩니다. 5 개의 숫자를 합한 것, 즉 5 개의 연산을 합한 다음 5로 나누고 6 개의 연산을 더한다고 가정 해 봅시다 (예를 들어 모두 동일한 컴퓨터 시간을 사용한다고 가정 할 것입니다. 그러나 실제로는 나누기가 느립니다) 추가에 비해). 동일한 코드를 사용하지만 숫자가 1000 인 경우 1001 작업을 수행하면 첫 번째 경우보다 훨씬 더 많은 시간이 걸립니다!

"이동 평균"을 사용하면 고정 된 숫자의 숫자를 사용하므로 숫자가 5 개 또는 1000 개이든 관계없이 실행하는 데 일정한 시간이 걸립니다.

이동 평균은 한 번에 배열에서 동일한 숫자를 사용하지 않는다는 단순한 표현입니다. 다음 배열 상상 :

int x = { 1, 4, 6, 3, 1 };
int arrayLength = 5;

그런 다음이 배열의 평균이 될 것이다

int runningTotal = 0; 
for(int i = 0; i < arrayLength; i++) 
{ 
    runningTotal += x[i]; 
} 
double average = runningTotal/arrayLength 

3 개 값의 이동 평균은에서

int movingLength = 3; 
int runningTotal = 0; 
for(int i = 0; i < movingLength; i++) 
{ 
    runningTotal += x[arrayLength - i - 1]; 
} 
double average = runningTotal/movingLength; 

그래서 첫 번째 값이 될 것이다 배열은 배열이 커질 때 계산의 일부가 아닙니다.

+0

알다시피 나는 여전히 "이동 평균"개념을 이해하기 위해 고심하고 있으므로 마지막 x 값 또는 1000x 값 비교에서 의미하는 것이 확실하지 않습니까? 그리고 예, 저는 평균을 계산할 때마다 전체 배열을 가질 필요가없는 것을 찾고 있습니다. – ahmd0

+0

설명해 주셔서 감사합니다. 이제 이해가된다. 이것은 마치 배열의 헤드 (또는 초기 데이터)를 버리고 마지막 N 개의 요소에 대해서만 평균을 계산하는 것과 같습니다. 흠. 그것은 재미있는 아이디어입니다 ... – ahmd0

1

새로운 가치를 얻을 때마다 합계와 개수를 업데이트하고 사용자에게 표시해야 할 때 간단하게 두 값을 나누십시오.

데이터 전송률의 경우 이는 문제가되는 방식입니다. 높은 대역폭으로 전송을 시작한 다음 연결이 끊어지는 시나리오를 생각해보십시오. 간단한 평균으로 UI에 현재 전송률이 0임을 반영하는 데 오랜 시간이 걸릴 수 있습니다. 가중 이동 평균을 사용하면 빠른 당신의 UI를보다 반응 적으로 보이게하는 방법.당신은 이동 평균을 찾고

float weight = 2.0; //you are going to want to tweak this to get the right balance between "responsive" and "noisy" 

void UpdateAverage(float newValue) 
{ 
    this.Average = (this.Average + (newValue*weight))/(weight+1) 
} 
+0

간단한 수학적 대답 – MDMalik

+0

누구든지 downvoted, 왜 설명 할 수 있습니까? 이것은 나의 생각이었다. – ahmd0

1

:

static void Main(string[] args) { 
     var nums = Enumerable.Range(1, 5).Select(n => (double)n); 
     nums = nums.Concat(nums.Reverse()); 

     var sma3 = SMA(3); 
     var sma5 = SMA(5); 

     foreach (var n in nums) { 
      Console.WriteLine("{0} (sma3) {1,-16} (sma5) {2,-16}", n, sma3(n), sma5(n)); 
     } 
    } 

    static Func<double, double> SMA(int p) { 
     Queue<double> s = new Queue<double>(p); 
     return (x) => { 
      if (s.Count >= p) { 
       s.Dequeue(); 
      } 
      s.Enqueue(x); 
      return s.Average(); 
     }; 
    } 

이의 가장 간단한 구현은 주기적으로 전송 속도를 샘플링 (5 초마다 말)와 같은 것을 사용하여 속도를 계산하는 것입니다

출처 : http://rosettacode.org/wiki/Averages/Simple_moving_average#C.23

+0

감사합니다. "이동 평균"은 전체 데이터 배열을 어딘가에서 메모리에 보관한다고 가정합니다. 죄송합니다. 위키 페이지는 너무 복잡하여 신속하게 파악할 수 없습니다. – ahmd0

+0

전체 배열을 메모리에 보관할 필요는 없으며 평균값으로 사용하려는 샘플의 수만 사용하십시오. – Yaur

0

가정은 당신이하지는 이동 평균을하고자 할 ..

마지막으로 평균을 계산할 때 요소의 현재 합계를 추적해야합니다. 실제 배열을 가정 당신은 요소의 몇 가지를 추가하고 배열은 다음과 같습니다

Array = {1, 5, 7, 2} 
Sum = 1 + 5 + 7 + 2 = 15 
Number of elements = 4 
Average = Sum/Number of elements = 3.75 

배열이 인 경우

...

Array = {1, 5, 7, 2, 10, 6} 

은 훨씬 큰 .. . 평균을 계산합니다 ..

Sum = ([previous sum] + [sum of new elements])/[number of elements] 
Number of elements = 6 
Average = ((15 * 4) + 10 + 6)/6 = 5.1666667 

편집 :에게 난을 f 정밀도와 크기에 대해 염려가있다. BigInteger

+0

감사합니다. 예, 필요한 것은 약입니다. 평균. 이 경우 수식은 무엇입니까? – ahmd0

+0

누적 합계와 요소 수를 유지하십시오. 누적 합계를 마지막으로 계산 한 이후 배열의 새로운 요소를 추적하면됩니다. 배열에 요소를 추가하는 경우 추가 할 때 누적 합계에 더합니다. – Kevin

+0

누적 합계에서 오버플로를 어떻게 처리하겠습니까? – ahmd0

1

나는 여기서 파티에 늦은 것을 알고 있지만 2000 년 적응로드 밸런서를 만들 때 이와 비슷한 문제를 해결했습니다. 표준 평균 두 가지 문제, 주어진 답변에서 언급 한 두 있습니다

  1. 오버 플로우 시나리오
  2. - 일반적으로, 당신은 모든 단일 샘플에 대해이 작업을 수행 할 필요가 - 실행중인 총을 유지하는 것은
  3. 평균
  4. 을 재 계산 오버 플로우 이어질 것

일반 평균 계산을 '수학적 관계'라고 부르는 '반복 관계'로 전환 할 수 있습니다. 즉, 이전 평균을 저장한다는 것을 의미합니다. 그러면 이전 평균을 계산 한 다음 새 값을 계산하는 데 사용됩니다 (Yaur의 답과 유사합니다. 아흐메드 (AHMED)에 동의하기 위해, 투표가 다운 된 것을 볼 수 없다. 나는 원래 델파이로 그 날을 썼다. 그래서 나는 최근에 .NET에서 똑같은 것을 다시했고 항목 목록이 커지면서 연속 평균을 계산하는 표준 프로세스와 비교했다.

: (난 그냥 내 타이핑 손가락을 저장하기 위해 링크를 게시하도록하겠습니다), 당신은 비교 실험의 이론적 치료, 대수, 결과를 찾을 수하고있는 문제를 해결하는 방법을 자기 홍보에 원하는없이

http://goadingtheitgeek.blogspot.co.uk/2014/05/blast-from-past.html

유용하게 사용하시기 바랍니다.

0

평균 버퍼 길이를 변경할 수 있다면 이전 프로그램이 그 것입니다.

namespace WindowsFormsApplication1 
{ 
    public partial class ComTester : Form 
    { 
    public int []sAvgArr=new int [251]; 
    public int sAvgAdr,sAvgCnt; 

    private void Calc_Values(object sender, int v)//v is value 
    { 
     int n = AverageLength; 
     if (n > 250) n = 250;//average buffer maksimum 
     if (n > 0) 
     { 
      sAvgArr[sAvgAdr] = v; 
      sAvgAdr += 1; 
      sAvgCnt += 1; 
      if (n <= sAvgAdr) sAvgAdr = 0; 
      if (n <= sAvgCnt) sAvgCnt = n; 
      n = sAvgCnt; 
      int f = 0, l = 0; ; 
      for (l = 0; l < n; l += 1) 
       f += sAvgArr[l]; 
      f = f/sAvgCnt; 
      sAvgVal = f; 
     } 
     else 
     { 
      sAvgVal=v; 
     } 
    } 
    } 
} 
-2
using System; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      int n = 3 , x , sum = 0 ; 
      double ave; 

      for (int i = 0; i < n; i++) 
      { 
       Console.WriteLine("enter the number:"); 
       x = Convert.ToInt16(Console.ReadLine()); 
       sum += x; 
      } 

      ave = (double)(sum)/3; 
      Console.WriteLine("average:"); 
      Console.WriteLine(ave); 
      Console.ReadLine(); 
     } 
    } 
} 
+2

답변의 형식을 수정하고 설명/설명하는 텍스트를 제공하는 것을 고려하십시오. –