Pageviews: Lissage par noyau gaussien
This commit is contained in:
parent
a555df3417
commit
89c501d4ea
|
@ -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 d’exécution
|
# Objet pour afficher le journal d’exécution
|
||||||
logger = logging.getLogger('pageviews')
|
logger = logging.getLogger('pageviews')
|
||||||
|
|
||||||
def wrapping_move_mean(data, window):
|
# Tableau contenant tous les jours de l’anné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 l’entrée.
|
|
||||||
"""
|
"""
|
||||||
down_half_window = math.floor(window / 2)
|
Calcule la distance entre deux jours de l’anné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 l’année
|
||||||
|
en utilisant un noyau gaussien.
|
||||||
|
|
||||||
|
À la bordure de fin ou de début d’année, le lissage est fait avec l’autre
|
||||||
|
morceau de l’anné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 d’un article après avoir suivi les redirections.
|
Obtient le nom canonique d’un 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 d’un article Wikipédia par
|
Obtient des statistiques moyennes sur les vues d’un 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()
|
||||||
|
|
Loading…
Reference in New Issue