스트리밍 데이터의 이동 평균 계산

최근에 들어오는 데이터 스트림에서 일부 통계(평균 및 표준 편차)를 계산해야 했습니다. 나는 그것에 대해 약간의 조사를 했고, 이 기사는 그 결과입니다. 여러 부분으로 나누어서 올리겠습니다. 이 첫 번째 부분은 평균을 점진적으로 계산하는 방법에 관한 것입니다. 표준 편차로 동일한 작업을 수행하는 방법에 관한 것입니다. 세 번째 부분은 저역 통과 필터라고도 하는 에 관한 것입니다.

What people often call the 'average' is more technically referred to in statistics as the 'arithmetic mean'. For this article, the terms 'average' and 'mean' are interchangeable.



우리 모두가 학교에서 배우는 일련의 데이터에 대한 평균을 계산하는 일반적인 방법은 모든 값(전체)을 더한 다음 값의 수(개수)로 나누는 것입니다.



방금 위에서 작성한 내용을 설명하는 수학 표기법은 다음과 같습니다.



다음은 이 순진한 접근 방식을 사용하여 평균을 구하는 간단한 자바스크립트 함수입니다.

const simpleMean = values => {
    validate(values)

    const sum = values.reduce((a,b)=>a+b, 0)
    const mean = sum/values.length
    return mean
}

const validate = values =>  {
    if (!values || values.length == 0) {
        throw new Error('Mean is undefined')
    }
}


이 논리가 진행되는 한 문제가 없지만 실제로는 몇 가지 제한 사항이 있습니다.
  • 잠재적으로 큰 합계를 누적하므로 floating point 유형을 사용할 때 정밀도 및 오버플로 문제가 발생할 수 있습니다.
  • 계산을 수행하려면 먼저 모든 데이터를 사용할 수 있어야 합니다.

  • 이 두 가지 문제는 각각의 새로운 값에 대한 평균을 조정하는 점진적 접근 방식으로 해결할 수 있습니다. 먼저 몇 가지 수학을 사용하여 이 공식을 유도하는 방법을 보여주고 JavaScript 구현을 보여드리겠습니다.

    There are two symbols in math that are often used to denote the mean. σ, the lowercase greek letter sigma, refers to the population mean. This is the average for an entire population - all of the possible values. The average of all the grades on a particular test is an example.

    , pronounced x-bar, refers to the sample mean. This is the average of a sample of values from the total population. You might take a random sample of people across the country to find the average height of the population, but it's impractical to measure the height of every single person in an entire country. Of course when using a sample, it's desirable to try to get as close as possible to the mean of the population the sample represents.

    I decided to use the sample notation for this article to indicate that the average we're calculating could be based on a sample.



    좋아, 우리가 이전에 본 평균에 대한 공식으로 시작하자.



    첫 번째 n-1 값을 먼저 더한 다음 마지막 값 xn을 더하도록 합계를 분할하겠습니다.



    평균 = 총계/개수라는 것을 알고 있습니다.



    이를 약간 재정렬해 보겠습니다.



    다음은 위의 대체를 첫 번째 n-1 값의 합계에 적용한 결과입니다.



    이것을 확장해 보겠습니다.



    약간 재정렬하면 다음을 얻습니다.



    최종 결과를 얻기 위해 첫 번째 분수에서 n 를 취소할 수 있습니다.



    이 모든 것이 실제로 무엇을 의미합니까? 이제 다음과 같이 n번째 값에 대한 평균을 정의하는 반복 관계가 있습니다. 이전 n-1 값에 대한 평균에 미분을 추가합니다. 새 값을 추가할 때마다 이 차이를 계산하여 이전 평균에 추가하기만 하면 됩니다. 이것은 이제 새로운 평균이 됩니다.

    다음은 이 아이디어를 간단하게 구현한 것입니다.

    class MovingAverageCalculator {
        constructor() {
            this.count = 0
            this._mean = 0
        }
    
        update(newValue) {
            this.count++
    
            const differential = (newValue - this._mean) / this.count
    
            const newMean = this._mean + differential
    
            this._mean = newMean
        }
    
        get mean() {
            this.validate()
            return this._mean
        }
    
        validate() {
            if (this.count == 0) {
                throw new Error('Mean is undefined')
            }
        }
    }
    


    위의 코드에서 새 값으로 update를 호출할 때마다 카운트를 증가시키고 차이를 계산합니다. newMean는 이 차이에 더해진 이전 평균입니다. 이것은 이제 우리가 update를 호출할 때 사용될 평균이 됩니다.

    다음은 두 가지 방법을 간단히 비교한 것입니다.

    console.log('simple mean = ' + simpleMean([1,2,3]))
    
    const calc = new MovingAverageCalculator()
    calc.update(1)
    calc.update(2)
    calc.update(3)
    console.log('moving average mean = ' + calc.mean)
    


    결과는 예상대로입니다.

    C:\dev\>node RunningMean.js
    simple mean = 2
    moving average mean = 2
    


    물론 가능한 다른 많은 종류moving averages가 있지만 단순히 누적 이동 평균을 원하는 경우 이 논리가 잘 작동합니다. 간단하고 스트리밍 데이터 세트에 적용할 수 있으며 정밀도 및 순진한 접근 방식으로 발생할 수 있는 오버플로.

    Before concluding, I'd like to derive one more identity using our last result. We don't need it right now, but we'll use in the next article.

    We'll start with our recurrence relation for the mean:

    Let's subtract the first term on the right from both sides, giving us the value of just our differential:

    Now let's multiply by n:

    Let's multiply both sides by -1:

    And finally let's mutiply the -1 through both sides:

    We'll just hold on to this identity for now, but it will be useful in part 2 where we derive the formula for incrementally calculating the variance and standard deviation.



    관련된:



  • 좋은 웹페이지 즐겨찾기