Geçmişte abartı sapmasını orta derecede verimli bir şekilde hesaplamak için aşağıdaki yaklaşımı kullandım (not, bu bir programcı yaklaşımı, bir istatistikçi değil, bu yüzden şüphesiz shabbychef'ler gibi akıllı hileler olabilir daha etkili olabilecek olabilir).
UYARI: Bu çevrimiçi bir algoritma değildir. O(n)
Bellek gerektirir . Ayrıca, en kötü durum performansına sahiptir.O(n)
gibi veri kümeleri için[1, -2, 4, -8, 16, -32, ...]
(yani tam yeniden hesaplama ile aynı). [1]
Bununla birlikte, birçok kullanım durumunda hala iyi performans gösterdiğinden, burada göndermeye değer olabilir. Örneğin, 10000 rasgele mutlak sapmayı hesaplamak için her öğe geldiğinde -100 ile 100 arasında sayının algoritmam bir saniyeden az sürer, tam yeniden hesaplama 17 saniyeyi alır (makinemde makine ve giriş verilerine göre). Bununla birlikte, tüm vektörleri bellekte tutmanız gerekir; bu, bazı kullanımlar için bir kısıtlama olabilir. Algoritmanın ana hatları aşağıdaki gibidir:
- Geçmiş ölçümleri saklamak için tek bir vektöre sahip olmak yerine, üç sıralı öncelik sırası kullanın (min / maks öbek gibi bir şey). Bu üç liste girdiyi üçe ayırır: ortalamadan büyük öğeler, ortalamadan küçük öğeler ve ortalamaya eşit öğeler.
- (Neredeyse) her ürün eklediğinizde ortalama değişiklikler olur, bu yüzden bölümlere ayırmamız gerekir. Önemli olan bölümlerin sıralı doğasıdır, yani listedeki her öğeyi yeniden parçalanmaya taramak yerine, yalnızca taşıdığımız öğeleri okumamız gerekir. En kötü durumda bu yine de gerektirir
O(n)
hareket operasyonları , ancak birçok kullanım durumunda bu böyle değildir.
- Bazı akıllı defter tutma yöntemlerini kullanarak, yeniden bölümleme yaparken ve yeni öğeler eklerken sapmanın her zaman doğru hesaplandığından emin olabiliriz.
Python'da bazı örnek kodlar aşağıdadır. Yalnızca öğelerin listeye eklenmesine izin verildiğini, kaldırılmadığını unutmayın. Bu kolayca eklenebilir, ancak bunu yazdığım zaman buna ihtiyacım yoktu. Aksine öncelikli kuyruklar kendim uygulamak yerine, ben kullandım SortedList Daniel Stutzbach mükemmel dan blist paketin kullanmak, B + Ağacı içten s.
MIT lisansı altında lisanslanan bu kodu göz önünde bulundurun . Önemli ölçüde optimize edilmemiş veya cilalanmamış, ancak geçmişte benim için çalıştı. Yeni sürümler burada mevcut olacak . Herhangi bir sorunuz varsa bize bildirin veya herhangi bir hata bulun.
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))
[1] Semptomlar devam ederse, doktorunuza başvurun.