यह समस्या एक z- स्कोर या मानक स्कोर के लिए कॉल करती है, जो ऐतिहासिक औसत को ध्यान में रखेगा, जैसा कि अन्य लोगों ने उल्लेख किया है, लेकिन इस ऐतिहासिक डेटा का मानक विचलन भी है, यह औसत का उपयोग करने की तुलना में अधिक मजबूत बनाता है।
आपके मामले में एक z- स्कोर की गणना निम्न सूत्र द्वारा की जाती है, जहां रुझान दर / दृश्य जैसे दिन होगा।
z-score = ([current trend] - [average historic trends]) / [standard deviation of historic trends]
जब z- स्कोर का उपयोग किया जाता है, तो z या स्कोर अधिक असामान्य प्रवृत्ति को कम करता है, इसलिए उदाहरण के लिए यदि z- स्कोर अत्यधिक सकारात्मक है, तो प्रवृत्ति असामान्य रूप से बढ़ रही है, जबकि यदि यह अत्यधिक नकारात्मक है तो यह असामान्य रूप से गिर रहा है । एक बार जब आप सभी उम्मीदवारों के रुझानों के लिए z- स्कोर की गणना करते हैं तो उच्चतम 10 z-स्कोर सबसे असामान्य रूप से बढ़ते हुए z- स्कोर से संबंधित होंगे।
कृपया अधिक जानकारी के लिए विकिपीडिया देखें, z- स्कोर के बारे में।
कोड
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
नमूना आउटपुट
>>> 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
टिप्पणियाँ
यदि आप बहुत अधिक इतिहास को ध्यान में नहीं रखना चाहते हैं, तो आप इस पद्धति का उपयोग एक स्लाइडिंग विंडो (पिछले 30 दिनों में) के साथ कर सकते हैं, जो अल्पावधि रुझानों को अधिक स्पष्ट कर देगा और प्रसंस्करण समय में कटौती कर सकता है।
प्रति दिन बढ़ते / घटते विचारों के असामान्य मूल्यों का पता लगाने के लिए आप एक दिन से दूसरे दिन के विचारों में परिवर्तन जैसे मूल्यों के लिए एक z- स्कोर का उपयोग कर सकते हैं। यह प्रति दिन के ग्राफ़ के ढलान या व्युत्पन्न का उपयोग करने जैसा है।
यदि आप जनसंख्या के वर्तमान आकार, जनसंख्या के वर्तमान कुल और जनसंख्या के x ^ 2 के वर्तमान कुल का ध्यान रखते हैं, तो आपको इन मूल्यों को पुनर्गणना करने की आवश्यकता नहीं है, केवल उन्हें अपडेट करें और इसलिए आपको केवल इसकी आवश्यकता है इतिहास के लिए इन मूल्यों को रखें, प्रत्येक डेटा मूल्य नहीं। निम्न कोड यह प्रदर्शित करता है।
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()
इस विधि का उपयोग करने से आपका कार्य प्रवाह इस प्रकार होगा। प्रत्येक विषय के लिए, टैग, या पेज एक फ्लोटिंग पॉइंट फ़ील्ड बनाते हैं, जो आपके डेटाबेस में कुल दिनों की संख्या, विचारों का योग और विचारों का योग है। यदि आपके पास ऐतिहासिक डेटा है, तो उस डेटा का उपयोग करके इन फ़ील्ड्स को इनिशियलाइज़ करें, अन्यथा शून्य पर इनिशियलाइज़ करें। प्रत्येक दिन के अंत में, तीन डेटाबेस फ़ील्ड में संग्रहीत ऐतिहासिक डेटा के विरुद्ध दिन के विचारों की संख्या का उपयोग करके z- स्कोर की गणना करें। उच्चतम X z- स्कोर वाले विषय, टैग या पृष्ठ, दिन के आपके X "हॉटेस्ट ट्रेंड" हैं। अंत में दिन के मूल्य के साथ 3 क्षेत्रों में से प्रत्येक को अपडेट करें और कल प्रक्रिया को दोहराएं।
नया जोड़
सामान्य z- स्कोर जैसा कि ऊपर चर्चा की गई है, डेटा के क्रम को ध्यान में नहीं रखते हैं और इसलिए '1' या '9' के अवलोकन के लिए z- स्कोर के अनुक्रम के विरुद्ध समान परिमाण होगा [1, 1, 1, 1 , ९, ९, ९, ९]। स्पष्ट रूप से प्रवृत्ति खोजने के लिए, सबसे वर्तमान डेटा में पुराने डेटा की तुलना में अधिक वजन होना चाहिए और इसलिए हम चाहते हैं कि '1' अवलोकन '9' अवलोकन की तुलना में बड़ा परिमाण स्कोर हो। इसे प्राप्त करने के लिए मैंने एक फ्लोटिंग औसत z- स्कोर का प्रस्ताव रखा। यह स्पष्ट होना चाहिए कि यह विधि सांख्यिकीय ध्वनि होने की गारंटी नहीं है, लेकिन प्रवृत्ति खोजने या समान के लिए उपयोगी होनी चाहिए। मानक z- स्कोर और फ्लोटिंग औसत z- स्कोर के बीच मुख्य अंतर औसत जनसंख्या मूल्य और औसत जनसंख्या मान की गणना के लिए एक फ्लोटिंग औसत का उपयोग है। विवरण के लिए कोड देखें:
कोड
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()
नमूना 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
अपडेट करें
जैसा कि डेविड केम्प ने सही ढंग से कहा, यदि निरंतर मूल्यों की एक श्रृंखला दी जाती है और फिर एक मनाया मूल्य के लिए एक zscore जो अन्य मूल्यों से भिन्न होता है, तो अनुरोध किया जाता है कि परिणाम संभवतः गैर-शून्य होना चाहिए। वास्तव में लौटाया गया मूल्य अनंत होना चाहिए। इसलिए मैंने इस लाइन को बदल दिया,
if self.std() == 0: return 0
सेवा:
if self.std() == 0: return (obs - self.avg) * float("infinity")
यह परिवर्तन फ़ैज़कोर समाधान कोड में परिलक्षित होता है। यदि कोई अनंत मूल्यों से निपटना नहीं चाहता है, तो एक स्वीकार्य समाधान इसके बजाय लाइन को बदलने के लिए हो सकता है:
if self.std() == 0: return obs - self.avg