कुशलतापूर्वक चलने वाले मानक विचलन की गणना कैसे करें?


87

मेरे पास संख्याओं की सूची की एक सरणी है, उदाहरण के लिए:

[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(मैं आबादी के साथ काम कर रहा हूं, जनसंख्या से नमूना नहीं)।

मानक विचलन करने के लिए, मैं फिर से लूप करता हूं, अब मेरे पास गणना का मतलब है।

मैं सरणी के माध्यम से दो बार जाने से बचना चाहूंगा, एक बार मतलब के लिए और फिर एक बार एसडी के लिए (मेरे पास एक मतलब होने के बाद)।

क्या दोनों मानों की गणना के लिए एक कुशल विधि है, केवल एक बार सरणी से गुजर रही है? एक व्याख्या की गई भाषा में कोई भी कोड (जैसे पर्ल या पायथन) या स्यूडोकोड ठीक है।


7
अलग-अलग भाषा, लेकिन एक ही एल्गोरिथ्म: stackoverflow.com/questions/895929/…
dmckee --- पूर्व-मध्यस्थ ने बिल्ली का बच्चा

धन्यवाद, मैं उस एल्गोरिथ्म की जाँच करूँगा। लगता है कि मुझे क्या चाहिए।
एलेक्स रेनॉल्ड्स

मुझे सही उत्तर देने के लिए धन्यवाद, dmckee। मैं आपको "सर्वश्रेष्ठ उत्तर" चेकमार्क देना चाहूंगा, यदि आप अपना उत्तर नीचे जोड़ने के लिए एक पल लेना चाहते हैं (यदि आप अंक चाहते हैं)।
एलेक्स रेनॉल्ड्स


1
विकिपीडिया के पास पायथन कार्यान्वयन en.wikipedia.org/wiki/… है
हामिश ग्रुबीजन

जवाबों:


116

इसका उत्तर वेलफ़ोर्ड के एल्गोरिथ्म का उपयोग करना है, जिसे "भोले तरीकों" के बाद बहुत स्पष्ट रूप से परिभाषित किया गया है:

यह अन्य प्रतिक्रियाओं में सुझाए गए दो कलेक्टरों के ऑनलाइन-पास या ऑनलाइन सरल योग की तुलना में अधिक संख्यात्मक रूप से स्थिर है। स्थिरता केवल वास्तव में मायने रखती है जब आपके पास बहुत सारे मूल्य होते हैं जो एक दूसरे के करीब होते हैं क्योंकि वे तैरते बिंदु साहित्य में " प्रलयकारी रद्द " के रूप में जाने जाते हैं ।

आप विचरण गणना में नमूनों (N) और N-1 की संख्या से विभाजित करने के बीच के अंतर पर भी ब्रश करना चाह सकते हैं। N-1 द्वारा विभाजित करने से नमूने से भिन्नता का एक निष्पक्ष अनुमान होता है, जबकि N द्वारा औसतन विभाजन को कम करके आंका जाता है (क्योंकि यह नमूना माध्य और सही माध्य के बीच विचरण को ध्यान में नहीं रखता है)।

मैंने उस विषय पर दो ब्लॉग प्रविष्टियाँ लिखी हैं जो अधिक विवरणों में जाती हैं, जिसमें ऑनलाइन पिछले मानों को कैसे हटाया जाए:

आप मेरे जावा कार्यान्वयन पर भी नज़र डाल सकते हैं; javadoc, स्रोत, और यूनिट परीक्षण सभी ऑनलाइन हैं:


1
Welford के एल्गोरिथ्म से मूल्यों को हटाने के बारे में ध्यान रखने के लिए +1
वेलफोर्ड

3
अच्छा उत्तर, जनसंख्या stddev और नमूना stddev के बीच अंतर के पाठक को याद दिलाने के लिए +1।
असद अब्राहिम

इन सभी वर्षों के बाद इस सवाल पर वापस आने के बाद, मैं सिर्फ एक महान जवाब देने के लिए समय निकालने के लिए धन्यवाद शब्द कहना चाहता था।
एलेक्स रेनॉल्ड्स

76

मूल उत्तर दोनों x का योग संचित करना है (इसे 'sum_x1') और x 2 (इसे 'sum_x2' कहें) जैसे आप जाते हैं। मानक विचलन का मान तब है:

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

कहाँ पे

mean = sum_x / n

यह नमूना मानक विचलन है; आपको विभाजक के रूप में 'n - 1' के बजाय 'n' का उपयोग करके जनसंख्या मानक विचलन मिलता है।

यदि आप बड़े नमूनों के साथ काम कर रहे हैं, तो दो बड़ी संख्याओं के बीच अंतर लेने की संख्यात्मक स्थिरता के बारे में चिंता करने की आवश्यकता हो सकती है। अधिक जानकारी के लिए अन्य उत्तरों (विकिपीडिया, आदि) में बाहरी संदर्भों पर जाएं।


यह मैं सुझाव देने वाला था। यह सबसे अच्छा और सबसे तेज़ तरीका है, सटीक त्रुटियों को मानते हुए कोई समस्या नहीं है।
रे हिदायत

2
मैंने Welford के एल्गोरिथ्म के साथ जाने का फैसला किया क्योंकि यह समान कम्प्यूटेशनल ओवरहेड के साथ अधिक मज़बूती से प्रदर्शन करता है।
एलेक्स रेनॉल्ड्स

2
यह उत्तर का एक सरलीकृत संस्करण है और इनपुट के आधार पर गैर-वास्तविक परिणाम दे सकता है (यानी, जब sum_x2 <sum_x1 * sum_x1)। एक वैध वास्तविक परिणाम सुनिश्चित करने के लिए, `sd = sqrt (((n * sum_x2) - (sum_x1 * sum_x1)) / (n * (n - 1))
Dan Tao

2
@ डान एक वैध मुद्दे को इंगित करता है - ऊपर दिया गया सूत्र x> 1 के लिए टूट जाता है क्योंकि आप एक नकारात्मक संख्या के sqrt को समाप्त करते हैं। नुथ दृष्टिकोण है: sqrt ((sum_x2 / n) - (माध्य * माध्य)) जहाँ माध्य = (sum_x / n)।
G__

1
@ युरीलोया - आपने मूल्यों की गणना कैसे की जाती है, इसके बारे में आपने कुछ नहीं कहा है। हालाँकि, यदि आप intC का उपयोग चौकों के योग को संग्रहीत करने के लिए करते हैं, तो आप उन मानों के साथ अतिप्रवाह की समस्याओं में भाग लेते हैं जिन्हें आप सूचीबद्ध करते हैं।
जोनाथन लेफ़लर

38

यहाँ http://www.johndcook.com/standard_deviya.html से Welford के एल्गोरिथ्म कार्यान्वयन का शाब्दिक शुद्ध पायथन अनुवाद है :

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}')

9
यह स्वीकृत उत्तर होना चाहिए क्योंकि यह केवल एक ही है जो दोनों सही है और एल्गोरिथ्म को दिखाता है, नथ के संदर्भ में।
जोहान लुंडबर्ग

26

शायद नहीं जो आप पूछ रहे थे, लेकिन ... यदि आप एक सुस्वादु सरणी का उपयोग करते हैं, तो यह आपके लिए कार्य कुशलता से करेगा:

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 ]

वैसे, इस ब्लॉग पोस्ट में कुछ दिलचस्प चर्चा है और कंप्यूटिंग साधनों और भिन्नताओं के लिए एक-पास तरीकों पर टिप्पणियां हैं:


14

अजगर runstats मॉड्यूल बात का सिर्फ इस तरह के लिए है। PyPI से रनस्टैट्स स्थापित करें :

pip install 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()

सांख्यिकी सारांश, कंप्यूटर प्रोग्रामिंग, वॉल्यूम 2, पी के कला में वर्णित एक पास में मानक विचलन की गणना के लिए नथ और वेलफोर्ड विधि पर आधारित हैं। 232, तीसरा संस्करण। इसका लाभ संख्यात्मक रूप से स्थिर और सटीक परिणाम है।

अस्वीकरण: मैं लेखक पायथन रनस्टेट्स मॉड्यूल हूं।


अच्छा मॉड्यूल। यह दिलचस्प होगा यदि Statisticsकोई .popविधि है तो रोलिंग आँकड़ों की गणना भी की जा सकती है।
गुस्तावो बीज़र्रा

@GustavoBezerra runstatsमानों की आंतरिक सूची को बनाए नहीं रखता है इसलिए मुझे यकीन नहीं है कि यह संभव है। लेकिन पुल अनुरोधों का स्वागत है।
ग्रांटज

8

सांख्यिकी :: वर्णनात्मक इन प्रकार की गणनाओं के लिए एक बहुत ही सभ्य पर्ल मॉड्यूल है:

#!/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

पीडीएल पर एक नज़र डालें (उच्चारण "पहेली!")।

यह पर्ल डेटा लैंग्वेज है जिसे उच्च परिशुद्धता गणित और वैज्ञानिक कंप्यूटिंग के लिए डिज़ाइन किया गया है।

आपके आंकड़ों का उपयोग करके एक उदाहरण यहां दिया गया है ...।

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]


पीडीएल पर एक नजर है :: आँकड़ों पर अधिक जानकारी के लिए आदिम समारोह । ऐसा लगता है कि ADEV "मानक विचलन" है।

हालाँकि यह शायद PRMS (जो सिनान के आँकड़े :: वर्णनात्मक उदाहरण दिखाते हैं) या RMS (जो ars का NumPy उदाहरण दिखाता है)। मुझे लगता है कि इन तीनों में से एक सही होना चाहिए ;-)

अधिक पीडीएल जानकारी के लिए इस पर एक नज़र डालें:


1
यह एक चलने वाली गणना नहीं है।
जेक

3

आपकी सरणी कितनी बड़ी है? जब तक कि यह लंबे समय तक तत्वों का नहीं है, तब तक दो बार इसके माध्यम से लूपिंग के बारे में चिंता न करें। कोड सरल और आसानी से परीक्षण किया जाता है।

मेरी प्राथमिकता संख्यात्मक सारणी एक्सटेंशन का उपयोग करके अपने सरणी के सारणियों को एक सुस्पष्ट 2D सरणी में बदलना और सीधे मानक देवता प्राप्त करना होगा:

>>> 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])

यदि वह विकल्प नहीं है और आपको शुद्ध पायथन समाधान की आवश्यकता है, तो पढ़ते रहें ...

अगर आपकी सरणी है

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

यह ऊपर सूचीबद्ध सूची समाधान के रूप में लगभग सुरुचिपूर्ण नहीं है।


मुझे वास्तव में संख्याओं के ज़िलों से निपटना है, जो कि एक कुशल समाधान के लिए मेरी आवश्यकता को प्रेरित करता है। धन्यवाद!
एलेक्स रेनॉल्ड्स

इसका डेटा सेट कितना बड़ा है, इसके बारे में, OFTEN के बारे में, मुझे प्रत्येक गणना पर प्रति सेकंड 500 से अधिक तत्वों पर 3500 विभिन्न मानक विचलन गणना
करनी है

1

आप मानक विचलन पर विकिपीडिया लेख को देख सकते हैं , विशेष रूप से रैपिड गणना विधियों के बारे में।

वहाँ भी एक लेख है जो मैंने पाया कि पायथन का उपयोग करता है, आपको बहुत अधिक बदलाव के बिना इसमें कोड का उपयोग करने में सक्षम होना चाहिए: अचेतन संदेश - रनिंग मानक विचलन


अचेतन संदेश संस्करण संख्यात्मक रूप से बहुत स्थिर नहीं है।
डेव

1

मुझे लगता है कि यह मुद्दा आपकी मदद करेगा। मानक विचलन


+1 @Lasse V. कर्लसेन का विकिपीडिया के लिए लिंक अच्छा है, लेकिन यह सही एल्गोरिथ्म है जिसका मैंने उपयोग किया है ...
kenn

1

यहां एक "वन-लाइनर" है, जो कार्यात्मक प्रोग्रामिंग शैली में कई लाइनों में फैला है:

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)))

1
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

1

जैसा कि निम्नलिखित उत्तर का वर्णन करता है: क्या पांडा / स्किपी / सुपी एक संचयी मानक विचलन फ़ंक्शन प्रदान करता है? पायथन पंडों मॉड्यूल में चल रहे या संचयी मानक विचलन की गणना करने की एक विधि है । उसके लिए आपको अपने डेटा को पांडा डेटाफ़्रेम (या यदि यह 1D है तो एक श्रृंखला) में बदलना होगा, लेकिन इसके लिए कार्य हैं।


1

मैं इस तरह से अपडेट व्यक्त करना चाहता हूं:

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)

ताकि एक-पास फ़ंक्शन इस तरह दिखाई दे:

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 / (N-1) सामान्यकरण कारक का उपयोग करता है)। अन्य उत्तरों के विपरीत, चर,var पर नज़र रखने वाला नमूनों की संख्या के अनुपात में नहीं बढ़ता है। हर समय यह अभी तक देखे गए नमूनों के समुच्चय का विचरण है (विचरण प्राप्त करने में कोई अंतिम "एन द्वारा विभाजन" नहीं है)।

एक कक्षा में यह इस तरह दिखेगा:

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)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.