이 문제는 다른 사람들이 언급했듯이 이력 데이터의 표준 편차뿐만 아니라 이력 데이터의 표준 편차를 고려하여 평균을 사용하는 것보다 더 강력한 z 점수 또는 표준 점수를 요구합니다.
귀하의 경우 z- 점수는 다음 공식으로 계산되며 추세는 조회 / 일과 같은 비율입니다.
z-score = ([current trend] - [average historic trends]) / [standard deviation of historic trends]
z- 점수가 사용될 때 z- 점수가 높거나 낮을수록 추세가 비정상적으로 증가하므로, 예를 들어 z- 점수가 매우 긍정적이면 추세가 비정상적으로 상승하는 반면, 매우 음수이면 비정상적으로 하락합니다. . 따라서 모든 후보 트렌드에 대해 z- 점수를 계산하면 최고 10 개의 z- 점수가 가장 비정상적으로 증가하는 z- 점수와 관련됩니다.
z- 점수에 대한 자세한 내용 은 Wikipedia 를 참조하십시오 .
암호
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()
이 방법을 사용하면 작업 흐름은 다음과 같습니다. 각 주제, 태그 또는 페이지에 대해 데이터베이스에서 총 일 수,보기 합계 및보기 합계에 대해 부동 소수점 필드를 작성하십시오. 기록 데이터가있는 경우 해당 데이터를 사용하여 이러한 필드를 초기화하고 그렇지 않으면 0으로 초기화하십시오. 하루가 끝나면 세 개의 데이터베이스 필드에 저장된 히스토리 데이터에 대한 일 수를 사용하여 z 점수를 계산하십시오. Xz 점수가 가장 높은 주제, 태그 또는 페이지는 오늘의 X "호스트 트렌드"입니다. 마지막으로 3 개의 각 필드를 일 값으로 업데이트하고 내일 프로세스를 반복하십시오.
새로운 추가
위에서 논의 된 일반적인 z- 점수는 데이터의 순서를 고려하지 않으므로 '1'또는 '9'의 관측에 대한 z- 점수가 시퀀스 [1, 1, 1, 1에 대해 동일한 크기를 갖습니다. , 9, 9, 9, 9]. 추세 찾기의 경우 가장 최신 데이터는 이전 데이터보다 가중치가 높아야하므로 '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
최신 정보
David Kemp가 올바르게 지적했듯이 일련의 상수 값이 주어지면 다른 값과 다른 관측 값에 대한 zscore가 요청되면 결과는 아마도 0이 아니어야합니다. 실제로 반환 된 값은 무한대 여야합니다. 그래서 나는이 줄을 바꿨다.
if self.std() == 0: return 0
에:
if self.std() == 0: return (obs - self.avg) * float("infinity")
이 변경 사항은 fazscore 솔루션 코드에 반영됩니다. 무한 값을 처리하지 않으려는 경우 수용 가능한 해결책은 대신 행을 다음과 같이 변경하는 것입니다.
if self.std() == 0: return obs - self.avg