복붙노트

[PYTHON] 실행 표준 편차를 효율적으로 계산하는 방법?

PYTHON

실행 표준 편차를 효율적으로 계산하는 방법?

일련 번호 목록이 있습니다 (예 :

[0] (0.01, 0.01, 0.02, 0.04, 0.03)
[1] (0.00, 0.02, 0.02, 0.03, 0.02)
[2] (0.01, 0.02, 0.02, 0.03, 0.02)
     ...
[n] (0.01, 0.00, 0.01, 0.05, 0.03)

내가하고 싶은 것은 모든 배열 요소에 걸쳐 목록의 각 인덱스에서 평균 및 표준 편차를 효율적으로 계산하는 것입니다.

평균을하기 위해 나는 배열을 반복하고 목록의 주어진 색인에서 값을 합산했습니다. 마지막으로, "평균 목록"의 각 값을 n으로 나눕니다.

표준 편차를 수행하기 위해 평균 계산이 완료되었으므로 루프를 다시 반복합니다.

나는 배열을 두 번 통과하지 않으려합니다. 한 번은 평균을 위해, 한 번은 SD를 위해 한 번 (평균값을 얻은 후) 피하십시오.

한 번만 배열을 통과하는 두 값을 계산하는 효율적인 방법이 있습니까? 해석 된 언어 (예 : Perl 또는 Python) 또는 의사 코드의 코드는 정상입니다.

해결법

  1. ==============================

    1.대답은 Welford의 알고리즘을 사용하는 것입니다.이 알고리즘은 다음과 같은 "순진한 방법"에서 매우 명확하게 정의됩니다.

    대답은 Welford의 알고리즘을 사용하는 것입니다.이 알고리즘은 다음과 같은 "순진한 방법"에서 매우 명확하게 정의됩니다.

    다른 응답에서 제안 된 2 패스 또는 온라인 제곱근 수집기보다 수치 적으로 안정적입니다. 안정성은 부동 소수점 문헌에서 "치명적인 취소"로 알려진 것을 이끌어 낼 때 서로 가깝게 많은 값을 가질 때만 중요합니다.

    또한 분산 계산에서 샘플 수 (N)와 N-1로 나눈 것의 차이 (제곱 된 편차) 사이의 차이점을 알아볼 수도 있습니다. N-1로 나눈 값은 표본의 편차에 대한 편향되지 않은 추정을 유도하는 반면, 평균에 대한 N으로 나누는 것은 표본 평균과 진정한 평균의 차이를 고려하지 않기 때문에 분산을 과소 평가합니다.

    나는 온라인에서 이전 값을 삭제하는 방법을 포함하여 세부 사항으로 들어가는 주제에 대한 두 개의 블로그 항목을 썼다.

    내 Java 구현을 살펴볼 수도 있습니다. javadoc, 소스 및 유닛 테스트가 모두 온라인 상태입니다.

  2. ==============================

    2.기본적인 대답은 x '(sum_x1이라고 부름)과 x2 (sum_x2'라고 부름)의 합계를 누적하는 것입니다. 표준 편차의 값은 다음과 같습니다.

    기본적인 대답은 x '(sum_x1이라고 부름)과 x2 (sum_x2'라고 부름)의 합계를 누적하는 것입니다. 표준 편차의 값은 다음과 같습니다.

    stdev = sqrt((sum_x2 / n) - (mean * mean)) 
    

    어디에

    mean = sum_x / n
    

    이것은 샘플 표준 편차입니다. 제수로 'n - 1'대신 'n'을 사용하여 인구 표준 편차를 얻습니다.

    큰 샘플을 다루는 경우 두 개의 큰 숫자의 차이를 취하는 수치 안정성에 대해 걱정할 필요가 있습니다. 자세한 내용은 다른 답변 (Wikipedia 등)의 외부 참조로 이동하십시오.

  3. ==============================

    3.아마도 당신이 묻는 것은 아니지만 ... 만약 당신이 질적 인 배열을 사용한다면, 당신을 위해 효율적으로 작업을 수행 할 것입니다.

    아마도 당신이 묻는 것은 아니지만 ... 만약 당신이 질적 인 배열을 사용한다면, 당신을 위해 효율적으로 작업을 수행 할 것입니다.

    from numpy import array
    
    nums = array(((0.01, 0.01, 0.02, 0.04, 0.03),
                  (0.00, 0.02, 0.02, 0.03, 0.02),
                  (0.01, 0.02, 0.02, 0.03, 0.02),
                  (0.01, 0.00, 0.01, 0.05, 0.03)))
    
    print nums.std(axis=1)
    # [ 0.0116619   0.00979796  0.00632456  0.01788854]
    
    print nums.mean(axis=1)
    # [ 0.022  0.018  0.02   0.02 ]
    

    그런데이 블로그 게시물에는 흥미로운 토론이 있고 컴퓨팅 수단과 분산에 대한 원 패스 (one-pass) 방법에 대한 의견이 있습니다.

  4. ==============================

    4.다음은 http://www.johndcook.com/standard_deviation.html에서 Welford 알고리즘 구현의 문자 그대로 순수한 Python 번역입니다.

    다음은 http://www.johndcook.com/standard_deviation.html에서 Welford 알고리즘 구현의 문자 그대로 순수한 Python 번역입니다.

    https://github.com/liyanage/python-modules/blob/master/running_stats.py

    class RunningStats:
    
        def __init__(self):
            self.n = 0
            self.old_m = 0
            self.new_m = 0
            self.old_s = 0
            self.new_s = 0
    
        def clear(self):
            self.n = 0
    
        def push(self, x):
            self.n += 1
    
            if self.n == 1:
                self.old_m = self.new_m = x
                self.old_s = 0
            else:
                self.new_m = self.old_m + (x - self.old_m) / self.n
                self.new_s = self.old_s + (x - self.old_m) * (x - self.new_m)
    
                self.old_m = self.new_m
                self.old_s = self.new_s
    
        def mean(self):
            return self.new_m if self.n else 0.0
    
        def variance(self):
            return self.new_s / (self.n - 1) if self.n > 1 else 0.0
    
        def standard_deviation(self):
            return math.sqrt(self.variance())
    

    용법:

    rs = RunningStats()
    rs.push(17.0);
    rs.push(19.0);
    rs.push(24.0);
    
    mean = rs.mean();
    variance = rs.variance();
    stdev = rs.standard_deviation();
    
  5. ==============================

    5.파이썬 runstats 모듈은 이런 종류의 일을합니다. PyPI에서 runstats 설치 :

    파이썬 runstats 모듈은 이런 종류의 일을합니다. PyPI에서 runstats 설치 :

    pip install runstats
    

    Runstats 요약은 단일 데이터 패스에서 평균, 분산, 표준 편차, 비대칭 및 첨도를 생성 할 수 있습니다. 우리는 이것을 사용하여 "실행중인"버전을 만들 수 있습니다.

    from runstats import Statistics
    
    stats = [Statistics() for num in range(len(data[0]))]
    
    for row in data:
    
        for index, val in enumerate(row):
            stats[index].push(val)
    
        for index, stat in enumerate(stats):
            print 'Index', index, 'mean:', stat.mean()
            print 'Index', index, 'standard deviation:', stat.stddev()
    

    통계 요약은 Knuth and Welford 방법을 기반으로 컴퓨터 프로그래밍의 기술, Vol 2, p. 232, 3 판. 이것의 이점은 수치 적으로 안정되고 정확한 결과입니다.

    면책 조항 : 필자는 Python runstats 모듈 작성자입니다.

  6. ==============================

    6.PDL (piddle이라고 발음합니다.)을보십시오.

    PDL (piddle이라고 발음합니다.)을보십시오.

    이것은 고정밀 수학과 과학 계산을 위해 설계된 Perl 데이터 언어입니다.

    귀하의 그림을 사용한 예가 있습니다 ....

    use strict;
    use warnings;
    use PDL;
    
    my $figs = pdl [
        [0.01, 0.01, 0.02, 0.04, 0.03],
        [0.00, 0.02, 0.02, 0.03, 0.02],
        [0.01, 0.02, 0.02, 0.03, 0.02],
        [0.01, 0.00, 0.01, 0.05, 0.03],
    ];
    
    my ( $mean, $prms, $median, $min, $max, $adev, $rms ) = statsover( $figs );
    
    say "Mean scores:     ", $mean;
    say "Std dev? (adev): ", $adev;
    say "Std dev? (prms): ", $prms;
    say "Std dev? (rms):  ", $rms;
    

    생산하는 제품 :

    Mean scores:     [0.022 0.018 0.02 0.02]
    Std dev? (adev): [0.0104 0.0072 0.004 0.016]
    Std dev? (prms): [0.013038405 0.010954451 0.0070710678 0.02]
    Std dev? (rms):  [0.011661904 0.009797959 0.0063245553 0.017888544]
    

    statsover 함수에 대한 자세한 내용은 PDL :: Primitive를 참조하십시오. 이것은 ADEV가 "표준 편차"라고 제안하는 것 같습니다.

    그러나 아마도 PRMS (Sinan의 Statistics :: Descriptive example이 보여줍니다) 또는 RMS (ars의 NumPy 예제가 보여주는) 일 수 있습니다. 나는이 세 가지 중 하나가 맞아야한다고 생각한다 ;-)

    자세한 PDL 정보는 다음을보십시오.

  7. ==============================

    7.Statistics :: Descriptive는 이러한 유형의 계산을위한 매우 적합한 Perl 모듈입니다.

    Statistics :: Descriptive는 이러한 유형의 계산을위한 매우 적합한 Perl 모듈입니다.

    #!/usr/bin/perl
    
    use strict; use warnings;
    
    use Statistics::Descriptive qw( :all );
    
    my $data = [
        [ 0.01, 0.01, 0.02, 0.04, 0.03 ],
        [ 0.00, 0.02, 0.02, 0.03, 0.02 ],
        [ 0.01, 0.02, 0.02, 0.03, 0.02 ],
        [ 0.01, 0.00, 0.01, 0.05, 0.03 ],
    ];
    
    my $stat = Statistics::Descriptive::Full->new;
    # You also have the option of using sparse data structures
    
    for my $ref ( @$data ) {
        $stat->add_data( @$ref );
        printf "Running mean: %f\n", $stat->mean;
        printf "Running stdev: %f\n", $stat->standard_deviation;
    }
    __END__
    

    산출:

    C:\Temp> g
    Running mean: 0.022000
    Running stdev: 0.013038
    Running mean: 0.020000
    Running stdev: 0.011547
    Running mean: 0.020000
    Running stdev: 0.010000
    Running mean: 0.020000
    Running stdev: 0.012566
    
  8. ==============================

    8.배열이 얼마나 큽니까? 요소가 길지 않은 한, 두 번 반복하는 것에 대해 걱정할 필요가 없습니다. 이 코드는 간단하고 쉽게 테스트 할 수 있습니다.

    배열이 얼마나 큽니까? 요소가 길지 않은 한, 두 번 반복하는 것에 대해 걱정할 필요가 없습니다. 이 코드는 간단하고 쉽게 테스트 할 수 있습니다.

    필자가 선호하는 것은 배열의 배열을 numpy 2D 배열로 변환하고 표준 편차를 직접 얻는 numpy 배열 maths 확장을 사용하는 것입니다.

    >>> x = [ [ 1, 2, 4, 3, 4, 5 ], [ 3, 4, 5, 6, 7, 8 ] ] * 10
    >>> import numpy
    >>> a = numpy.array(x)
    >>> a.std(axis=0) 
    array([ 1. ,  1. ,  0.5,  1.5,  1.5,  1.5])
    >>> a.mean(axis=0)
    array([ 2. ,  3. ,  4.5,  4.5,  5.5,  6.5])
    

    이것이 옵션이 아니며 순수한 Python 솔루션이 필요하다면 계속 읽고 ...

    배열이

    x = [ 
          [ 1, 2, 4, 3, 4, 5 ],
          [ 3, 4, 5, 6, 7, 8 ],
          ....
    ]
    

    표준 편차는 다음과 같습니다.

    d = len(x[0])
    n = len(x)
    sum_x = [ sum(v[i] for v in x) for i in range(d) ]
    sum_x2 = [ sum(v[i]**2 for v in x) for i in range(d) ]
    std_dev = [ sqrt((sx2 - sx**2)/N)  for sx, sx2 in zip(sum_x, sum_x2) ]
    

    배열을 한 번만 반복하도록 결정하면 누적 합계를 결합 할 수 있습니다.

    sum_x  = [ 0 ] * d
    sum_x2 = [ 0 ] * d
    for v in x:
       for i, t in enumerate(v):
       sum_x[i] += t
       sum_x2[i] += t**2
    

    위의 목록 이해력 솔루션만큼 우아하지는 않습니다.

  9. ==============================

    9.나는이 문제가 당신을 도울 것이라고 생각합니다. 표준 편차

    나는이 문제가 당신을 도울 것이라고 생각합니다. 표준 편차

  10. ==============================

    10.표준 편차에 관한 Wikipedia 기사, 특히 신속한 계산 방법에 관한 섹션을 살펴볼 수 있습니다.

    표준 편차에 관한 Wikipedia 기사, 특히 신속한 계산 방법에 관한 섹션을 살펴볼 수 있습니다.

    파이썬을 사용하는 문서도 있습니다. 코드를 변경하지 않고도 사용할 수 있어야합니다. Subliminal Messages - Running Standard Deviations.

  11. ==============================

    11.

    n=int(raw_input("Enter no. of terms:"))
    
    L=[]
    
    for i in range (1,n+1):
    
        x=float(raw_input("Enter term:"))
    
        L.append(x)
    
    sum=0
    
    for i in range(n):
    
        sum=sum+L[i]
    
    avg=sum/n
    
    sumdev=0
    
    for j in range(n):
    
        sumdev=sumdev+(L[j]-avg)**2
    
    dev=(sumdev/n)**0.5
    
    print "Standard deviation is", dev
    
  12. ==============================

    12.다음 답변은 다음과 같이 설명합니다. pandas / scipy / numpy는 누적 표준 편차 함수를 제공합니까? Python Pandas 모듈에는 실행 또는 누적 표준 편차를 계산하는 메소드가 있습니다. 이를 위해서는 데이터를 판다 데이터 프레임 (또는 1D 인 경우 시리즈)으로 변환해야하지만 그 기능이 있습니다.

    다음 답변은 다음과 같이 설명합니다. pandas / scipy / numpy는 누적 표준 편차 함수를 제공합니까? Python Pandas 모듈에는 실행 또는 누적 표준 편차를 계산하는 메소드가 있습니다. 이를 위해서는 데이터를 판다 데이터 프레임 (또는 1D 인 경우 시리즈)으로 변환해야하지만 그 기능이 있습니다.

  13. ==============================

    13.다음은 함수형 프로그래밍 스타일로 여러 줄에 걸쳐있는 "한 줄짜리"코드입니다.

    다음은 함수형 프로그래밍 스타일로 여러 줄에 걸쳐있는 "한 줄짜리"코드입니다.

    def variance(data, opt=0):
        return (lambda (m2, i, _): m2 / (opt + i - 1))(
            reduce(
                lambda (m2, i, avg), x:
                (
                    m2 + (x - avg) ** 2 * i / (i + 1),
                    i + 1,
                    avg + (x - avg) / (i + 1)
                ),
                data,
                (0, 0, 0)))
    
  14. ==============================

    14.이 방법으로 업데이트를 표현하고 싶습니다.

    이 방법으로 업데이트를 표현하고 싶습니다.

    def running_update(x, N, mu, var):
        '''
            @arg x: the current data sample
            @arg N : the number of previous samples
            @arg mu: the mean of the previous samples
            @arg var : the variance over the previous samples
            @retval (N+1, mu', var') -- updated mean, variance and count
        '''
        N = N + 1
        rho = 1.0/N
        d = x - mu
        mu += rho*d
        var += rho*((1-rho)*d**2 - var)
        return (N, mu, var)
    

    one-pass 함수는 다음과 같이 보일 것입니다.

    def one_pass(data):
        N = 0
        mu = 0.0
        var = 0.0
        for x in data:
            N = N + 1
            rho = 1.0/N
            d = x - mu
            mu += rho*d
            var += rho*((1-rho)*d**2 - var)
            # could yield here if you want partial results
       return (N, mu, var)
    

    이것은 1 / (N-1) 정규화 인수를 사용하는 모집단 분산의 비 편향 추정이 아니라 표본 분산 (1 / N)을 계산한다는 점에 유의하십시오. 다른 답변과 달리 실행 변수를 추적하는 변수 var는 샘플 수에 비례하여 증가하지 않습니다. 항상 그것은 지금까지 보인 샘플 세트의 분산 일뿐입니다 (분산을 구하는 데 마지막으로 "n으로 나눔"이 없습니다).

    수업에서는 다음과 같이 보입니다.

    class RunningMeanVar(object):
        def __init__(self):
            self.N = 0
            self.mu = 0.0
            self.var = 0.0
        def push(self, x):
            self.N = self.N + 1
            rho = 1.0/N
            d = x-self.mu
            self.mu += rho*d
            self.var += + rho*((1-rho)*d**2-self.var)
        # reset, accessors etc. can be setup as you see fit
    

    가중치가있는 샘플에도 적용됩니다.

    def running_update(w, x, N, mu, var):
        '''
            @arg w: the weight of the current sample
            @arg x: the current data sample
            @arg mu: the mean of the previous N sample
            @arg var : the variance over the previous N samples
            @arg N : the number of previous samples
            @retval (N+w, mu', var') -- updated mean, variance and count
        '''
        N = N + w
        rho = w/N
        d = x - mu
        mu += rho*d
        var += rho*((1-rho)*d**2 - var)
        return (N, mu, var)
    
  15. from https://stackoverflow.com/questions/1174984/how-to-efficiently-calculate-a-running-standard-deviation by cc-by-sa and MIT license