मैंने अतीत में निम्न दृष्टिकोण का उपयोग कुशलता से अनुपस्थिति विचलन की गणना करने के लिए किया है (ध्यान दें, यह एक प्रोग्रामर दृष्टिकोण है, न कि एक सांख्यिकीविद्, इसलिए अप्रत्यक्ष रूप से shabbychef की तरह चतुर चाल हो सकती है जो अधिक कुशल हो सकती है)।
चेतावनी: यह एक ऑनलाइन एल्गोरिथ्म नहीं है। इसके लिए O(n)
स्मृति की आवश्यकता होती है। इसके अलावा, इसमें O(n)
डेटासेट के लिए सबसे खराब स्थिति है [1, -2, 4, -8, 16, -32, ...]
(जैसे कि पूर्ण पुनर्गणना के समान)। [1]
हालाँकि, क्योंकि यह अभी भी कई उपयोग के मामलों में अच्छा प्रदर्शन करता है, यह यहाँ पोस्ट करने लायक हो सकता है। उदाहरण के लिए, प्रत्येक आइटम के आते ही -100 और 100 के बीच 10000 यादृच्छिक संख्याओं की पूर्ण अवमूल्यन की गणना करने के लिए , मेरा एल्गोरिथ्म एक सेकंड से भी कम समय लेता है, जबकि पूर्ण पुनर्गणना में 17 सेकंड से अधिक समय लगता है (मेरी मशीन पर, प्रति मशीन अलग-अलग होगी और इनपुट डेटा के अनुसार)। आपको हालाँकि पूरे सदिश को स्मृति में बनाए रखना होगा, जो कुछ उपयोगों के लिए एक बाधा हो सकती है। एल्गोरिथ्म की रूपरेखा निम्नानुसार है:
- पिछले मापों को संग्रहीत करने के लिए एक एकल वेक्टर होने के बजाय, तीन क्रमबद्ध प्राथमिकता वाले कतारों (कुछ मिनट / अधिकतम ढेर) का उपयोग करें। ये तीन सूचियाँ इनपुट को तीन में विभाजित करती हैं: माध्य से अधिक आइटम, माध्य से कम वस्तु और माध्य के बराबर आइटम।
- (लगभग) हर बार जब आप किसी आइटम को जोड़ते हैं, तो हमें बदलाव की आवश्यकता होती है। महत्वपूर्ण बात यह है कि विभाजन की छँटाई प्रकृति है जिसका अर्थ है कि सूची में प्रत्येक आइटम को पुनरावृत्ति के लिए स्कैन करने के बजाय, हमें केवल उन वस्तुओं को पढ़ना होगा जो हम आगे बढ़ रहे हैं। हालांकि सबसे खराब स्थिति में इसके लिए अभी भी
O(n)
कदम संचालन की आवश्यकता होगी , कई उपयोग-मामलों के लिए ऐसा नहीं है।
- कुछ चतुर बहीखाते का उपयोग करते हुए, हम यह सुनिश्चित कर सकते हैं कि हर समय, जब पुनरावृत्ति हो रही हो और नई वस्तुओं को जोड़ते समय विचलन की सही गणना की जाए।
कुछ नमूना कोड, अजगर में, नीचे है। ध्यान दें कि यह केवल आइटम को सूची में जोड़ने की अनुमति देता है, हटाए नहीं। यह आसानी से जोड़ा जा सकता है, लेकिन जिस समय मैंने यह लिखा था मुझे इसकी कोई आवश्यकता नहीं थी। प्राथमिकता कतारों अपने आप को लागू करने के बजाय, मैं का इस्तेमाल किया है sortedlist डैनियल Stutzbach उत्तम से blist पैकेज है, जो उपयोग बी + ट्री आंतरिक रूप से है।
एमआईटी लाइसेंस के तहत लाइसेंस प्राप्त इस कोड पर विचार करें । यह काफी अनुकूलित या पॉलिश नहीं किया गया है, लेकिन मेरे लिए अतीत में काम किया है। नए संस्करण यहां उपलब्ध होंगे । यदि आपके कोई प्रश्न हैं, या कोई बग ढूंढते हैं तो मुझे बताएं।
from blist import sortedlist
import operator
class deviance_list:
def __init__(self):
self.mean = 0.0
self._old_mean = 0.0
self._sum = 0L
self._n = 0 #n items
# items greater than the mean
self._toplist = sortedlist()
# items less than the mean
self._bottomlist = sortedlist(key = operator.neg)
# Since all items in the "eq list" have the same value (self.mean) we don't need
# to maintain an eq list, only a count
self._eqlistlen = 0
self._top_deviance = 0
self._bottom_deviance = 0
@property
def absolute_deviance(self):
return self._top_deviance + self._bottom_deviance
def append(self, n):
# Update summary stats
self._sum += n
self._n += 1
self._old_mean = self.mean
self.mean = self._sum / float(self._n)
# Move existing things around
going_up = self.mean > self._old_mean
self._rebalance(going_up)
# Add new item to appropriate list
if n > self.mean:
self._toplist.add(n)
self._top_deviance += n - self.mean
elif n == self.mean:
self._eqlistlen += 1
else:
self._bottomlist.add(n)
self._bottom_deviance += self.mean - n
def _move_eqs(self, going_up):
if going_up:
self._bottomlist.update([self._old_mean] * self._eqlistlen)
self._bottom_deviance += (self.mean - self._old_mean) * self._eqlistlen
self._eqlistlen = 0
else:
self._toplist.update([self._old_mean] * self._eqlistlen)
self._top_deviance += (self._old_mean - self.mean) * self._eqlistlen
self._eqlistlen = 0
def _rebalance(self, going_up):
move_count, eq_move_count = 0, 0
if going_up:
# increase the bottom deviance of the items already in the bottomlist
if self.mean != self._old_mean:
self._bottom_deviance += len(self._bottomlist) * (self.mean - self._old_mean)
self._move_eqs(going_up)
# transfer items from top to bottom (or eq) list, and change the deviances
for n in iter(self._toplist):
if n < self.mean:
self._top_deviance -= n - self._old_mean
self._bottom_deviance += (self.mean - n)
# we increment movecount and move them after the list
# has finished iterating so we don't modify the list during iteration
move_count += 1
elif n == self.mean:
self._top_deviance -= n - self._old_mean
self._eqlistlen += 1
eq_move_count += 1
else:
break
for _ in xrange(0, move_count):
self._bottomlist.add(self._toplist.pop(0))
for _ in xrange(0, eq_move_count):
self._toplist.pop(0)
# decrease the top deviance of the items remain in the toplist
self._top_deviance -= len(self._toplist) * (self.mean - self._old_mean)
else:
if self.mean != self._old_mean:
self._top_deviance += len(self._toplist) * (self._old_mean - self.mean)
self._move_eqs(going_up)
for n in iter(self._bottomlist):
if n > self.mean:
self._bottom_deviance -= self._old_mean - n
self._top_deviance += n - self.mean
move_count += 1
elif n == self.mean:
self._bottom_deviance -= self._old_mean - n
self._eqlistlen += 1
eq_move_count += 1
else:
break
for _ in xrange(0, move_count):
self._toplist.add(self._bottomlist.pop(0))
for _ in xrange(0, eq_move_count):
self._bottomlist.pop(0)
# decrease the bottom deviance of the items remain in the bottomlist
self._bottom_deviance -= len(self._bottomlist) * (self._old_mean - self.mean)
if __name__ == "__main__":
import random
dv = deviance_list()
# Test against some random data, and calculate result manually (nb. slowly) to ensure correctness
rands = [random.randint(-100, 100) for _ in range(0, 1000)]
ns = []
for n in rands:
dv.append(n)
ns.append(n)
print("added:%4d, mean:%3.2f, oldmean:%3.2f, mean ad:%3.2f" %
(n, dv.mean, dv._old_mean, dv.absolute_deviance / dv.mean))
assert sum(ns) == dv._sum, "Sums not equal!"
assert len(ns) == dv._n, "Counts not equal!"
m = sum(ns) / float(len(ns))
assert m == dv.mean, "Means not equal!"
real_abs_dev = sum([abs(m - x) for x in ns])
# Due to floating point imprecision, we check if the difference between the
# two ways of calculating the asb. dev. is small rather than checking equality
assert abs(real_abs_dev - dv.absolute_deviance) < 0.01, (
"Absolute deviances not equal. Real:%.2f, calc:%.2f" % (real_abs_dev, dv.absolute_deviance))
[१] यदि लक्षण बने रहते हैं, तो अपने चिकित्सक को देखें।