Category Archives: Internet

Quel trajet minimal pour récupérer le maximum de bonbons à l’Halloween ? (partie 1)

Bon, ben cette fois ça y est, c’est l’Halloween… et comme tous les ans, mon rôle devrait se limiter à creuser les citrouilles, décorer la maison… et attendre à la porte de la maison que les enfants des voisins viennent me dévaliser ma réserve de bonbons ! Je pourrais à la rigueur revendiquer un petit quelque chose dans le déguisement de mon fils (on a passé pas mal de temps à feuilleter les premiers tomes de Walking Deads, histoire de mieux saisir l’essence des personnages de morts-vivants, en plus de la Zombie Walk la fin de semaine passée, en centre-ville).

Mais cette année, pas de billet sur les zombies comme l’an passé, mais un vrai problème pratique: comment optimiser son trajet, quand on sait où sont les bonnes maisons, où on a de fortes chances d’avoir plein de bonbons (en particulier chez les parents des amis) ? C’est assez proche de l’idée de passer par un maximum de maisons, et ce à une heure raisonnable (histoire qu’il reste des bonbons à récupérer).

Pour tous ceux qui ont fait un peu de programmation dynamique, c’est un problème classique, connu sous le nom du “voyageur de commerce“. Ce problème est né en juillet 1954 avec “the shortest route for a traveling salesman” paru dans Newsweek ci-dessous (que l’on retrouve en détails dans le livre 50 Years of Integer Programming)

Enfin, disons qu’il a été popularisé à cette époque, car Euler évoquait déjà un problème similaire quand il travaillait sur le problème des sept ponts de Königsberg, dans “Solutio problematis ad geometriam situs pertinentis“,

(même si ce problème consiste à étudier l’existence d’un trajet sous des contraintes de passages par des nœuds, et pas vraiment de l’optimisation). On retrouve aussi un exemple en 1832, en Allemagne, dans un livre intitulé Der Handlungsreisende – wie er sein soll und was er zu thun hat, um Auftraege zu erhalten und eines gluecklichen Erfolgs in seinen Geschaeften gewiss zu sein – Von einem alten Commis-Voyageur où un trajet passant par 45 villes en Allemagne et en Suisse devait être optimisé

(le schéma ci-dessus montre celle décrite en 1832, pour un total de 1,285km, mais il est possible de faire une boucle de 1,248km).

En fait le problème a explosé en 1962 (à cette époque, il semble que les gens pouvaient encore penser que faire des maths pouvait être le fun), lors que Procter & Gamble ont offert un prix de 10,000$ à celui qui trouverait le chemin le plus court pour que Toody et Muldoom, les conducteurs de la voiture 54 dans une série populaire à l’époque, passent par 33 villes, aux États-Unis.

Cela dit, Carl Menger avait noté dès 1930 a noté que ce problème devrait etre difficile à résoudre. Facile à écrire, mais difficile à résoudre explicitement. Dans son livre, William Cooke rappelle qu’avec 33 villes, il y aurait

131,565,418,466,846,765,083,609,006,080,000,000

chemins possibles, dont il faudrait calculer la longueur. Et qu’avec l’ordinateur le plus puissant en 2009 (effectuant 1.5 million de milliards d’opérations à la seconde) il faudrait 28,000 milliards d’année pour mener à bien les calculs. Même si on essayait de tenir compte des progrès de l’informatique dans les mille prochaines années, ça risque de prendre du temps !..

En 1967, Jack Edmonds notait “I conjecture that there is no good algorithm for the traveling salesman problem” où “good” est une manière élégante pour dire un temps polynomial en , le nombre de villes. Ce qui s’appelle les problèmes de la classe . Il semblerait que le problème du voyageur de commerce soit un problème  et pas de la classe (cf le chapitre du livre de Sanjeev Arora et Boaz Barak, ou le chapitre 11 des notes de cours de Olivier Bournez, que j’ai pu découvrir grâce à @dmonniaux, ou formellement de la classe  et pas , i.e.  complet), voir aussi la discussion sur wikipedia),

Et depuis, l’institut Clay a proposé $1,000,000 à celui qui prouverait que les problèmes   ne sont pas de type  (ou qui prouveraient qu’ils le sont… laconjecture reste ouverte, semble-t-il). Bref, les enjeux financiers derrière ont considérablement augmenté (on pourra consulter Sipser (2007) pour la petite histoire)

Bon, et si l’histoire est intéressante, ce n’est pas une raison pour la lire en se croisant les bras… essayons de programmer un algorithme (simple) afin d’approcher une solution, car je ne pourrais me contenter de dire à mes enfants “c’est un problème  complet, papa a capitulé“.

Commençons par tirer 5 points au hasard dans le carré unité,

>  n = 5
>  (x = matrix(runif(2*n),nr=n))
[,1]       [,2]
[1,] 0.4142621 0.35600725
[2,] 0.9477231 0.66938653
[3,] 0.2518656 0.19900873
[4,] 0.5314231 0.22954670
[5,] 0.5156522 0.09066741
et commençons par calculer la distance entre les points (i.e. une matrice, ou ici une matrice triangulaire inférieure)
>  (d = dist(x))
1         2         3         4
2 0.6186980
3 0.2258786 0.8399243
4 0.1723919 0.6056111 0.2812205
5 0.2840514 0.7222195 0.2851688 0.1397719
On va mettre ce triangle sous forme de matrice (pleine), ça sera plus simple à manipuler par la suite
>  (d = as.matrix(d))
1         2         3         4         5
1 0.0000000 0.6186980 0.2258786 0.1723919 0.2840514
2 0.6186980 0.0000000 0.8399243 0.6056111 0.7222195
3 0.2258786 0.8399243 0.0000000 0.2812205 0.2851688
4 0.1723919 0.6056111 0.2812205 0.0000000 0.1397719
5 0.2840514 0.7222195 0.2851688 0.1397719 0.0000000
Le principe, pour initialiser l’algorithme est de tirer au hasard un trajet, c’est à dire une permutation de nos points,
>  (o = sample(1:n))
[1] 2 4 1 5 3
Il faut alors calculer le 4 distances entre ces 5 villes (on ne prévoit pas de retour à la ville de départ, pour l’instant). Le plus simple est de jouer avec cette matrice de la réarranger,
>  d[o[1:(n-1)],][,o[2:n]]
4         1         5         3
2 0.6056111 0.6186980 0.7222195 0.8399243
4 0.0000000 0.1723919 0.1397719 0.2812205
1 0.1723919 0.0000000 0.2840514 0.2258786
5 0.1397719 0.2840514 0.0000000 0.2851688
et de prendre les 4 valeurs sur la diagonale
>  diag(d[o[1:(n-1)],][,o[2:n]])
[1] 0.6056111 0.1723919 0.2840514 0.2851688
Ce sont les 4 distances que l’on cherche, entre les 5 villes. La distance totale parcourue est alors
>  sum(diag(d[o[1:(n-1)],][,o[2:n]]))
[1] 1.347223
L’idée est ensuite de permuter deux des villes
>  (i=sample(1:n,2))
[1] 3 1
(ici la première et la troisième de la liste, mais on pourrait décider de fixer la première si on doit partir de là) et de voir si la nouvelle distance est plus courte, ou pas,
>  os=o
>  os[i]=o[rev(i)]
>  sum(diag(d[os[1:(n-1)],][,os[2:n]]))
[1] 1.785391
La distance étant plus longue, on ne va pas permuter. On pourrait tenter 1000 fois de permuter deux villes. Si on ne parvient pas à réduire la distance totale, c’est qu’on a atteint une valeur intéressante (à défaut de pouvoir prouver qu’elle est optimale). Et si on peut améliorer la distance, on permute. Le plus simple est donc de faire des petites fonctions. La première reprend le calcul de la distance totale, sur la diagonale de la matrice permutée, à matrice de distance donnée et à permutation donnée,
> tsp.longueur=function(matrice,ordres) {
+ n=length(ordres)
+ sum(diag(matrice[ordres[1:(n-1)],][,ordres[2:n]])) }
 La seconde est juste une boucle,
> tsp.optimal=function(d,N=1000) {
+ d=as.matrix(d)
+ n=ncol(d)
+ o=sample(1:n)
+ v=tsp.longueur(d,o)
+ k=0
+ while(k < N) {
+   i<-sample(1:n,2)
+   os=o
+   os[i]=o[rev(i)]
+   w=tsp.longueur(d,os)
+   if(w < v) {
+     v=w
+     o=os
+     k=0} else {k=k+1}}
+ list(ordre=o,longueur=v)}
On peut se lancer maintenant, avec par exemple 30 points simulés, sur le carré unité,
>  set.seed(1)
>  n=30
>  x=matrix(runif(2*n),nr=n)
>  o=sample(1:n)
>  plot(x,xlim=0:1,ylim=0:1,xlab="",ylab="")
>  lines(x[o,],col='blue')
>  r=tsp.optimal(dist(x))
>  os=r$ordre
>  lines(x[os,],col='blue',lwd=1.5)
avec la première trajectoire, à gauche, qui reste en trait fin sur le dessin de droite,

Pas mal, non ? Bon, en fait le soucis est que si on joue plusieurs fois avec notre fonction, on obtient toujours un graphique différent,

Autrement dit, je trouve (certes) des chemins pas trop long, mais je suis loin de trouver le chemin optimal. Et histoire de clotûrer le débat, notons qu’on peut faire un peu de simulation, afin de comparer la distance obtenue en faisant le trajet au hasard, et un trajet “optimal“,

> RATIO=HASARD=OPTIMAL=matrix(NA,500,10)
> for(m in 1:10){
+ n=5*m
+ for(s in 1:500){
+  x=matrix(runif(2*n),nr=n)
+  r=tsp.opt(dist(x))
+  HAZARD[s,m]=tsp.longueur(as.matrix(dist(x)),1:n)
+  OPTIMAL[s,m]=r$longueur
+  RATIO[s,m]=HAZARD[s,m]/
+             OPTIMAL[s,m]
+ }
+}

Si on compare la longueur moyenne du trajet (sur 500 scénarios) avec un tour au hasard (en rouge) et ou tour optimisé (en bleu), on a

ce qui donne un ratio moyen (ou une moyenne des ratios, les deux sont représentés)

Autrement dit, avec une dizaine de points éparpillés (au hasard) dans le carré unité, un tour au hasard ne sera que deux fois plus long… étonnant non ?

Mais on doit pouvoir aller plus loin, parce que sous R, il y a des fonctions (et des packages) pour faire des algorithmes plus compliqués… à suivre avant la tournée des bonbons de demain soir !

La recherche, l’enseignement et les élèves

Depuis quelques temps, lorsqu’on me demande ce que je fais dans la vie, je réponds “enseignant-chercheur” et je trouve que le terme me convient bien…

I.− Part. prés. de enseigner*: a) [L’obj. désigne le destinataire] Transmettre un savoir à. Synon.

Prononc. et Orth. : [ʃ ε ʀ ʃ œ:ʀ], fém. [-ø:z]. Ds Ac. 1694-1932. Étymol. et Hist. 1. le plus souvent avec compl. introduit par de a) 1538 cercheur « personne qui cherche, qui s’informe » (Est., s.v. conquisitores); 1636 chercheur (Monet); b) 1840 adj. « qui cherche (qqc.) » (Proudhon, Qu’est-ce que la propriété, p. 133); 2. emploi abs. 1835 adj. chercheuse « avide de connaissances, qui essaie de découvrir » (Balzac, loc. cit.);

Si on regarde les définitions, on voit qu’un chercheur s’informe (et reçoit du savoir) alors que l’enseignant le transmet (et communique son savoir). D’aucuns prétendront que le chercheur aussi transmet, mais quand on voit l’impact des articles académiques, on peut se demander à qui on transmet. Sans chercher à polémiquer, je trouve d’ailleurs surprenant qu’en France on ait pu séparer les deux, en créant des postes de chercheurs qui n’étaient pas tenu de partager leur savoir (mais j’ouvre une parenthèse que je ne tiens pas à ouvrir davantage)…. Bref, je suis très content d’enseigner car c’est cette activité qui me donne une utilité sociale.
Sauf que comme tous les enseignants, je déteste faire des examens. Pire encore, les corriger…
Lors de mon dernier examen, j’avais fait un questionnaire, avec des choix multiples (4 réponses, une seule bonne). Ça demande un temps fou à préparer, mais la correction est beaucoup plus rapide que lire des dizaines de pages (activité que je me laisse pour les heures à venir, car en plus des questionnaires, il y avait deux gros devoirs sur des bases de données). Et en plus, avec les choix multiples la correction est impartiale !
Dans un monde idéal, j’aimerais pouvoir dire “si vous pensez avoir réussi, passez au cours suivant, sinon reprenez le…” Alors j’ai tenté l’expérience. J’ai demandé aux étudiants d’écrire sur la copie le nombre de bonnes réponses qu’ils pensaient avoir. L’exercice était libre, et sans influence sur la note finale. Enfin, presque. Suite à une suggestion, j’ai accepté de donner des points à toute personne qui prédirait exactement son score !

> ACT6420=read.table("ACT6420-H2012.csv",
> base=ACT6420[ACT6420$obs>0,]
> attach(base)

Tout d’abord, comme l’exercice n’était pas obligatoire, certains (plusieurs) n’ont pas fait de prédiction… et comme souvent, la “non-réponse” est (très) informative,

> reponse=(is.na(pred)==FALSE)
> boxplot(obs~reponse,horizontal=TRUE)

Ceux qui n’ont pas répondu ont moins bien réussi que ceux qui ont répondu. Et sans vouloir revenir sur un point vu en cours (corrélation n’est pas causalité), je suis toujours surpris de fait que les personnes qui ne répondent pas aient un comportement aussi clairement différent de ceux qui répondent.

Maintenant regardons ce qui a été répondu par ceux qui ont joué le jeu, et qui ont fait une prédiction,

> plot(pred,obs,xlim=c(0,40),ylim=c(0,40),
+ xlab="Nombre de bonne réponses prédit",
+ ylab="Nombre de bonne réponses observé")
> abline(a=0,b=1,lty=1,col="red")
> abline(lm(obs~pred),lty=2)

En abscisse la prédiction, et en ordonnée, la valeur observée (un peu comme dans le cours de prévision justement). La courbe en rouge est une prédiction parfaite. Et la courbe en pointillé, la droite de régression. Les meilleurs se sous-estiment (en moyenne), alors que les moins bons se surestiment. Comme le note @AlbertineP on voit que les moins bons sont en fait un peu meilleurs qu’ils ne le pensent, alors que les meilleurs se surestiment ! Un effet Dunning-Kruger inversé, pour reprendre la terminologie proposée par @Tournyol. Damned, je ne pourrais donc pas demander aux étudiants de s’auto-évaluer, il va falloir que je continue à corriger mes copies ! (et je vais renouveler l’expérience, pour voir sur plus de copies ce que ça donne !)

OGM, ABC et mythologie scientifique

Une tentative de billet en cette fin de semaine pour revenir sur deux événements scientifiques récents, que certains pourraient trouver surprenant de rapprocher. Mais les deux événements sont liés à des publications (voire des prépublications) qui ont su faire le buzz, ces dernières semaines. Et si je les rapproche, c’est aussi probablement pour mieux les opposer.

  • d’un coté, l’exclusivité du Nouvel Observateur sur les OGM, et sur l’article de Séralini et al. (2012). Pour reprendre les premières phrases de l’article, “c’est une véritable bombe que lance, ce 19 septembre à 15 heures, la très sérieuse revue américaine “Food and Chemical Toxicology” – une référence en matière de toxicologie alimentaire – en publiant les résultats…” Je ne reviendrais pas sur l’article que je n’ai pas compris (y compris la partie statistique, et je renvoie aux articles parus dans Le Monde ou Libération sur le décryptage) mais sur la perception médiatique de la recherche scientifique… On gardera aussi en mémoire dans le titre de Rue89, “Les OGM dangereux pour la santé : l’étude qui le prouve” (mais les deux sites appartiennent à la même boutique, c’est probablement normal d’y lire la même chose).
  • de l’autre, les articles sur la conjecture d’Oesterlé-Masser, dite ABC, que Shinichi Mochizuki aurait démontré, dans Mochizuki (2012). Peu de journaux semblent en avoir parlé en France, mais le New York Times, par exemple, en parle, “with no fanfare, Shinichi Mochizuki, a mathematician at Kyoto University in Japan, dropped onto the Internet four papers.The papers, encompassing 500 pages and four years of effort, claim to solve an important problem in number theory known as the abc conjecture.” Après les précautions d’usage de journalistes qui ne cherchent pas un scoop, on apprend qu’un chercheur aurait résolu (ou prétend avoir résolu) un important problème mathématique. Certains sites comme Business Insider ne s’embarrassent pas trop de précautions, et titrent “World’s Most Complex Mathematical Theory ‘Cracked‘”. Si les éditeurs de ce site lisaient le Nouvel Obs, ils auraient peut-être écrit que “c’est une véritable bombe que lance” Shinichi Mochizuki.
Les deux évènements sont radicalement opposés selon moi. L’un étant avec et l’autre sans fanfare, comme le note le New York Times. Mais ce qui me dérange dans ces deux événements, c’est le mythe entretenu par certains journalistes sur le fonctionnement de la recherche. On se cache (autant que possible), et quand on est prêt (ou quand on pense l’être), on lance une “bombe” !
Je dois avouer que je rêve moi aussi d’écrire un article qui révolutionnerait le monde ! ou au moins mon monde, mon tout petit monde (pour reprendre le titre du livre de David Lodge)… Mais non, ce que je fais n’intéresse personne…
Et je ne crois pas non plus en la culture du secret, au contraire: dès que j’écris un truc, que je le présente dans une conférence, que ma grand mère en parle à une de ses amies au téléphone, j’en parle sur mon blog, et je mets les documents (y compris les codes pour les reproduire) sur mon blog. Car je ne me fais même plus d’illusion sur la portée de mes recherches. 24 articles ont cité des travaux que j’avais fait sur les comportements limites des copules Archimédiennes (dans la queue inférieure), mais 1 seul cite ceux sur les mesures d’inégalité et de pauvreté.
Ce qui est désolant, c’est cette vision du monde de la recherche; avec d’un coté, les chercheurs qui lancent des bombes, et de l’autre, ben…. les chercheurs qui admirent leurs collègues? qui les jalousent? qui se tournent les pouces? Ce n’est pas si simple que ça…. Par exemple, pour les travaux sur les OGM (ou sur le Roundup car je n’ai toujours pas compris si l’étude portait sur un OGM, ou sur un désherbant), les “les chercheurs français” ne sont probablement pas les seuls à publier sur le sujet !
Dans le cas d’ABC, Slate explique clairement les choses: “la démonstration du Japonais est détaillée dans quatre articles scientifiques (repris sur le site de Nature) qui reposent chacun sur d’autres longs articles“. Oui, ce n’est pas un chercheur tout seul qui a fait la découverte. Shinichi Mochizuki s’appuie “sur d’autres longs articles”, publiés par des chercheurs qui n’auront jamais leur heure de gloire, que l’histoire (y compris l’histoire des sciences) oubliera probablement… Mais ce n’est pas grave, car peu, très peu cherchent la gloire. Et tous fuient la médiatisation comme la peste !
Fort justement, The Telegraph posait l’autre jour la question suivante “How many scientists does it take to make a discovery?”. Intéressante question, n’est-ce-pas ? (et j’ai été déçu que l’article soit aussi court). Car oui, derrière les articles qui font du buzz, il y a des chercheurs qui cherchent… L’article note d’ailleurs dès le début que “the era of the lone genius, as epitomised by Albert Einstein, has long gone“… “long gone” ? Pas si sûr quand on voit la mythologie véhiculée par certains journalistes…. Il serait temps que ça change.

How to Talk About Books You Haven’t Read?

This summer, I have read with a great pleasure a short book (in French) translated into “How to Talk About Books You Haven’t Read ?”, by Pierre Bayard, professor of French literature at the University of Paris Sorbonne. The book was mentioned on http://www.brainpickings.org/ and on http://www.nytimes.com/ (and can be found in French online). The book is great… and I have identified a lot of things that can be observed if you work as an academic. Not only in literature.

The book starts with Oscar Wilde’s famous quote “I never read a book I must review; it prejudices you so”. So obviously, there should be good reasons not to read books. But first, Pierre Bayard suggests to distinguish among books that you “haven’t read“.

The first illustration is based on the librarian in Robert Musil‘s Der Mann ohne Eigenschaften. Good librarian do not read ! More precisely “The secret of a good librarian is that he never reads anything more of the literature in his charge than the title and the table of contents. Anyone who lets himself go and starts reading a book is lost as a librarian…He’s bound to lose perspective.” You should not read books if you want a good perspective. Further, “We marched down the ranks in that colossal storehouse of books, and I don’t mind telling you I was not particularly overwhelmed […]. Still, after a while I couldn’t help starting to do some figuring in my head, and I got an unexpected answer. […] I had been thinking that if I read a book a day […] I could claim a certain position in the world of the intellect. […] But what do you suppose that librarian said to me as […] I asked him how many books they had in this crazy library ? ‘Three and a half million’ he tells me. It would take me ten thousand years to carry out my plan.” There are so many books that it is clearly impossible to read everything. But this was mentioned earlier, in the Bible, Ecclesiastes 12:12, “the writing of many books is endless“. Actually, we have the same problem with academic research: there are papers published everyday, so as for Musil’s librarian, there is no way to read all of them. So clearly, if we want an overview of a given scientific field, we just go through titles, and abstracts (if we have time)…

As a second illustration, Pierre Bayard mentions the poet Paul Valéry who claimed that “je demeure peu lecteur, car je ne recherche dans un ouvrage que ce qui peut permettre ou interdire quelque chose à ma propre activité”. Similarly in academic research, we read mainly because we have to be sure that what we do is new, and has not be done before.

Then Pierre Bayard mention books that we have just heard of. And to illustrate this point, he mentions Umberto Ecco‘s Il nome della rosa. If you remember the book (or the movie), Baskerville finds the truth not because he has read a copy of the book, but he has heard of it. And it is clearly enough ! “Gradually this second book took shape in my mind as it had to be. I could tell you almost all of it, without reading the pages that were meant to poison me“. And trust me, academics do that all the time ! Because there are books you are supposed to mentioned when you want to publish. But some of them are out of print, and cannot be found in your library, and are way to expensive to buy them. So you just listen to what people say about that book.

So now we know that it is not necessary to read book when talk about them. But still, you have to behave properly if you still want to be reliable. The example mentioned by Pierre Bayard is the Martins-Dexter quiproquo in Graham Greene’s The third man. “‘If you want to know, I’ve never heard of him. What did he write?’ He didn’t realize it, but he was making an enormous impression. Only a great writer could have taken so arrogant, so original“. A similar story can be found in David Lodge’s Campus trilogy, when professors have to confess that they have not read certain books (in the so-called humiliation game), and the head of the literature department admits that he has never read Hamlet. It is rather difficult to admit that you have not read a book.

But similarly, the question “have you read the article ?” is usually quite ambiguous. Pretending that you have read it can mean that you have fully understood the paper, and the proof, and the implication. So usually, I do not pretend that I have read an article. Perhaps I might say that I had time to go through it. But not much more…

More funny is Pierre Siniac’s Ferdinaud Céline, where the author does not know the book he thought he wrote. It looks like funny, but I have to admit that this is a felling I have also experienced ! When people mention your work, or talk about it, but not the way you expected it. Like when you develop a nice theory, and you propose an application at the end, but some people only remember the 12% difference you have with the benchmark model, while the goal of the paper was simply to propose a new method, based on something else you’ve been working on. The article people read is usually not the one you wrote. Especially after a few revisions, where referees have required many changes (and you’ve done them because you need that publication).

Anyway, “How to Talk About Books You Haven’t Read ?” by Pierre Bayard is a great book that should be read by everyone !

Qui se ressemble se suit (sur Twitter au moins)

Un nouveau billet pour reprendre une analyse marrante faite par @3wen  (Ewen Gallic, qui travaille à Montréal alors que je profite de la Suisse). Suite à l’analyse amusante des trolls de Twitter, j’avais lancé l’idée qu’il pourrait être amusant de regarder parmi les députés français (que j’avais un peu suivis l’autre jour), qui tweete avec qui. Ewen a eu la bonne idée de regarder sur  http://lelab.europe1.fr/ ce qui lui a permis de récupérer la liste des comptes Twitter des députés, en France. L’idée est simple: parmi les députés français, on regarde qui suit qui. Quelqu’un de très suivi sera au centre du nuage, alors que quelqu’un qui se contente de suivre sera sur le bord (intensément connecté au reste du nuage). Pour les personnes peu familières, Twitter n’est pas Facebook: on n’a pas des “amis“, il y a des gens que l’on suit parce qu’ils racontent des choses qui peuvent nous intéresser.

En utilisant gephi Ewen a ensuite pu visualiser le graphique des interconnexions entre les députés.

Sans grande surprise, les députés de gauche suivent essentiellement les députés de gauche, et inversement. Quelques gros comptes font la passerelle entre les deux groupes parlementaires. En fait, si on regarde en détail (voire sur le fichier image complet), on peut observer un peu mieux ce qui se passe.

Bon, la grande difficulté est de lire ces interactions correctement. En particulier, on ne peut pas conclure (à la vue seule du graphique) que Cécile Duflot est de gauche ! Ce que cela nous dit est que ce qu’elle raconte intéresse les gens de gauche (ou en tous cas les députés du Parti Socialiste), et pas du tout les gens de droite (les députés de l’UMP) ! On notera aussi que le centre n’existe pas. Sur Twitter en tous cas. Et si on regarde tout en bas, à droite, on retrouve le Front National, et on a la confirmation que ce que raconte le Front National n’intéresse personne !

A la recherche des groupes de trolls sur Twitter

Il y a quelques jours @olihb avait mis en ligne sur son blog http://olihb.com/ une très jolie carte permettant de visualiser les personnes (ou les comptes) impliquées sur Twitter sur les manifestations récentes au Québec (la carte était basée sur gephi). Beaucoup de monde twittait avec des hashtags, et l’idée était d’utiliser les plus classiques et les plus populaires pour identifier les comptes actifs (#ggi#manifencours, etc). Mais la semaine passée j’avais l’impression que le débat s’était durci, avec beaucoup plus de trolls dans les discussions.

Bref, le principe est que les trolls évoluent souvent en petits groupes, donc avec @3wen on a voulu voir si on pouvait identifier facilement les groupes de trolls (sans pour autant faire du sentiment analysis, juste visualiser des personnes qui se suivent beaucoup entre elles, les connivences entre twittos, i.e. du suivi mutuel).

La méthodologie est simple. On a deux bases à notre disposition. Un première contient tous les tweets contenant #ggi entre le 7 juin à 1 heure du matin et le 8 à minuit 45 (soit 14,700 tweets). La seconde contient tous les tweets contenant #ggi entre le 12 juin à 23 heures 30 et le 14 juin à 17 heures (soit 14,784 tweets). Ah oui, les heures sont GMT. Plus précisément, on a la fréquence d’arrivée suivante

Les durées d’observations sont courtes, mais l’idée est que si une personne a tweetté au moins une fois pendant ces périodes, on les a dans notre base, et ça suffit pour les suivre. On ne va pas étudier l’intensité de la mise en ligne de tweets. Je ne rentre pas dans le détail du code, mais c’est basé sur les fonctions présentées dans un précédant billet, et toujours avec la même librairie,

require("RJSONIO")

Sur des deux bases, i.e. 29,484 tweets, on récupère un ensemble de 6,556 twittos uniques (mais répartis dans deux listes: ceux qui ont tweeté le 7 et ceux qui ont tweeté le 14). Pour toutes ces personnes, on est allé voir qui les suivaient. Sur le principe, c’est simple, mais on fonctionne avec des API qui imposent des limites horaires. Bref, il faut bricoler. Pour une personne, on récupère avec la fonction suivante la liste de ses followers,

recuperefollowers=function(id,nbrequetes){
followers=try(scan(paste(
"http://api.twitter.com/1/followers/ids.json?cursor=-1&user_id=",
id,sep=""),what = "character", encoding="latin1"))
if(is.null(attr(followers,"condition"))){
followers=paste(followers[1:length(followers)],collapse=" ")
followers=fromJSON(followers, method = "C")
id_followers=followers$id
next_cursor=followers$next_cursor_str
nbrequetes=nbrequetes+1
plusDe5000=FALSE
while(nbrequetes<150 & next_cursor!="0" &
is.null(attr(followers,"condition"))){
plusDe5000=TRUE
followers=scan(paste(
"http://api.twitter.com/1/followers/ids.json?cursor=",
next_cursor,"&user_id=",id,sep="")
,what = "character", encoding="latin1")
followers=paste(followers[1:length(followers)],collapse=" ")
followers=fromJSON(followers, method = "C")
id_followers=c(id_followers,followers$id)
next_cursor=followers$next_cursor_str
nbrequetes=nbrequetes+1
}
if(plusDe5000 & nbrequetes>=149){
return(c(list(),nbrequetes,TRUE))
}else{
return(c(list(id_followers),nbrequetes,FALSE))
}}else{
nbrequetes=nbrequetes+1
print(paste("Probleme rencontre avec ",id,sep=""))
return(c(list("PROBLEME"),nbrequetes,FALSE))}}

On peut ensuite lancer cette fonction sur tous les identifiants qu’on a récupéré, et on stocke tout le monde dans une (petite) base

temp=try(recuperefollowers(
lesIDAParcourir[unID_index],nbrequetes))
lesFollowers=temp[[1]]
resul=cbind(rep(lesIDAParcourir[unID_index]
,length(lesFollowers)),lesFollowers)
nbrequetes=temp[[2]]
refaire=temp[[3]]
Sys.sleep(runif(1,1,1.5))
compte=compte+1
write.table(resul,paste("auto_resul_",
compte,".txt",sep=""),sep=";")

Si on veut que ça tourne, il faut juste faire patienter un heure après avoir fait 150 requêtes. Bref, dans la boucle, on met une petite fonction qui temporise,

if(nbrequetes>148){
nbrequetes=1
Sys.sleep(60*60+60*trunc(runif(1,2,3))) }

Une fois créées les 6,500 bases de nos 6,500 comptes, contenant la liste de tous les followers, on va les agréger (fort heureusement, on n’avait pas les  gros comptes avec plus d’un million de followers). La liste se récupère avec

N=list.files("id/petits")

D’ailleurs, pour recoller les 6,500 bases ensemble, Ewen suggérait le code suivant, beaucoup beaucoup plus rapide qu’une gros boucle,

recupere_petits_fichiers=function(x){
temp=read.table(paste("id/petits/",x,sep=""),
header=TRUE,sep=";",comment.char="",
check.names=FALSE,colClasses=
c("character","character"))
colnames(temp)=list("id_twittos","id_follower")
head(temp)

On fait ensuite une récupération des followers pour la première base de tweets, et une autre pour ceux de la seconde. Les deux listes sont obtenues avec le code suivant

present_avant_temp=temp[which(
temp$id_twittos%in%lesID_avant),]
if(nrow(present_avant_temp)>0){
present_avant_temp=
present_avant_temp[which(
present_avant_temp$id_follower%in%lesID_avant),]}
else{
present_avant_temp=NULL}

present_apres_temp=
temp[which(temp$id_twittos%in%lesID_apres),]
if(nrow(present_apres_temp)>0){present_apres_temp=
present_apres_temp[
which(present_apres_temp$id_follower%in%lesID_apres),]}
else{present_apres_temp=NULL}
return(c(list(present_avant_temp),
list(present_apres_temp),
list(nbfollowers=nrow(temp))))

Pour constituer notre grosse base, la ruse est d’utiliser non pas une boucle sur tous les petites bases, mais

resul=lapply(N,recupere_petits_fichiers)
liens_avant=data.frame(do.call(
"rbind",lapply(resul,function(x) x[[1]])),
stringsAsFactors=FALSE)
liens_apres=data.frame(do.call(
"rbind",lapply(resul,function(x) x[[2]])),
stringsAsFactors=FALSE)

On a ainsi récupéré une liste avec plusieurs centaines de milliers de comptes Twitter. On a retenu seulement ceux qui avaient twitté avec le hashtag #ggi. On a ainsi pu constituer, pour nos 6,556 twittos une base de personnes qui tweettent, et de personnes qui les suivent (et qui ont twitté pendant cette – courte – période avec le hastag #ggi). Bref, une grosse matrice de correspondance de qui suit qui. On a pu le faire sur les deux bases. C’est précisément la différence entre les deux bases que l’on a cherché à visualiser, et gephi semble permettre de comparer les bases dans le temps. A gauche, on a le nuage de connexions entre les comptes pour la première période, et à droite pour la seconde.

Bon, le premier est plus compact, mais on voit qu’il y a des différences, en particulier sur les bords, que ce soit en haut

ou à droite du nuage,

Dans les deux cas, on voit que plein de petits comptes sont venus se greffer au nuage, souvent en suivant quelqu’un qui le suit en retour. Et parfois, ce sont les seuls connexions qu’ils ont (qui utilisent le hashtag #ggi). Ce sont ces comptes qui pourraient constituer les nouveaux trolls qu’on espérait identifier. L’avantage est qu’on a les noms de tous ces comptes (on ne les a pas mis sur le graphique), mais dans un second temps, on va aller regarder ce qu’on fait précisément ces comptes. Peut-être interprétons nous mal ces graphiques, qui représentent une arrivée de nouveaux comptes, et que cette dynamique est la même pour tous les nouveaux comptes, qui commencent par de faibles connexions, et ensuite vont s’étoffer au fur et à mesure. Ce qu’il faut que l’on comprenne aussi c’est pourquoi ils sont tous aussi rapprochés. Ils semblent être suivis par des personnes qui sont suivis pas les mêmes personnes. Ce qui laisse à penser que l’on a effectivement identifié une certaine catégorie de comptes.
On peut reprendre les graphs avec une résolution plus fine, avant

et après

ou alors en changeant les options, avant

à comparer avec après

On voit peut être encore plus clairement sur ces deux dernières images les nouveaux comptes se greffer sur le graph existant. Si la qualité ne suffit pas, des graphiques (très) haute résolution sont téléchargeables (15Mo chacun), avant etaprès (avec les identifiants cette fois). Sinon, en promenant la souris sur le dessin dessous, on voit encore mieux la différence,
 

Maintenant – pour être complètement honnête – sur la lecture des graphs, j’avoue ne pas avoir tout bien compris. Les représentations semblent claires, mais j’aurais bien aimé être certain d’avoir compris la construction proposée par gephi avant de les mettre en ligne. Car si on regarde sur moins ce compte, on comprend que l’algorithme permet effectivement de bien mettre en avant les réseaux. Parmi les illustrations les plus frappantes, la figure suivante montre des interconnections avec Facebook à gauche, et purement aléatoire à droite (illustration trouvé sur le site de gephi),

La grande difficulté est alors de représenter spatialement les groupes, comme le notent Gastner et Newman dans The Spatial Structure of Networks, Watts et Strogatz dansCollective dynamics of ‘small-world’ networksou encore Nisha et Venkatesh dans Small worlds: How and why. Mais pour etre tout à fait complet, je renverrais aussi vers la thèse de doctorat de Jure Leskovec, intituléeDynamics of large networks ainsi qu’au livre (intégralement téléchargeable) Networks, Crowds, and Markets: Reasoning About a Highly Connected World de David Easley et Jon Kleinberg. Bref, on a découvert un outils probablement très riche, mais il va nous falloir du temps pour comprendre ce qu’il fait vraiment.

Do you still have time to sleep ?

Last week, @3wen (Ewen) helped me to write nice R functions to extract tweets in R and build datasets containing a lot of information. I’ve tried a couple of time on my own. Once on tweet contents, but it was not convincing and once on the activity on Twitter following an event (e.g. the death of someone famous). I have to admit that I am not a big fan of databases that can be generated using standard function to study tweets. For instance, we can only extract tweets, notre-tweets (which is also an important indicator of tweet-activity). @3wen suggested to use

require("RJSONIO")

The first step is to extract some information from a tweet, and store it in a dataset (details can be found on https://dev.twitter.com/)

obtenir_ligne <- function(unTweet){
date_courante=unTweet$created_at
id_courant=unTweet$id_str
text=unTweet$text
nb_followers=unTweet$user$followers_count
nb_amis=unTweet$user$friends_count
utc_offset=unTweet$user$utc_offset
listeMentions=unTweet$entities$user_mentions
return(c(list(c(id_courant,date_courante,text,
nb_followers,nb_amis,utc_offset)),
list(do.call("rbind",lapply(listeMentions,
function(x,id_courant) c(id_courant,
x$screen_name),unTweet$id_str)))))
}

Now that we  have the code to extract information from one tweet, let us find several tweets, from one user, say my account,

nom="Freakonometrics"

The (small) problem here, is that we have a limitation: we can only get 100 tweets per call of the function

n=100
tweets_courants=scan(paste(
"http://api.twitter.com/1/statuses/user_timeline.json?
include_entities=true&include_rts=true&screen_name=
",nom,"&count=",n,sep=""),what = "character",
encoding="latin1")
tweets_courants=paste(tweets_courants[
1:length(tweets_courants)],collapse=" ")
tweets_courants=fromJSON(tweets_courants,
method = "C")

Then, we use our function to build a database with 100 lines,

extracTweets <- lapply(tweets_courants,
obtenir_ligne)
mentions=do.call("rbind",lapply(extracTweets,
function(x) x[[2]]))
colnames(mentions)=list("id","screen_name")
res=t(sapply(extracTweets,function(x) x[[1]]))
colnames(res) <- list("id","date","text",
"nb_followers","nb_amis","utc_offset")

The idea then is simply to use a loop, based on the latest id observed

dernier_id=tweets_courants[[length(
tweets_courants)]]$id_str

So, here we go,

compteurLimite=100

while(compteurLimite<4100){
tweets_courants=scan(paste(
"http://api.twitter.com/1/statuses/user_timeline.json?
include_entities=true&include_rts=true&screen_name=
",nom,"&count=",n,"&max_id=",dernier_id,sep=""),
what = "character", encoding="latin1")
tweets_courants=paste(tweets_courants[
1:length(tweets_courants)],collapse=" ")
tweets_courants=fromJSON(tweets_courants,
method = "C")

extracTweets <- lapply(tweets_courants[
2:length(tweets_courants)],obtenir_ligne)
mentions=rbind(mentions,do.call("rbind",
lapply(extracTweets,function(x) x[[2]])))
res=rbind(res,t(sapply(extracTweets,function(x) x[[1]])))
t(sapply(extracTweets,function(x) x[[1]]))
dernier_id=tweets_courants[[length(
tweets_courants)]]$id_str
compteurLimite=compteurLimite+100
}

resFreakonometrics=res=
data.frame(res,stringsAsFactors=FALSE)

All the information about my own tweets (and re-tweets) are stored in a nice dataset. Actually, we have even more, since we have extracted also names of people mentioned in tweets,

mentionsFreakonometrics=
data.frame(mentions)

We can look at people I mention in my tweets

gazouillis=sapply(split(mentionsFreakonometrics,
mentions$screen_name),nrow)
gazouillis=gazouillis[order(gazouillis,
decreasing=TRUE)]

plot(gazouillis)
plot(gazouillis,log="xy")
> gazouillis[1:20]
tomroud freakonometrics       adelaigue       dmonniaux
155              84              77              56
J_P_Boucher         embruns      SkyZeLimit        coulmont
42              39              35              31
Fabrice_BM            3wen          obouba          msotod
31              30              29              27
StatFr     nholzschuch        renaudjf        squintar
26              25              23              23
Vicnent        pareto35        romainqc        valatini
23              22              22              22

If we plot those frequencies, we can clearly observe a standard Pareto distribution,

Now, let us spend some time with dates and time of tweets (it was the initial goal of this post)… One more time, there is a (small) technical problem that we have to deal with: language. We need a function to convert date in English (on Twitter) to dates in French (since I have a French version of R),

changer_date_anglais <- function(date_courante){
mois <- c("Jan","Fév", "Mar", "Avr", "Mai",
"Jui", "Jul", "Aoû", "Sep", "Oct", "Nov", "Déc")
months <- c("Jan", "Feb", "Mar", "Apr", "May",
"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
jours <- c("Lun","Mar","Mer","Jeu",
"Ven","Sam","Dim")
days <- c("Mon","Tue","Wed","Thu",
"Fri","Sat","Sun")
leJour <- substr(date_courante,1,3)
leMois <- substr(date_courante,5,7)
return(paste(jours[match(leJour,days)]," ",
mois[match(leMois,months)],substr(
date_courante,8,nchar(date_courante)),sep=""))
}

So now, it is possible to plot the times where I am online, tweeting,

DATE=Vectorize(changer_date_anglais)(res$date)
DATE=sapply(resSkyZeLimit$date,
changer_date_anglais,simplify=TRUE)

DATE2=strptime(as.character(DATE),
"%a %b %d %H:%M:%S %z %Y")
lt= as.POSIXlt(DATE2, origin="1970-01-01")
heure=lt$hour+lt$min/60
plot(DATE2,heure)

On this graph, we can see that I am clearly not online almost 6 hours a day (or at least not on Twitter). It is possible to visualize more precisely the period of the day where I might be on Twitter,

hist(heure,breaks=0:24,col="light green",proba=TRUE)
X=c(heure-24,heure,heure+24)
d=density(X,n = 512, from=0, to=24,bw=1)
lines(d$x,d$y*3,lwd=3,col="red")

or, if we want to illustrate with some kind of heat plot,

Note that we did it for my Twitter account, but we can also run the code on (almost) anyone on Twitter. Consider e.g. @adelaigue. Since Alexandre is tweeting in France, we have to play with time-zones,

res=extractR("adelaigue")
DATE=Vectorize(changer_date_anglais)(res$date)
DATE2=strptime(as.character(DATE),
"%a %b %d %H:%M:%S %z %Y",tz = "GMT")+2*60*60

or I can also look at @skythelimit who’s usually twitting from Singapore (I am in Montréal). I can seen clearly when we might have overlaps,

res=extractR("skythelimit")

Nice isn’t it. But it is possible to do much better… for instance, for those who do not ask specifically not to be Geo-located, we can see where they do tweet during the day, and during the night… I am quite sure a dozen posts with those functions can be written…

Licornes, philosophes, vieux cons, peer-review et instituts de sondages

oui, vaste programme… Lorsque les enfants étaient petits, je me souviens avoir été maintes fois étonné par la profondeur des questions qu’ils pouvaient poser,

dis papa, comment tu sais tout ça ?

ou

dis papa, si j’étais pas né comment ça serait ?

Toutes ces questions sont embarrassantes, car elles sont assez fondamentales quand on y pense. Car le problème est qu’après, les enfants grandissent, et pensent avoir des réponses à ces mêmes questions,

t’es sûre, tu ne veux pas une licorne pour ton anniversaire ?

mais non papa, ça n’existe pas les licornes

bien sûr que si que ça existe, n’oublie pas que les papas ça sait tout ! Et comment tu sais que ça existe pas d’abord ?

ben j’en ai jamais vu…

et alors… tu n’as jamais vu de crocodiles, et pourtant ça existe…

oui mais j’en ai vu à la télé

et moi à la télé j’ai vu des wookies et des ewoks dans Star Wars, et des dragons dans Harry Potter, et..

oui mais à la télé ça existe pas ! Les licornes personne n’en a jamais vu d’abord

et ça suffit pour dire que ça n’existe pas, tu penses ?

(en fait, on peut avoir ce même genre de dialogue avec dieu, ou mieux, le père Noël). Bref, suite à cette discussion je me demandais ce qui faisait qu’on y croyait ou qu’on n’y croyait plus. Par exemple en sciences: l’opposition classique entre sciences et religion est basée sur le fait que la religion repose sur la foi, et alors que la science non, on doit avoir une preuve de ce qu’on avance. Un peu comme le personnage de Gorgias (de Platon), le précurseur de tous nos hommes (et femmes) politiques: on a raison parce qu’on a eu le dernier mot. Et non parce qu’on l’a prouvé. Mais il faut être lucide. La science devient de plus en plus une histoire de foi et de croyance. Par exemple en cours, la très grande majorité de mes élèves me croient si je leur dit qu’une méthode ne marche pas, rares sont ceux qui penseraient à me demander de leur justifier, ou au mois de trouver des éléments étayant mon propos (car la tendance est de faire de moins de moins de démonstration en cours, surtout quand on fait de la statistique appliquée). Par exemple en séries temporelles: lorsque je faisais cours il y a 10 ans à l’université Paris Dauphine, on passait des heures sur les choix des ordres d’autorégression (faut-il un retard à l’ordre 4, ou 12 ?). Maintenant, tous les logiciels font ça automatiquement. Un peu comme le choix de la fenêtre quand on fait de l’estimation à noyau… sous R, on a un choix optimal de fenêtre… et souvent, quand on est pressé, on y croit.

Oui, en sciences, on utilise beaucoup cet argument de foi. Le plus classique étant de dire que ça a été publié dans une grande revue… Et c’est le principe du peer-review: on délègue à d’autres chercheurs la responsabilité de regarder en détails un papier, qui souvent dépasse nos propres compétences, afin de se reposer sur leur jugement les yeux fermés. C’est bien entendu stupide, et c’est pour ça qu’on demande aux étudiants de maîtrise de creuser les papiers en détails, de relire et comprendre les démonstrations, et de faire des simulations pour vérifier si ça marche ! Et je serais bien le premier à dire qu’il ne faut jamais croire ce qui est écrit dans mes livres ou mes papiers ! ou sur le blog ! Quoi que… sur le blog, je mets autant que possible l’intégralité des codes, afin de permettre aux personnes de vérifier plus facilement ce que j’ai fait. Et c’est le gros intérêt du blog pour les chercheurs, par rapport aux articles publiés: on n’est pas là pour épater la galerie (je renvoie d’ailleurs à un très bon article expliquant comment écrire un article scientifique). Sur le blog, on peut davantage lancer des discussions, et être beaucoup plus transparents, et modestes !

Soit dit en passant, cette histoire de foi se retrouve largement dans cette mise en abyme des sondages, évoquée dans un précédant billet, sur le fait que plus personne ne croit aux sondages. Pourtant des grands sociologues et des grands statisticiens ont travaillé depuis des dizaines d’années sur la théorie des sondages. Des centaines d’articles (parus dans des articles relus par d’autres grands scientifiques) justifient certaines méthodes d’analyse. Et pourtant la foi n’est pas là. Peut-être serait-il temps que les instituts soient plus transparents, qu’ils donnent accès aux données brutes. Car je suis convaincu que la transparence est la clé de tout. Enfin presque… pour l’existence du père Noël, je vais me battre autant que possible pour maintenir le doute !

Maths can be cool (to impress your kids)

Just imagine that your kids need some help, to prepare fishes for April 1st, like

Her: “please, Daddy, help us to draw some fishes”

Me: “Sure, Daddy is a champion, actually, I do that everyday at work: drawing fishes – and more generally nice stuff – is exactly Daddy’s job”.

OK, no need to talk neither about Talbot’s curvesellipse negative pedal curvenor Burleigh’s ovals, unless you don’t want to scare them, e.g.

t=seq(0,2*pi,length=100) 
b=.8
c=sqrt(1-b^2)
x=cos(t)-c*sin(t)^2
y=(1-2*c^2+c*cos(t))*sin(t)/b
plot(x,y)

From now on, it is rather simple to draw fishes,

t=seq(0,2*pi,length=100)
y=cos(t)-sin(t)^2/sqrt(2)
x=cos(t)*sin(t)
plot(x,y,type="l",axes=FALSE,xlab="",ylab="")
polygon(c(-2,-2,2,2),
c(-2,2,2,-2),col="light blue",border=NA)
polygon(x,y,col="red",border=NA)
axis(1)
axis(2)
lines(x,y,type="l")

so we can easily get nice fishes,

Le paradoxe de l’examen surprise…

La semaine dernière, Steve Landsburg reprenait (sur http://thebigquestions.com) sous une forme amusante un paradoxe que j’avais évoqué voilà deux ans sur le blog. Je ne résiste pas au plaisir de me replonger dans ce paradoxe…

Un professeur rédigeant son plan de cours veut mentionner un examen surprise, qui compterait pour 10% de la note finale.  Il annonce donc à ses étudiants, au premier cours, qu’un examen surprise (et un seul) se tiendrait à une date (surprise) parmi les 12 séances de cours. Mais comme le fait noter un élève, l’examen ne pourrait avoir lieu lors de la dernière séance (la 12ème), car cela signifierait qu’il n’y a pas eu d’examen les 11 premières séances, et donc l’examen surprise devrait forcément se tenir au 12ème cours (mais alors il ne serait plus surprise du tout). Bref, impossible d’avoir un examen surprise ce jour là. Mais dans ce cas, surenchérit une étudiante, il ne peut non plus avoir lieu à l’avant dernière séance (la 11ème), car là encore cela signifierait qu’il n’y a pas eu d’examen les 10 premières séances, et donc l’examen surprise devrait forcément au 11ème cours (car il ne peut pas avoir lieu au 12ème comme on vient de le voir, et là encore, il ne serait plus surprise du tout). Bref, de manière récurrente, on peut montrer que l’examen surprise a alors lieu forcément le premier jour. Mais là encore, il n’y a pas de surprise. Et donc impossible qu’il y ait un examen surprise si ce dernier a été annoncé. Moralité, pour faire un examen surprise, il ne faut surtout pas évoquer qu’il y en aura un. Mais comme on ne peut pas faire un examen non annoncé dans les modalités de contrôle des connaissances, il est impossible de faire des surprises aux étudiants à l’université… C’est triste, non ?

11/11/11 11:11

Aujourd’hui, c’est la fête du parallélisme ! Déjà que 11:11 mettait Pierre Desproges dans un état proche de l’orgasme, mais qu’il soit 11:11 le 11/11/11… c’est la fête ! Tous les amateurs de parallélisme vont apprécier.

On va aussi dire que c’est la fête du théorème de Thalès.

Monsieur Thalès, alias Thalès de Millet (Θαλῆς ὁ Μιλήσιος) était un brave monsieur qui faisait des mathématiques il y a un peu plus de 2500 ans (et contrairement à ce que croit ma fille, je n’ai pas connu cette époque là, ni celle des – vrais – dinosaures). Selon Plutarque, dans Le Banquet des Sept Sages, un pharaon (en l’occurrence Ahmès II) aurait dit que personne ne serait capable de calculer la hauteur de la grande pyramide de Khéops. “Challenge accepted” se serait alors écrié Thalès (πρόκληση αποδεκτή à l’époque) et il aurait relevé le défi en calculant le rapport entre son ombre et celle d’un bout de bois…


vous avez mesuré la pyramide sans le moindre embarras et sans avoir eu besoin d’aucun instrument. Après avoir dressé votre bâton à l’extrémité de l’ombre que projetait la pyramide, vous construisîtes deux triangles par la tangence d’un rayon, et vous démontrâtes qu’il y avait la même proportion entre la hauteur du bâton et la hauteur de la pyramide qu’entre la longueur des deux ombres

(Denis Guedj en parle dans le Théorème du Perroquet). Formellement, si on utilise le dessin à droite, ce théorème dit que si les droites rouges sont parallèles, alors

http://freakonometrics.blog.free.fr/public/latex/thales.gif

Ce théorème est fondamental non seulement en géométrie, mais plus généralement, car c’est la base de la règle de trois ! En effet, le parallélisme induit de la proportionnalité. Et la proportionnalité est la base de tout. J’avais fait un billet sur la règle de trois et les techniques de provisionnement en assurance non-vie, et j’en ai parlé dans le cours de tarification, lorsque l’on faisait des régressions avec un modèle multiplicatif. Mais je parle trop, cet instant magique ne dure qu’une seconde, et ça serait dommage de le gâcher avec mes petites histoires…