예를 들어 다음과 같은 숫자 목록이 있습니다.
[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) 또는 의사 코드로 된 코드는 괜찮습니다.
답변
대답은 Welford의 알고리즘을 사용하는 것입니다. 이는 다음에서 “순진한 방법”뒤에 매우 명확하게 정의되어 있습니다.
- Wikipedia : 분산 계산 알고리즘
다른 응답에서 제안 된 2- 패스 또는 온라인 단순 제곱합 수집기보다 수치 적으로 더 안정적입니다. 안정성 은 부동 소수점 문헌에서 ” 치명적 취소 ” 로 알려진 결과로 이어지기 때문에 서로 가까운 값이 많은 경우에만 실제로 중요합니다 .
분산 계산 (제곱 편차)에서 샘플 수 (N)로 나누는 것과 N-1 사이의 차이를 살펴볼 수도 있습니다. N-1로 나누면 표본에서 편향되지 않은 분산 추정값이 생성되는 반면, 평균 N으로 나누면 분산이 과소 평가됩니다 (표본 평균과 실제 평균 사이의 분산을 고려하지 않기 때문).
온라인에서 이전 값을 삭제하는 방법을 포함하여 더 자세한 내용을 다루는 주제에 대한 두 개의 블로그 항목을 작성했습니다.
내 Java 구현을 살펴볼 수도 있습니다. javadoc, 소스 및 단위 테스트는 모두 온라인입니다.
답변
기본적인 대답은 x ( ‘sum_x1’이라고 부름)와 x 2 ( ‘sum_x2’라고 부름)의 합계를 모으는 것입니다. 표준 편차의 값은 다음과 같습니다.
stdev = sqrt((sum_x2 / n) - (mean * mean))
어디
mean = sum_x / n
이것은 표본 표준 편차입니다. 제수로 ‘n-1’대신 ‘n’을 사용하여 모집단 표준 편차를 얻습니다.
큰 표본을 다루는 경우 두 큰 숫자 간의 차이를 가져 오는 수치 안정성에 대해 걱정해야 할 수도 있습니다. 자세한 내용은 다른 답변 (Wikipedia 등)의 외부 참조로 이동하십시오.
답변
다음은 http://www.johndcook.com/standard_deviation.html 에서 Welford 알고리즘 구현의 문자 그대로 순수한 Python 번역입니다 . .
https://github.com/liyanage/python-modules/blob/master/running_stats.py
import math
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()
print(f'Mean: {mean}, Variance: {variance}, Std. Dev.: {stdev}')
답변
아마도 당신이 요청한 것은 아니지만 … numpy 배열을 사용하면 효율적으로 작업을 수행합니다.
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 ]
그건 그렇고,이 블로그 게시물에는 평균과 분산을 계산하기위한 원 패스 방법에 대한 몇 가지 흥미로운 토론이 있습니다.
답변
파이썬 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()
통계 요약은 Art of Computer Programming, Vol 2, p에 설명 된대로 한 번의 패스로 표준 편차를 계산하기위한 Knuth 및 Welford 방법을 기반으로합니다. 232, 3 판. 이것의 이점은 수치 적으로 안정적이고 정확한 결과입니다.
면책 조항 : 저는 Python runstats 모듈의 작성자입니다.
답변
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
답변
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]
통계 에 대한 자세한 내용
은 PDL :: Primitive 를 참조하십시오. 함수 . 이것은 ADEV가 “표준 편차”임을 시사하는 것 같습니다.
그러나 PRMS (Sinan의 Statistics :: Descriptive 예제가 표시됨) 또는 RMS (ars의 NumPy 예제가 표시됨) 일 수 있습니다. 이 세 가지 중 하나가 맞을 것 같아요 😉
자세한 PDL 정보는 다음을 참조하십시오.