Tag Archives: QCM

Quiz de probabilité

Ce matin, en fin de cours, j’ai fait passé un petit quiz. Compte tenu de la configuration de la salle, j’avais distribué deux questionnaires, avec chacun 10 questions. Les questions étaient identiques, à l’application numérique près (pour quelques exercices). La première série d’exercice est en ligne, ainsi que des éléments de correction; la seconde série est aussi en ligne, avec là encore des éléments de correction. J’ai rajouté après la correction les statistiques de réponses pour chaque formulaire, mais aussi au niveau agrégé (en incluant l’autre questionnaire). Il va de soi qu’il est possible de continuer à s’entraîner à faire des exercices pendant les semaines à venir, ça ne fera de mal à personne !

Fin de session !

La session d’hiver est enfin terminée (pour les cours en tous cas). L’examen du cours ACT6420 méthodes de prévisions est maintenant en ligne, avec l’énoncé, les annexes (qui correspondent à celles mises en ligne en début de semaine, avec quelques nombres entourés, qu’il fallait commenter expliquer) et quelques éléments (succincts) de correction (qui seront en ligne à partir de 15 heures).

Il reste encore le deuxième devoir à rendre, pour vendredi prochain dernier délai (comme indiqué mardi, après le cours). Merci aux étudiants qui ont joué le jeu, et qui ont mis une prévision de leur propre note.

Finding Waldo, a flag on the moon and multiple choice tests, with R

I have to admit, first, that finding Waldo has been a difficult task. And I did not succeed. Neither could I correctly spot his shirt (because actually, it was what I was looking for). You know, that red-and-white striped shirt. I guess it should have been possible to look for Waldo’s face (assuming that his face does not change) but I still have problems with size factor (and resolution issues too). The problem is not that simple. At thehttp://mlsp2009.conwiz.dk/ conference, a price was offered for writing an algorithm in Matlab. And one can even find Mathematica codes online. But most of the those algorithms are based on the idea that we look for similarities with Waldo’s face, as described in problem 3 on http://www1.cs.columbia.edu/~blake/‘s webpage. You can find papers on that problem, e.g. Friencly & Kwan (2009) (based on statistical techniques, but Waldo is here a pretext to discuss other issues actually), or more recently (but more complex) Garg et al. (2011) on matching people in images of crowds.

What about codes in R ? On http://stackoverflow.com/, some ideas can be found (and thank Robert Hijmans for his help on his package). So let us try here to do something, on our own. Consider the following picture,

With the following code (based on the following file) it is possible to import the picture, and to extract the colors (based on an RGB decomposition),

> library(raster)
> waldo=brick(system.file("DepartmentStoreW.grd",
+ package="raster"))
> waldo
class       : RasterBrick
dimensions  : 768, 1024, 786432, 3 (nrow,ncol,ncell,nlayer)
resolution  : 1, 1  (x, y)
extent      : 0, 1024, 0, 768  (xmin, xmax, ymin, ymax)
coord. ref. : NA
values      : C:\R\win-library\raster\DepartmentStoreW.grd
min values  : 0 0 0
max values  : 255 255 255

My strategy is simple: try to spot areas with white and red stripes (horizontal stripes). Note that here, I ran the code on a Windows machine, the package is not working well on Mac. In order to get a better understanding of what could be done, let us start with something much more simple. Like the picture below, with Waldo (and Waldo only). Here, it is possible to extract the three colors (red, green and blue),

> plot(waldo,useRaster=FALSE)

It is possible to extract the red zones (already on the graph above, since red is a primary color), as well as the white ones (green zones on the graphs means a white region on the picture, on the left)

# white component
white = min(waldo[[1]] , waldo[[2]] , waldo[[3]])>220
focalswhite = focal(white, w=3, fun=mean)
plot(focalswhite,useRaster=FALSE)

# red component
red = (waldo[[1]]>150)&(max(  waldo[[2]] , waldo[[3]])<90)
focalsred = focal(red, w=3, fun=mean)
plot(focalsred,useRaster=FALSE)

i.e. here we have the graphs below, with the white regions, and the red ones,

From those two parts, it has been possible to extract the red-and-white stripes from the picture, i.e. some regions that were red above, and white below (or the reverse),

# striped component
striped = red; n=length(values(striped)); h=5
values(striped)=0
values(striped)[(h+1):(n-h)]=(values(red)[1:(n-2*h)]==
TRUE)&(values(red)[(2*h+1):n]==TRUE)
focalsstriped = focal(striped, w=3, fun=mean)
plot(focalsstriped,useRaster=FALSE)

So here, we can easily spot Waldo, i.e. the guy with the red-white stripes (with two different sets of thresholds for the RGB decomposition)

Let us try somthing slightly more complicated, with a zoom on the large picture of the department store (since, to be honest, I know where Waldo is…).

Here again, we can spot the white part (on the left) and the red one (on the right), with some thresholds for the RGB decomposition

Note that we can try to be (much) more selective, playing with threshold. Here, it is not very convincing: I cannot clearly identify the region where Waldo might be (the two graphs below were obtained playing with thresholds)

And if we look at the overall pictures, it is worst. Here are the white zones, and the red ones,

and again, playing with RGB thresholds, I cannot spot Waldo,

Maybe I was a bit optimistic, or ambitious. Let us try something more simple, like finding a flag on the moon. Consider the picture below on the left, and let us see if we can spot an American flag,

Again, on the left, let us identify white areas, and on the right, red ones

Then as before, let us look for horizontal stripes

Waouh, I did it ! That’s one small step for man, one giant leap for R-coders ! Or least for me… So, why might it be interesting to identify areas on pictures ? I mean, I am not Chloe O’Brian, I don’t have to spot flags in a crowd, neither Waldo, nor some terrorists (that might wear striped shirts). This might be fun if you want to give grades for your exams automatically. Consider the two following scans, the template, and a filled copy,

A first step is to identify regions where we expect to find some “red” part (I assume here that students have to use a red pencil). Let us start to check on the template and the filled form if we can identify red areas,

exam = stack("C:\\Users\\exam-blank.png")
red = (exam[[1]]>150)&(max(  exam[[2]] , exam[[3]])<150)
focalsred = focal(red, w=3, fun=mean)
plot(focalsred,useRaster=FALSE) 
exam = stack("C:\\Users\\exam-filled.png")
red = (exam[[1]]>150)&(max(  exam[[2]] , exam[[3]])<150)
focalsred = focal(red, w=3, fun=mean)
plot(focalsred,useRaster=FALSE)

First, we have to identify areas where students have to fill the blanks. So in the template, identify black boxes, and get the coordinates (here manually)

exam = stack("C:\\Users\\exam-blank.png")
black = max(  exam[[1]] ,exam[[2]] , exam[[3]])<50
focalsblack = focal(black, w=3, fun=mean)
plot(focalsblack,useRaster=FALSE)
correct=locator(20)
coordinates=locator(20)
X1=c(73,115,156,199,239)
X2=c(386,428.9,471,510,554)
Y=c(601,536,470,405,341,276,210,145,79,15)
LISTX=c(rep(X1,each=10),rep(X2,each=10))
LISTY=rep(Y,10)
points(LISTX,LISTY,pch=16,col="blue")

The blue points above are where we look for students’ answers. Then, we have to define the vector of correct answers,

CORRECTX=c(X1[c(2,4,1,3,1,1,4,5,2,2)],
X2[c(2,3,4,2,1,1,1,2,5,5)])
CORRECTY=c(Y,Y)
points(CORRECTX, CORRECTY,pch=16,col="red",cex=1.3)
UNCORRECTX=c(X1[rep(1:5,10)[-(c(2,4,1,3,1,1,4,5,2,2)
+seq(0,length=10,by=5))]],
X2[rep(1:5,10)[-(c(2,3,4,2,1,1,1,2,5,5)
+seq(0,length=10,by=5))]])
UNCORRECTY=c(rep(Y,each=4),rep(Y,each=4))

Now, let us get back on red areas in the form filled by the student, identified earlier,

exam = stack("C:\\Users\\exam-filled.png")
red = (exam[[1]]>150)&(max(  exam[[2]] , exam[[3]])<150)
focalsred = focal(red, w=5, fun=mean)

Here, we simply have to compare what the student answered with areas where we expect to find some red in,

ind=which(values(focalsred)>.3)
yind=750-trunc(ind/610)
xind=ind-trunc(ind/610)*610
points(xind,yind,pch=19,cex=.4,col="blue")
points(CORRECTX, CORRECTY,pch=1,
col="red",cex=1.5,lwd=1.5)

Crosses on the graph on the right below are the answers identified as correct (here 13),

> icorrect=values(red)[(750-CORRECTY)*
+ 610+(CORRECTX)]
> points(CORRECTX[icorrect], CORRECTY[icorrect],
+ pch=4,col="black",cex=1.5,lwd=1.5)
> sum(icorrect)
[1] 13

In the case there are negative points for non-correct answer, we can count how many incorrect answers we had. Here 4.

> iuncorrect=values(red)[(750-UNCORRECTY)*610+
+ (UNCORRECTX)]
> sum(iuncorrect)
[1] 4

So I have not been able to find Waldo, but I least, that will probably save me hours next time I have to mark exams…

Choix multiples et théorie des tests

En poursuivant la première question du QCM de “probabilité & statistiques” (en ligne ici pour l’énoncé, et pour une ébauche de correction), on a l’occasion de voir une application intéressante (ou tout du moins selon mon point de vue) de la théorie des tests.

Je souhaite tester une hypothèse

H0:  la personne a répondu au hasard aux questions

(je spécifierais plus tard l’hypothèse alternative, de toutes les façons, on n’en a pas besoin pour construire la statistique de test.)
En répondant au hasard (i.e. sous l’hypothèse H0), la personne avait 1 chance sur 3 de gagner 1 point, et 2 chances sur 3 de perdre 0,5 point1. Bref, à une transformation affine prêt, pour chaque question, on a une loi de Bernoulli. Plus précisément le nombre de points gagnés (ou perdus) à la question i est

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/eqn4809-1.png

Aussi, la loi du nombre total de points est

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/eqn4809-2.png

or si l’on suppose que l’on réponde au hasard à toutes les questions, on peut suppose les variables indépendantes, et donc

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/eqn4809-3.png

et sans être trop prétentieux, on connaît de cette loi (en particulier sa fonction de répartition et sa fonction quantile, au moins numériquement en tous les cas). Bref, si F est cette fonction de répartition,

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/eqn4809-6.png

ensuite on sait faire: c’est juste trouver la loi d’une transformation croissante de cette variable (linéaire en fait). Aussi

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/eqn4809-7.png

c’est à dire

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/eqn4809-9.png

Ben ça peut se représenter facilement avec R
> X=seq(-10,20,by=.1)
> G = function(x){pbinom((10+x)*2/3,size=20,prob=1/3)}
> Y=G(X)
> plot(X,Y,type=”l”)

Notons que je peux aussi avoir la fonction quantile de cette loi. On cherche q tel que

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/eqn4809-10.png

C’est à dire tel que

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/eqn4809-11.png

i.e.

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/eqn4809-12.png

En  R, on obtient la fonction suivante
> G.inv = function(u){1.5*qbinom(u,size=20,prob=1/3)-10}
Voilà, j’ai donc la loi de la note (qui me servira de statistique de test) sous l’hypothèse H0. Bon, ça suffit presque à construire complètement le test. Il suffit de spécifier l’hypothèse alternative afin de construire les régions critiques. A priori je vois deux formes pour l’hypothèse alternative,

H1:  la personne n’a pas répondu au hasard aux questions

ce qui correspondra à un test bilatéral, incluant ceux qui ont des bonnes notes (et qui sont plus fort que le hasard), et ceux qui ont des très mauvaises notes (et qui sont donc moins fort que le hasard en quelque sorte). L’autre hypothèse alternative, qui a plus de sens à mes yeux serait

H1:  la personne est plus forte que le hasard

ce qui sous-entend qu’elle a un peu travaillé (ou qu’elle a raisonné un minimum).
Dans le premier cas, on cherche les deux seuils de la région de rejet
> (note.inf = G.inv(0.05))
-5.5
> (note.sup=G.inv(.975))
6.5 

ce qui donnera un intervalle d’acceptation à 95%. Dans le second cas, on prendra une région de rejet qui commencera à la note minimal (-10), et on montera jusqu’au quantile à 95% de G, soit
> (note.sup=G.inv(.95))

Moralité, il semblerait que pour 20% des élèves, on accepte l’hypothèse comme quoi ils ont répondu au hasard, et on atteint 30% si on prend l’autre hypothèse alternative. En fait, étrangement, si on regarde les réponses à la première question sur le calcul de la moyenne, presque qu’un tiers des élèves a répondu que s’ils cochaient au hasard, ils auraient 6,6667/20. Or ce tiers a précisément obtenu 6,83/20. Donc il semble qu’un tiers des personnes aient effectivement répondu hasard !
Si j’autorise la personne à choisir (au hasard) l’option de ne pas répondre, je me retrouve avec une loi dite multinomiale. On prendra par la suite la proba de ne pas répondre à la question comme paramètre, afin de voir comme le test évolue avec ce paramètre.
Pour décrire la loi mutinomiale

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/eqn4809-13.png

Bref, là aussi on peut obtenir la fonction de répartition de cette loi, ainsi que sa densité… au moins numériquement, car la somme de lois multinomiales indé
pendantes, ça peut vite devenir un peu compliqué.. Bon, je vais faire du numérique par la suite…
On va commencer par supposer que dans 10% des cas, on ne sait pas répondre, ou plutôt on ne répond rien… Dans ce cas, on note que cela ne change pas trop (au moins sur la région de rejet du test).

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/.rejet-rejet-H0-notes-qcm-x-50_m.jpg

Si par contre on suppose que dans 1/4 des cas, on ne répond pas, la région rétrécit,

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/.rejet-rejet-H0-notes-qcm-x-50_m.jpg

et encore davantage si on suppose qu’on ne répond pas dans 50% des cas…

https://blogperso.univ-rennes1.fr/arthur.charpentier/public/perso2/.rejet-rejet-H0-notes-qcm-x-50_m.jpg

1 je ne prends pas en compte la possibilité qu’une personne puisse ne pas répondre…. on verra ça plus tard.