Bu sorun, diğer insanların belirttiği gibi, tarihsel ortalamayı dikkate alacak bir z skoru veya standart puan gerektirir, ancak bu geçmiş verilerin standart sapmasını da sadece ortalamayı kullanmaktan daha sağlam hale getirir.
Sizin durumunuzda, z-puanı, aşağıdaki formülle hesaplanır; buradaki eğilim, görüntüleme / gün gibi bir oran olacaktır.
z-score = ([current trend] - [average historic trends]) / [standard deviation of historic trends]
Bir z-skoru kullanıldığında, z-skoru ne kadar yüksek veya düşükse eğilim o kadar anormal olur, bu nedenle örneğin z-skoru oldukça pozitifse, eğilim anormal bir şekilde yükselir, çok negatifse anormal olarak düşer . Bu nedenle, tüm aday trendler için z skorunu hesapladığınızda, en yüksek 10 z skoru, en anormal şekilde artan z skorlarıyla ilişkilendirilir.
Z skorları hakkında daha fazla bilgi için lütfen Wikipedia'ya bakınız .
kod
from math import sqrt
def zscore(obs, pop):
# Size of population.
number = float(len(pop))
# Average population value.
avg = sum(pop) / number
# Standard deviation of population.
std = sqrt(sum(((c - avg) ** 2) for c in pop) / number)
# Zscore Calculation.
return (obs - avg) / std
Örnek Çıktı
>>> zscore(12, [2, 4, 4, 4, 5, 5, 7, 9])
3.5
>>> zscore(20, [21, 22, 19, 18, 17, 22, 20, 20])
0.0739221270955
>>> zscore(20, [21, 22, 19, 18, 17, 22, 20, 20, 1, 2, 3, 1, 2, 1, 0, 1])
1.00303599234
>>> zscore(2, [21, 22, 19, 18, 17, 22, 20, 20, 1, 2, 3, 1, 2, 1, 0, 1])
-0.922793112954
>>> zscore(9, [1, 2, 0, 3, 1, 3, 1, 2, 9, 8, 7, 10, 9, 5, 2, 4, 1, 1, 0])
1.65291949506
notlar
Kısa vadeli eğilimleri daha belirgin hale getirecek ve işlem süresini kısaltabilecek olan çok fazla geçmişi dikkate almak istemiyorsanız, bu yöntemi kayan bir pencereyle (yani son 30 gün) kullanabilirsiniz.
Ayrıca, günlük görüntüleme sayısını artırmak / azaltmak için anormal değerleri bulmak için bir günden sonraki güne görünüm değişikliği gibi değerler için bir z puanı kullanabilirsiniz. Bu, günlük görünümlerin eğiminin veya türevinin kullanılması gibidir.
Nüfusun mevcut boyutunu, nüfusun mevcut toplamını ve nüfusun mevcut toplam x ^ 2'sini takip ederseniz, bu değerleri yeniden hesaplamanıza, yalnızca güncellemenize ve bu nedenle yalnızca bu değerleri her veri değeri için değil, geçmiş için saklayın. Aşağıdaki kod bunu göstermektedir.
from math import sqrt
class zscore:
def __init__(self, pop = []):
self.number = float(len(pop))
self.total = sum(pop)
self.sqrTotal = sum(x ** 2 for x in pop)
def update(self, value):
self.number += 1.0
self.total += value
self.sqrTotal += value ** 2
def avg(self):
return self.total / self.number
def std(self):
return sqrt((self.sqrTotal / self.number) - self.avg() ** 2)
def score(self, obs):
return (obs - self.avg()) / self.std()
Bu yöntemi kullanarak iş akışınız aşağıdaki gibi olacaktır. Her konu, etiket veya sayfa için, toplam gün sayısı, görünümlerin toplamı ve veritabanınızdaki karelerin toplamları için bir kayan nokta alanı oluşturun. Geçmiş verileriniz varsa bu alanları bu verileri kullanarak başlatın, aksi halde sıfıra başlatın. Her günün sonunda, üç veritabanı alanında depolanan geçmiş verilere karşı günün görüntüleme sayısını kullanarak z skorunu hesaplayın. En yüksek X z puanına sahip konular, etiketler veya sayfalar, günün X "en sıcak trendleri" dir. Son olarak 3 alanın her birini günün değeri ile güncelleyin ve işlemi yarın tekrarlayın.
Yeni eklenti
Yukarıda tartışıldığı gibi normal z-skorları verilerin sırasını dikkate almaz ve bu nedenle '1' veya '9' gözlemi için z-skoru sekansa karşı aynı büyüklüğe sahip olacaktır [1, 1, 1, 1 , 9, 9, 9, 9]. Açıkçası, eğilim bulmak için, en güncel veriler daha eski verilerden daha fazla ağırlığa sahip olmalıdır ve bu nedenle '1' gözleminin '9' gözleminden daha büyük bir büyüklük skoruna sahip olmasını istiyoruz. Bunu başarmak için değişken bir ortalama z puanı öneriyorum. Bu yöntemin istatistiksel olarak sağlam olduğu garanti EDİLMEDİĞİ açık olmalıdır, ancak eğilim bulma veya benzeri için yararlı olmalıdır. Standart z-skoru ve değişken ortalama z-skoru arasındaki temel fark, ortalama nüfus değerini ve ortalama nüfus değerinin karesini hesaplamak için değişken bir ortalamanın kullanılmasıdır. Ayrıntılar için koda bakın:
kod
class fazscore:
def __init__(self, decay, pop = []):
self.sqrAvg = self.avg = 0
# The rate at which the historic data's effect will diminish.
self.decay = decay
for x in pop: self.update(x)
def update(self, value):
# Set initial averages to the first value in the sequence.
if self.avg == 0 and self.sqrAvg == 0:
self.avg = float(value)
self.sqrAvg = float((value ** 2))
# Calculate the average of the rest of the values using a
# floating average.
else:
self.avg = self.avg * self.decay + value * (1 - self.decay)
self.sqrAvg = self.sqrAvg * self.decay + (value ** 2) * (1 - self.decay)
return self
def std(self):
# Somewhat ad-hoc standard deviation calculation.
return sqrt(self.sqrAvg - self.avg ** 2)
def score(self, obs):
if self.std() == 0: return (obs - self.avg) * float("infinity")
else: return (obs - self.avg) / self.std()
Örnek ES
>>> fazscore(0.8, [1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9]).score(1)
-1.67770595327
>>> fazscore(0.8, [1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9]).score(9)
0.596052006642
>>> fazscore(0.9, [2, 4, 4, 4, 5, 5, 7, 9]).score(12)
3.46442230724
>>> fazscore(0.9, [2, 4, 4, 4, 5, 5, 7, 9]).score(22)
7.7773245459
>>> fazscore(0.9, [21, 22, 19, 18, 17, 22, 20, 20]).score(20)
-0.24633160155
>>> fazscore(0.9, [21, 22, 19, 18, 17, 22, 20, 20, 1, 2, 3, 1, 2, 1, 0, 1]).score(20)
1.1069362749
>>> fazscore(0.9, [21, 22, 19, 18, 17, 22, 20, 20, 1, 2, 3, 1, 2, 1, 0, 1]).score(2)
-0.786764452966
>>> fazscore(0.9, [1, 2, 0, 3, 1, 3, 1, 2, 9, 8, 7, 10, 9, 5, 2, 4, 1, 1, 0]).score(9)
1.82262469243
>>> fazscore(0.8, [40] * 200).score(1)
-inf
Güncelleme
David Kemp'in doğru bir şekilde işaret ettiği gibi, bir dizi sabit değer ve daha sonra gözlemlenen bir değer için diğer değerlerden farklı bir zscore istenirse, sonuç muhtemelen sıfır olmamalıdır. Aslında döndürülen değer sonsuz olmalıdır. Bu yüzden bu çizgiyi değiştirdim,
if self.std() == 0: return 0
için:
if self.std() == 0: return (obs - self.avg) * float("infinity")
Bu değişiklik fazscore çözüm koduna yansır. Eğer biri sonsuz değerlerle uğraşmak istemiyorsa, kabul edilebilir bir çözüm satırı aşağıdaki gibi değiştirmek olabilir:
if self.std() == 0: return obs - self.avg