[spip-dev] popularite

Je viens de commiter une nouvelle méthode de popularité, basée sur mon
modèle mathématique exponentiel, sur l'idée d'Arno d'avoir un input des
visites et des referrers, etc, sur les commentaires d'Antoine côté
performances. J'espère que la synthèse vous plaira !

Les objectifs étaient :

1) on utilise des double pour avoir une discrimination partout
(par ex: select id_article,titre,popularite from spip_articles where
id_secteur=1)

2) Que ça ait du sens (si ce rythme se maintient votre popularité = nombre
de visiteurs (ip déifférentes) sur cet article en une journée)

3) Que ça se calcule facilement

4) Que ça donne rapidement une tendance (update souvent toutes les dix
minutes)

5) Notion de popularité totale du site et de popularité absolue

6) Que ça ne fasse pas un update à chaque hit

Mission accomplie ? Il reste à créer le tag #POPULARITE_TOTALE ; certains
pensent qu'on peut le mettre dans le backend...

-- Fil

Je viens de commiter une nouvelle méthode de popularité...

post-scriptum :

* pour la "période de demi-vie" des points attribués (un point par visiteur,
  un point par referer) j'ai mis 3 jours, un peu au pif. Peut-être faut-il que
  ça soit plus réactif (1 jour, 12 heures) ou plus lisse (1 semaine). Je ne
  sais pas s'il est intéressant/pertinent de faire des essais autour de ça.
  Pour tester il suffit de changer la variable $demivie = ... dans
  inc_statistiques.php3

* il faudra peut-être renommer, et en tous cas documenter les deux nouveaux
  tags #POPULARITE_ABS (est-ce qu'on l'appelle #POPULARITE_ABSOLUE ?)
  #POPULARITE_TOTALE (#POPULARITE_SITE ?), ainsi que le système de
  popularité.

* je passe en 1.4pr7

-- Fil

+ reset ($count_article);
+ while (list($count,$articles) = each($count_article)) {
+ $query = "UPDATE spip_articles
+ SET popularite = popularite + $b
+ WHERE id_article IN (0$articles)";
+ spip_query($query);
+ }

Plutôt $b * $count à la place de $b, non ?

Plutôt $b * $count à la place de $b, non ?

Oui ; en ayant un peu réfléchi (la matinée porte conseil) je crois qu'il
faut baisser $demivie pour avoir une sensibilité plus élevée aux variations
de la journée. Car sur le "long terme" on a le critère des visites totales,
et sur le "court terme" on n'a que la "popularite". Qui plus est, si on
choisit arbitrairement $demi-vie = 24 heures, les explications sont encore
plus simples, puisque tout est basé sur "la journée": le "nombre estimé de
visites sur cete article en vitesse de croisière" et "le temps qui fait
qu'une visite est comptée pour 0.5"...

-- Fil

Oui ; en ayant un peu réfléchi (la matinée porte conseil) je crois qu'il
faut baisser $demivie pour avoir une sensibilité plus élevée aux variations
de la journée. Car sur le "long terme" on a le critère des visites totales,
et sur le "court terme" on n'a que la "popularite". Qui plus est, si on
choisit arbitrairement $demi-vie = 24 heures, les explications sont encore
plus simples, puisque tout est basé sur "la journée": le "nombre estimé de
visites sur cete article en vitesse de croisière" et "le temps qui fait
qu'une visite est comptée pour 0.5"...

Au fait, ton calcul est franchement bizarre. Le $b = 60 * 24 n'est pas
homogène (durée au lieu de popularite)

Je verrais plutôt :

  $a = pow(2, - $duree / ($demivie * 60));
  $b = 1 - $a;

  // oublier un peu le passe
  spip_query("UPDATE spip_articles SET popularite = popularite * $a");

(suite inchangée)

??

Je verrais plutôt :
  $a = pow(2, - $duree / ($demivie * 60));
  $b = 1 - $a;
  spip_query("UPDATE spip_articles SET popularite = popularite * $a");

- tu changes la signification de $a en 1-$a, c'est exprès pour nous
embrouiller :wink: Je note donc $A ce que tu as indiqué ci-dessus, $a restant
égal à 1-$A et conforme à mes explications. Je préfère $a, proche de 0, plutôt
que $A, qui est proche de 1. Personnellement je trouve ça plus parlant, mais
bon...

- avec $b = 1-$A la "popularite" limite si tu as une visite par minute sera
égale à 1 ; or pour le tag #POPULARITE_ABSOLUE le nb de visites par JOUR
sera plus parlant que PAR MINUTE. Donc il faut $b = (nb de visites par jour
si j'ai en continu une viste par minute) * (1-$A) ; ma formule était la
bonne.

- le calcul de $A avec pow() plutôt qu'avec exp(log()), pourquoi pas, c'est
kifkif.

- tu peux remettre $demivie=24 heures stp ?

-- Fil

- avec $b = 1-$A la "popularite" limite si tu as une visite par minute sera
égale à 1

Je ne comprends pas trop d'où sort cette histoire de minutes.... On a un nombre
de visites absolues, qui est égalisé sur une durée de $demivie. $b est homogène
à un nombre de visites et ne doit pas être multiplié par une durée.

A réfléchir on aurait plutôt :

$b = 1 - 2 puissance (- 24 * 3600 / demi-vie)

Cela répond à l'équation :

$b * N + N * $A = N quand durée = 1 journée

Non ?

(note : l'avantage de ma notation ($a, $b) est que les équations sont plus
simples à écrire ;-))

@ Antoine Pitrou <antoine@rezo.net> :

>- avec $b = 1-$A la "popularite" limite si tu as une visite par minute sera
>égale à 1

Je ne comprends pas trop d'où sort cette histoire de minutes.... On a un
nombre de visites absolues, qui est égalisé sur une durée de $demivie.

Oublie les minutes : c'était quand la formule s'appliquait à chauqe hit,
pour que MySQL n'ait pas des chiffres trop petits qui auraient dépassé sa
précision (truc que tu avais soulevé) ; mais maintenant que l'UPDATE se fait
en passant directement le facteur multiplicatif, to $A est le bon, et mieux
exprimé dans ton commit que dans ton mail.

$b est homogène à un nombre de visites et ne doit pas être multiplié par
une durée.

Certes ; mais à une visite par minute (mon hypothèse de base) c'est la même
chose. 24 * 60 c'est la popularité limite d'un article visité une fois par
minute.

A réfléchir on aurait plutôt :
$b = 1 - 2 puissance (- 24 * 3600 / demi-vie)

Cela répond à l'équation :
$b * N + N * $A = N quand durée = 1 journée

pas exactement : l'équation n'est pas celle que tu mentionnes, mais
    $b * 10 + N * $A = N

où $A = 0.5 puissance (10 minutes/demi-vie)
   N = 60 * 24;

D'où, avec la demi-vie d'une journée,
     $b = (1-pow(0.5, 10 / (60*24))) * 60 * 24 /10
        = 0.69148161;

(note : l'avantage de ma notation ($a, $b) est que les équations sont plus
simples à écrire ;-))

Je sais bien, il faudra juste réécrire les explications.

-- Fil

Bonjour,

J'ai l'impression d'avoir un problème avec la fonction de surlignage :

L'affichage d'une page "recherchée" est hyper lent et j'obtiens en bas de ma
page :

Fatal error: Maximum execution time of 30 seconds exceeded in f:\program
files\easyphp\www\spip\ecrire\inc_surligne.php3 on line 52

Je regarde le code incriminé et j'arrive sur :

// supprimer tout ce qui est avant </head> ou <body>
if (eregi("(.*<\/head>)(.*)", $page, $exp))
  list(,$debut,$page) = $exp;
else if (eregi("(.*<body[^>]*>)(.*)", $page, $exp))
  list(,$debut,$page) = $exp;
else
  $debut = '';

=> c'est un truc qui vient d'être ajouté ça, non ?
=> vous n'avez pas le même genre de problème ?

Pour info je suis en local XP / EasyPHP....

@ David Féroc <feroc@noos.fr> :

Je regarde le code incriminé et j'arrive sur :

// supprimer tout ce qui est avant </head> ou <body>
if (eregi("(.*<\/head>)(.*)", $page, $exp))
  list(,$debut,$page) = $exp;
else if (eregi("(.*<body[^>]*>)(.*)", $page, $exp))
  list(,$debut,$page) = $exp;
else
  $debut = '';

=> c'est un truc qui vient d'être ajouté ça, non ?

oui

=> vous n'avez pas le même genre de problème ?

non. Mais on va faire un correctif. Merci !

-- Fil

Le surlignage fonctionne, avec un petit pb cependant :

<title><span class="spip_surligne">Quelque chose</span></title>

Bon weekend, si l'explosion des utilisateurs vous laisse une minute...

pas exactement : l'équation n'est pas celle que tu mentionnes, mais $b * 10 + N * $A = N

où $A = 0.5 puissance (10 minutes/demi-vie)
   N = 60 * 24;

D'où, avec la demi-vie d'une journée,
     $b = (1-pow(0.5, 10 / (60*24))) * 60 * 24 /10
        = 0.69148161;

Oui, exact.
Plus généralement :

$b = (1 - 2 puissance (- duree / demie-vie)) * periode de reference / duree

avec dans le cas présent :
période de référence = demie-vie = 1 journée

Note : le ln(2) * truc que tu proposes correspond probablement à la limite
de $b quand la durée tend vers 0.

Note : le ln(2) * truc que tu proposes correspond probablement à la limite
de $b quand la durée tend vers 0.

probablement seulement ? :wink:

-- Fil

@ David Féroc <feroc@noos.fr> :

J'ai l'impression d'avoir un problème avec la fonction de surlignage :

Pourrais-tu essayer stp de remplacer le fichier ecrire/inc_surligne.php3 par
celui qui se trouve dans le CVS ?

<http://rezo.net/spip-cvs/*checkout*/ecrire/inc_surligne.php3?rev=HEAD&cvsroot=SPIP&content-type=text/plain&gt;

Merci !

-- Fil

C'est réglé en ce qui concerne le title..
Thank's

OK ça marche nickel avec la version CVS !

@ David Féroc <feroc@noos.fr> :

OK ça marche nickel avec la version CVS !

Merci !

-- Fil

Dans le CVS les nouveaux tags de popularité, à utiliser comme suit :

<BOUCLE_pop(ARTICLES){id_article}{popularite>0}>
<h5>Popularité</h5>
Cet article a une popularité absolue égale à #POPULARITE_ABSOLUE, soit
#POPULARITE % de #POPULARITE_MAX. Au total, ce site fait environ
#POPULARITE_SITE visites par jour.
<hr>
</BOUCLE_pop>

NB : le rendu est toujours un entier, ce qui donnera, sur des sites peu
fréquentés ou à la popularité tout juste démarrée, des choses amusantes du
genre :

"Cet article a une popularité absolue égale à 1, soit 17 % de 2. Au total, ce
site fait environ 5 visites par jour."

-- Fil

Dans le tableau de bord, marge de gauche de statistiques_referers.php3, il y
a trois cases

* tout le site
  articles récents

* articles populaires

* articles visités hier

Il y a bcp de répétitions entre les trois blocs.

A mon avis avec la nouvelle popu on peut se satisfaire d'un seul bloc {par
popularite}{inverse}{0,30} auquel on ajoute les 5 plus récents non
doublonnés. Pas d'objection ?

-- Fil