Masalah ini memerlukan skor-z atau skor standar, yang akan memperhitungkan rata-rata historis, seperti yang disebutkan orang lain, tetapi juga simpangan baku dari data historis ini, membuatnya lebih kuat daripada hanya menggunakan rata-rata.
Dalam kasus Anda, skor-z dihitung dengan rumus berikut, di mana trennya adalah tingkat seperti pandangan / hari.
z-score = ([current trend] - [average historic trends]) / [standard deviation of historic trends]
Ketika skor-z digunakan, semakin tinggi atau lebih rendah skor-z semakin tren abnormal, jadi misalnya jika skor-z sangat positif maka trennya naik secara tidak normal, sedangkan jika sangat negatif itu akan jatuh secara tidak normal . Jadi, begitu Anda menghitung skor-z untuk semua tren kandidat, skor-10 tertinggi akan berhubungan dengan skor-z yang paling tidak normal.
Silakan lihat Wikipedia untuk informasi lebih lanjut, tentang skor-z.
Kode
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
Output Sampel
>>> 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
Catatan
Anda dapat menggunakan metode ini dengan jendela geser (yaitu 30 hari terakhir) jika Anda tidak ingin memperhitungkan banyak riwayat, yang akan membuat tren jangka pendek lebih jelas dan dapat mengurangi waktu pemrosesan.
Anda juga dapat menggunakan skor-z untuk nilai-nilai seperti perubahan tampilan dari satu hari ke hari berikutnya untuk menemukan nilai abnormal untuk meningkatkan / menurunkan tampilan per hari. Ini seperti menggunakan kemiringan atau turunan dari grafik tampilan per hari.
Jika Anda melacak ukuran populasi saat ini, total populasi saat ini, dan total populasi saat ini x ^ 2, Anda tidak perlu menghitung ulang nilai-nilai ini, hanya memperbaruinya dan karenanya Anda hanya perlu simpan nilai-nilai ini untuk histori, bukan setiap nilai data. Kode berikut menunjukkan ini.
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()
Dengan menggunakan metode ini alur kerja Anda adalah sebagai berikut. Untuk setiap topik, tag, atau halaman buat bidang floating point, untuk jumlah hari, jumlah tampilan, dan jumlah tampilan yang dikuadratkan dalam database Anda. Jika Anda memiliki data historis, inisialisasi bidang ini menggunakan data itu, jika tidak, inisialisasi ke nol. Pada akhir setiap hari, hitung skor-z menggunakan jumlah tampilan hari itu terhadap data historis yang disimpan dalam tiga bidang basis data. Topik, tag, atau halaman, dengan skor X z tertinggi adalah "tren terpanas" Anda hari ini. Terakhir perbarui masing-masing 3 bidang dengan nilai hari dan ulangi proses besok.
Penambahan Baru
Skor-z normal seperti yang dibahas di atas tidak memperhitungkan urutan data dan karenanya skor-z untuk pengamatan '1' atau '9' akan memiliki besaran yang sama terhadap urutan [1, 1, 1, 1 , 9, 9, 9, 9]. Jelas untuk penemuan tren, data terbaru harus memiliki bobot lebih dari data yang lebih tua dan karenanya kami ingin observasi '1' memiliki skor magnitudo lebih besar daripada observasi '9'. Untuk mencapai ini, saya mengusulkan skor-z mengambang. Harus jelas bahwa metode ini TIDAK dijamin secara statistik baik tetapi harus berguna untuk menemukan tren atau serupa. Perbedaan utama antara skor-z standar dan rata-rata mengambang skor-z adalah penggunaan rata-rata mengambang untuk menghitung nilai populasi rata-rata dan nilai populasi rata-rata kuadrat. Lihat kode untuk detail:
Kode
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()
Contoh IO
>>> 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
Memperbarui
Seperti yang David Kemp tunjukkan dengan benar, jika diberikan serangkaian nilai konstan dan kemudian zscore untuk nilai yang diamati yang berbeda dari nilai-nilai lain yang diminta hasilnya mungkin harus tidak nol. Bahkan nilai yang dikembalikan harus tak terhingga. Jadi saya mengubah baris ini,
if self.std() == 0: return 0
untuk:
if self.std() == 0: return (obs - self.avg) * float("infinity")
Perubahan ini tercermin dalam kode solusi fazscore. Jika seseorang tidak ingin berurusan dengan nilai-nilai tak terbatas, solusi yang dapat diterima adalah mengubah baris menjadi:
if self.std() == 0: return obs - self.avg