Amélioration statistiques

This commit is contained in:
Jean-Marie Favreau 2025-03-15 19:11:27 +01:00
parent ca1015814a
commit 527fa886b7
5 changed files with 338 additions and 274 deletions

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,8 @@ from icalendar import Event as icalEvent
from location_field.models.spatial import LocationField
from django.dispatch import receiver
from django.db.models.signals import post_save
from django.db.models.aggregates import StdDev
from django.db.models import Avg, Max, Min
from .calendar import CalendarDay
from .import_tasks.extractor import Extractor
@ -49,9 +51,24 @@ from .import_tasks.generic_extractors.fbevent import (
CExtractor as FacebookEventExtractor,
)
from django.db.models import Aggregate, FloatField
logger = logging.getLogger(__name__)
class Median(Aggregate):
function = "PERCENTILE_CONT"
name = "median"
output_field = FloatField()
template = "%(function)s(0.5) WITHIN GROUP (ORDER BY %(expressions)s)"
#
#
# Useful for translation
to_be_translated = [_("mean"), _("median"), _("maximum"), _("minimum"), _("stdev")]
class UserProfile(models.Model):
user = models.OneToOneField(
User,
@ -2728,26 +2745,38 @@ class RecurrentImport(models.Model):
else:
return None
def get_foresight_quality(self):
from statistics import median, mean, stdev
def _get_foresight_quality_internal(qs):
limit = datetime.now() + timedelta(days=-30)
values = [
x["foresight"]
for x in Event.objects.filter(import_sources__contains=[self.source])
.annotate(foresight=ExtractDay(F("start_day") - F("created_date")))
.values("foresight")
]
if len(values) == 0:
return []
result = [
[_("minimum"), min(values)],
[_("maximum"), max(values)],
[_("mean"), round(mean(values), 2)],
[_("median"), median(values)],
]
if len(values) > 2:
result.append([_("standard deviation"), round(stdev(values), 2)])
return result
qs = qs.filter(start_day__gte=F("created_date")).annotate(
foresight=ExtractDay(F("start_day") - F("created_date"))
)
stats = qs.filter().aggregate(
minimum=Min("foresight"),
maximum=Max("foresight"),
mean=Avg("foresight"),
median=Median("foresight"),
stdev=StdDev("foresight"),
)
statsm = qs.filter(created_date__gte=limit).aggregate(
minimum=Min("foresight"),
maximum=Max("foresight"),
mean=Avg("foresight"),
median=Median("foresight"),
stdev=StdDev("foresight"),
)
return [[_(x), round(stats[x], 2), round(statsm[x], 2)] for x in stats]
def get_global_foresight_quality():
return RecurrentImport._get_foresight_quality_internal(Event.objects)
def get_foresight_quality(self):
return RecurrentImport._get_foresight_quality_internal(
Event.objects.filter(import_sources__contains=[self.source])
)
class BatchImportation(models.Model):

View File

@ -90,7 +90,9 @@
<h2>Qualité de l'anticipation</h2>
<p>
On s'intéresse à la différence entre la date de publication d'un événement et la date effective de l'événement. Plus le nombre de jours qui les sépare est élevé, plus
la source anticipe ses événements, et peut être considérée comme une source fiable.
la source anticipe ses événements, et peut être considérée comme une source fiable. On ignore les événements ajoutés à l'agenda alors que l'événement a déjà eu lieu.
On affiche cette information pour les imports depuis le début de son
intégration à l'agenda, mais aussi pour le dernier mois.
</p>
<table>
<thead>
@ -99,9 +101,13 @@
</thead>
<tbody>
<tr>
<th class="label">Nb jours</th>
<th class="label">écart (en jours)</th>
{% for v in stat %}<th>{{ v.1 }}</th>{% endfor %}
</tr>
<tr>
<th class="label">écart du dernier mois (en jours)</th>
{% for v in stat %}<th>{{ v.2 }}</th>{% endfor %}
</tr>
</tbody>
</table>
{% endif %}

View File

@ -42,6 +42,29 @@
On retrouve une synthèse par mois du tableau précédent, sous forme d'une moyenne du nombre de création d'événements par jour pour chaque mois.
</p>
{% include "agenda_culturel/statistics_per_month.html" with data=stats_months_by_creation %}
<h2>Qualité de l'anticipation</h2>
<p>
On s'intéresse à la différence entre la date de publication d'un événement et la date effective de l'événement. Plus le nombre de jours qui les sépare est élevé, plus
les sources anticipent leurs événements. On ignore les événements ajoutés à l'agenda alors que l'événement a déjà eu lieu.
On affiche cette information pour les imports depuis le début de leur
intégration à l'agenda, mais aussi pour le dernier mois.
</p>
<table>
<thead>
<th class="label"></th>
{% for v in stats_foresight %}<th>{{ v.0 }}</th>{% endfor %}
</thead>
<tbody>
<tr>
<th class="label">écart (en jours)</th>
{% for v in stats_foresight %}<th>{{ v.1 }}</th>{% endfor %}
</tr>
<tr>
<th class="label">écart du dernier mois (en jours)</th>
{% for v in stats_foresight %}<th>{{ v.2 }}</th>{% endfor %}
</tr>
</tbody>
</table>
<h2>Par ville</h2>
<p>Nombre d'événements référencés par ville.</p>
<ul>

View File

@ -2816,6 +2816,8 @@ def statistics(request):
.order_by("-total")
)
stats_foresight = RecurrentImport.get_global_foresight_quality()
context = {
"stats_by_startday": stats["start_day"],
"stats_by_creation": stats["created_date__date"],
@ -2826,6 +2828,7 @@ def statistics(request):
"first_by_creation": first["created_date__date"],
"last_by_creation": last["created_date__date"],
"nb_by_city": nb_by_city,
"stats_foresight": stats_foresight,
}
return render(request, "agenda_culturel/statistics.html", context)