Pageviews: Lissage par noyau gaussien

This commit is contained in:
Mattéo Delabre 2019-11-25 21:32:07 -05:00
parent a555df3417
commit 89c501d4ea
Signed by: matteo
GPG Key ID: AE3FBD02DC583ABB
1 changed files with 48 additions and 14 deletions

View File

@ -5,8 +5,10 @@ from datetime import datetime
import logging import logging
import math import math
import matplotlib import matplotlib
import numpy
from matplotlib import pyplot from matplotlib import pyplot
import requests import requests
from scipy import stats
import sys import sys
import mwclient import mwclient
@ -29,19 +31,46 @@ wikimedia_pageviews_start = datetime(2015, 7, 1)
# Objet pour afficher le journal dexécution # Objet pour afficher le journal dexécution
logger = logging.getLogger('pageviews') logger = logging.getLogger('pageviews')
def wrapping_move_mean(data, window): # Tableau contenant tous les jours de lannée de 1 à 365
""" year_all_days = numpy.arange(1, 366)
Calcule une moyenne par fenêtre circulaire sur un tableau de valeurs.
:param data: Tableau de valeurs.
:param window: Taille de la fenêtre. def year_date_distance(a, b):
:return: Tableau moyenné avec une fenêtre de taille donnée. Le résultat
a les même dimensions que lentrée.
""" """
down_half_window = math.floor(window / 2) Calcule la distance entre deux jours de lannée.
up_half_window = math.ceil(window / 2)
padded_data = data[-down_half_window:] + data + data[:up_half_window] :example: year_date_distance(10, 360) == 15
return bottleneck.move_mean(padded_data, window=window)[window - 1:] :example: year_date_distance(numpy.array([10, 182, 355]), 182)
== [172, 0, 173]
:param a: Première valeur (peut être un tableau numpy).
:param b: Seconde valeur (peut être un tableau numpy).
:return: Valeur de la distance.
"""
return numpy.stack((
numpy.mod(a - b, len(year_all_days)),
numpy.mod(b - a, len(year_all_days))
)).min(axis=0)
def year_smooth_gaussian(data, scale):
"""
Fait un lissage de tableau de valeurs avec une valeur par jour de lannée
en utilisant un noyau gaussien.
À la bordure de fin ou de début dannée, le lissage est fait avec lautre
morceau de lannée.
:param data: Données à lisser.
:param scale: Variance du noyau gaussien.
:return: Données lissées.
"""
ref_pdf = stats.norm.pdf(year_date_distance(year_all_days, 1), scale=scale)
pdf_matrix = numpy.stack([
numpy.roll(ref_pdf, day - 1)
for day in year_all_days
])
return pdf_matrix.dot(data)
def wikimedia_page_views(site, article): def wikimedia_page_views(site, article):
""" """
@ -79,6 +108,7 @@ def wikimedia_page_views(site, article):
for record in data['items'] for record in data['items']
)) ))
def wikimedia_article_canonical_name(site, article): def wikimedia_article_canonical_name(site, article):
""" """
Obtient le nom canonique dun article après avoir suivi les redirections. Obtient le nom canonique dun article après avoir suivi les redirections.
@ -97,6 +127,7 @@ def wikimedia_article_canonical_name(site, article):
return original_page.resolve_redirect().name return original_page.resolve_redirect().name
def wikimedia_article_views(site, article): def wikimedia_article_views(site, article):
""" """
Obtient le nombre de visites sur un article Wikipédia, incluant la page Obtient le nombre de visites sur un article Wikipédia, incluant la page
@ -127,10 +158,11 @@ def wikimedia_article_views(site, article):
# Somme le nombre de visites sur chacune des pages # Somme le nombre de visites sur chacune des pages
return sum( return sum(
(wikimedia_page_views(site, page) (wikimedia_page_views(site, page)
for page in redirects + [article]), for page in redirects + [article]),
start=collections.Counter() start=collections.Counter()
) )
def wikimedia_mean_article_views(site, article): def wikimedia_mean_article_views(site, article):
""" """
Obtient des statistiques moyennes sur les vues dun article Wikipédia par Obtient des statistiques moyennes sur les vues dun article Wikipédia par
@ -170,7 +202,8 @@ def wikimedia_mean_article_views(site, article):
key=lambda x: x[0] key=lambda x: x[0]
)] )]
return wrapping_move_mean(days, window=60) return days
def create_year_plot(): def create_year_plot():
""" """
@ -190,6 +223,7 @@ def create_year_plot():
ax.set_xticklabels(calendar.month_abbr[1:13]) ax.set_xticklabels(calendar.month_abbr[1:13])
return fig, ax return fig, ax
if __name__ == '__main__': if __name__ == '__main__':
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
@ -225,7 +259,7 @@ dénombrées comme une visite sur la page canonique.
) )
data = wikimedia_mean_article_views(site, canonical_article) data = wikimedia_mean_article_views(site, canonical_article)
ax.plot(data, label=canonical_article) ax.plot(year_smooth_gaussian(data, 10), label=canonical_article)
ax.set_ylabel('Vues par jour') ax.set_ylabel('Vues par jour')
fig.legend() fig.legend()