Arthur Charpentier

Aller au contenu | Aller au menu | Aller à la recherche

vendredi 6 novembre 2009

Cartes avec R (partie 4)

Un tout petit billet pour compléter sur les cartes... j’ai découver la fonction match.map() de library(maps), qui assigne automatiquement un code R pour un département français à un nom que l’on connaît...
> library(maps)
> france<-map(database="france")
> france$names
> dpt=c("Calvados","Nord","Ille-et-Vilaine","Bouches-du-Rhone")
> couleur=c(2,3,4,6)
> match=match.map(france,dpt)
> color=couleur[match]
> map(database="france", fill=TRUE, col=color)
Ceci répondre à quelques questions posées très récemment

mercredi 28 octobre 2009

La base des graphiques avec R

Dans les cours d’économétrie, j’apprends à utiliser R, mais je dois avouer que je ne passe pas beaucoup de temps sur la paramétrisation des graphiques... A la demande générale, je vais écrire trois lignes pour expliquer ce que j’ai pu comprendre de la manière de générer des graphiques sous R.

  • La fonction plot()
plot() est la fonction de base pour générer un graphique. Cette fonction fait deux choses à la fois: elle crée une fenêtre graphique, et ensuite elle affiche un graphique.
  • Quelques paramtères de la fonction plot()
Par défaut, les graphiques sont dans un rectangle. On peut supprimer le rectangle en mettant en option axes=FALSE. Il suffit alors de demander par exemple axis(1) pour ne tracer que l’axe des abscisses, en bas.
> plot(cars)

> plot(cars,axes=FALSE); axis(1)

Notons que l’on peut aussi rafiner les axes,
> plot(cars,axes=FALSE,xlab="")
> axis(1,col="red",col.axis="blue",font.axis=3)
> axis(2)
> title(xlab="vitesse de la voiture",font.lab=2,col.lab="green",cex.lab=1)

ou encore
> plot(cars,axes=FALSE,ylab="")
> axis(1)
> axis(2,col="red",col.axis="blue",font.axis=2,las=2)
> title(ylab="distance de freinage",font.lab=1,col.lab="red",cex.lab=1.2)

Bon, on peut aussi changer le fond du dessin, soit avec un fond uni, soit avec une image
> par(bg = "thistle")
> plot(cars)

ou bien
> library(pixmap)
> bck <- read.pnm("D:\\fond.pnm")
> plot(bck)
> axis(1)
> axis(2)

Dans ce dernier cas, la taille des axes est liée à la résolution de l’image... on utilise plutôt ça pour des cartes,

On a aussi des paramètres pour les points, dont on peut changer la forme, ou la taille,
> plot(cars,pch=c(1:25,1:25))
> plot(cars,pch=1,cex=seq(0.25,2,length=50))

  • Les fonctions abline(), lines() et points()
Une fois tracé le graphique de base, on peut rajouter d’autres courbes sur le graphique, par exemple une droite de régression
> plot(cars)
> abline(lm(dist~speed,cars),col="red")
> abline(a=-17.579,b=3.932,col="blue",lwd=2)

On peut aussi ajouter non pas une droite, mais une courbe,
> reg=lm(dist~I(speed^2),cars)
> x=seq(5,25,by=0.5)
> y=predict(reg,newdata=data.frame(speed=x))
> plot(cars)
> lines(x,y,lwd=2,col="green")
> reg=lm(dist~speed+I(speed^2)+I(speed^3)+I(speed^4),cars)
> x=seq(5,25,by=0.5)
> y=predict(reg,newdata=data.frame(speed=x))
> plot(cars)
> lines(x,y,lty=2,col="purple")
Cette fonction peut être utilisée, par exemple, pour rajouter une estimation de densité sur un histogramme. Par exemple
> hist(residus,proba=TRUE,col="light green")
> lines(density(residus),col="red",lwd=2)
> x=seq(min(residus),max(residus),lenght=100)
> y=dnorm(x,,mean=0,sd=sd(residus))
> lines(x,y,col="blue",lty=2)
> points(residus,rep(0.037,50))
La fonction points() ici permet de tracer des points, sans les relier. Sinon on peut aussi s’amuser à colorier des régions avec la fonction polygon(),
> densite=density(residus)
> X=densite$x
> Y1=densite$y
> Y2=dnorm(X,,mean=0,sd=sd(residus))
> plot(X,Y1,axes=FALSE,type="l")
> axis(1); axis(2)
> polygon(c(X,rev(X)),c(Y1,rev(Y2)),col="light pink",border = 0)
> lines(X,Y2,col="blue",lty=2)
> lines(X,Y1,col="red",lwd=2)

  • Tracer une série temporelle
Bon, les séries temporelles, c’est toujours un peu plus pénible (mais je crois que c’est vrai quel que soit le logiciel). On peut définir un fecteur comme une série temporelle facilement dès lors que les dates sont régulièrement espacées. Pour reprendre un exemple de l’aide, on peut générer de fausses données mensuelles,
> gnp <- ts(cumsum(1 + round(rnorm(100), 2)),
+           start = c(1954, 7), frequency = 12)
> plot(gnp) # using ’plot.ts’ for time-series plot

Mais on peut aussi tenter de visualiser des données irrégulièrement espacées dans le temps. Et là c’est un peu plus vicieux.
> dates <- c("02/27/92", "02/27/92", "01/14/92", "02/28/92", "02/01/92")
> z=as.Date(dates, "%m/%d/%y")
> zs=sort(z)
> plot(zs,y,type="p")
> plot(zs,y,type="b",col="blue")
La fonction as.Date() permet de convertir une chaîne de caractère sous un format date.

Mais fondamentalement, dans les applications que nous verrons, les dates n’ont que peu d’intérêt ici. On peut travailler directement sur un vecteur (peu importe les dates et leur format). Pour emprunter un graphique qui se trouve sur addictedtor (ici), on peut aussi faire des jolies prédiction
> require(gplots)
> series <- arima.sim(list(ar=0.9),n=250)
> model=arima(series[1:200],c(1,0,0))
> forecast=predict(model,80)
> ylim <- c( min(series[1:200],forecast$pred - 1.96 * forecast$se),
+            max(series[1:200],forecast$pred + 1.96 * forecast$se))
> opar <- par(mar=c(4,4,2,2),las=1)
> plot(series,ylim=ylim,type="n",xlim=c(1,250))
> usr <- par("usr")
> rect(usr[1],usr[3],201   ,usr[4],border=NA,col="light blue")
> rect(201   ,usr[3],usr[2],usr[4],border=NA,col="lavender")
> abline(h= (-3:3)*2 , col ="gray" , lty =3)
> polygon( c(201:280,280:201),
+          c(forecast$pred - 1.96*forecast$se,rev(forecast$pred + 1.96*forecast$se)),
+  col = "light pink",
+  lty=2,border=NA)
> lines( 201:280 , forecast$pred - 1.96*forecast$se , lty=2)
> lines( 201:280 , forecast$pred + 1.96*forecast$se , lty=2)
> lines( series , lwd=2 )
> lines(201:280 , forecast$pred , lwd=2 , col ="white")

  • Tracer des figures avec deux axes (indépendants)
On peut aussi essayer de supersposer des courbes qui ne sont pas représentées suivant les mêmes amplitudes, par exemple
> x=seq(-4,4,length=200)
> y1 = sin(x); y2 = 5*cos(x)
> plot(x, y1, col="blue", type="l",ylim=c(-5,5),axes=FALSE)
> axis(1); axis(2)
> lines(x, y2,col="red")

On peut essayer de faire les deux courbes l’une après l’autre. Pour cela, il vaut juste commencer à utiliser la fonction par() qui gère les fenêtre graphiques,
> ylim <- c(-1.1, 1.1)
> plot(x, y1, col="blue", type="l", ylim=ylim,axes=FALSE, ylab="")
> axis(1);
> ylim <- c(-5.5, 5.5)
> axis(2, col="blue")
> par(new=TRUE)
> plot(x, y2, col="red", type="l", ylim=ylim,axes=FALSE, ylab="")
> axis(4, col="red")
> mtext("Axe du premier graphique", 2, line=2, col="blue", cex=1.2)
> mtext("Axe du second graphique", 4, line=2, col="red", cex=1.2)

Cette fonction peut être utilisée pour générer des fenêtres plus ou moins grandes,
plot.new()
par(fig=c(0.1, 0.6, 0.1, 0.6))
plot(cars,type="p",col="red",lwd=2)
par(new=TRUE)
par(fig=c(0.4, 0.9, 0.4, 0.95))
plot(cars[,2:1],type="p",col="green",lwd=2)
ou on peut insérer un petit graphique dans un plus grand
> plot.new()
> plot(cars,type="p",col="red",lwd=2)
> par(new=TRUE)
> par(fig=c(0.1, 0.7, 0.55, 0.98))
> plot(cars,type="p",col="green",lwd=2)

  • Tracer des jolis graphiques, last but not least
Et pour finir (pour cette fois), juste un petit graphique que l’on peut générer assez facilement avec R, mélangeant des nuages de points et des histogrammes,
> library(evd); data(lossalae)
> plot(lossalae)

permet de visualiser les données brutes, mais on peut faire plus joli,
> x <- lossalae$Loss; y <- lossalae$ALAE
> xhist <- hist(log(x), plot=FALSE)
> yhist <- hist(log(y), plot=FALSE)
> top <- max(c(xhist$counts, yhist$counts))
> nf <- layout(matrix(c(2,0,1,3),2,2,byrow=TRUE), c(3,1), c(1,3), TRUE)
> par(mar=c(3,3,1,1))
> plot(x, y, xlab="", ylab="",log="xy",col="red")
> par(mar=c(0,3,1,1))
> barplot(xhist$counts, axes=FALSE, ylim=c(0, top), space=0,col="light green")
> par(mar=c(3,0,1,1))
> barplot(yhist$counts, axes=FALSE, xlim=c(0, top), space=0, horiz=TRUE,col="light blue")

lundi 28 septembre 2009

Créer des images LaTex

Comme l’insertion de LaTeX n’est plus disponible sur le blog, la solution la plus simple est d’insérer des images (contenant les formules). C’est un peu plus lourd, mais ça marche... Bref, Google a développé un petit widget pour faire ça simplement, je vais donc le mettre ici parce que je passe mon temps à en chercher (il y en existe d’autres ici ou là)

lundi 24 août 2009

Une autre façon de faire du R, sans en avoir l'air

R commander (dans son nom français) permet faire du R sans coder, en cliquant sur la souris, pour ceux qui auraient peur (du code, pas de la souris)... En pratique, il faut installer le package de R Commander (library(Rcmdr)) lors de la première installation, i.e. avant l’installation de tous les autres packages. On a alors à disposition une interface pour utiliser les fonctions R. John Fox a publié une introduction à Rcmdr (ici), et on notera que cet outil est très proche, par exemple, de l’intégration de R dans excel (ici ou sur la toile - parmi tant d’autres - ou encore ici ou sur ce blog).

Dans le cas de l’analyse des données, le package FactoMineR (développé à l’agro) propose une interface via R Commander.

Proposer des interphaces simples de R pour des utilisateurs ne souhaitant pas programmer a été au coeur de la dernière conférence UseR!, donc je pense que beaucoup de choses arriveront prochainement sur le sujet ! à suivre donc.....

jeudi 2 juillet 2009

UseR, tutoriels: gnm et big(g)glm (1)

N’ayant pas encore de don d’ubiquité, je ne pourrais suivre que deux tutoriels mardi à la conférence useR! (le programme est toujours ici). Le matin, c’est l’économétrie sur les très grosses bases de données, avec un exposé de Thomas Lumley sur les library(biglm) et library(bigglm).

L’après midi, Heather Turner viendra présenter library(gnm) d’économétrie nonlinéaire (très utilie pour les modèles un peu poussés de mortalité par exemple). Les slides sont en ligne ici. Pour un petit exemple sur le modèle de Lee-Carter, en mortalité, c’est assez facile.
> Ex = read.table("http://perso.univ-rennes1.fr/arthur.charpentier/FR-Exposures_1x1.txt",header=TRUE)
> Death = read.table("http://perso.univ-rennes1.fr/arthur.charpentier/FR-Deaths_1x1.txt",header=TRUE) 

(pour information, les données viennent du site mortality.org, ici). Ensuite, on bricole un peu car les âges contiennent un "110+", qui trouble: pour transformer cette variable en nombre, on supprime cette réponse, puis on recode le facteur en caractère, puis en nombre.
 > Ex1 = Ex[Ex$Age!="110+",]
> Ex1$AgeI = as.integer(as.character(Ex1$Age))
> Death1 = Death[Death$Age!="110+",]
> Death1$AgeI = as.integer(as.character(Death1$Age))
> Ex = subset(Ex1,select=
+ c("Year","AgeI","Female","Male","Total"))
> names(Ex) = c("Y","A","EF","EM","ET")
> Death = data.frame(Y=Death1$Year,A=Death1$AgeI,
+ DF=Death1$Female,DM=Death1$Male,DT=Death1$Total)
> Base=merge(Ex,Death)
> SBase=Base
> SBase=Base[(Base$A>(-1))&(Base$A<95)==TRUE,]
Pour la suite, il convient d’être un peu patient, l’optimisation se faisant en (très) grande dimension, avec presque 300 paramètres.
> SBase$A=as.factor(SBase$A)
> SBase$Y=as.factor(SBase$Y)
> SBase$Age=as.numeric(as.character(SBase$A))
> SBase$Year=as.numeric(as.character(SBase$Y))
> library(gnm)
> REG = gnm(DT ~ A + Mult(Exp(A),Y),offset=log(ET),
+ family="quasipoisson",data=SBase)
Initialising
Running start-up iterations..
Running main iterations....................
Done

Et voilà, ensuite il suffit de tracer les coefficients de la régression. C’est d’ailleurs ce package qui a permis de faire les graphiques de fond des Journées d’Economiet et d’Econométrie de l’Assurance (ici). Le code suivant permet de récupérer les résidus en fonction de la variable âge, par exemple,
> AGE=unique(SBase$Age)
> res <- residuals(REG, type = "pearson")
> COULEUR=SBase$Year-1898
> CH.COL=heat.colors(max(COULEUR)*1.25)
> COUL=CH.COL[COULEUR]
> plot(SBase$Age, res, xlab="",ylab="",
+ main = "",col=COUL,cex=0.7,xlim=c(0,95),axes=FALSE)
> axis(1)

Ou sinon en fonction de l’année,
> YEAR=unique(SBase$Year)
> res <- residuals(REG, type = "pearson")
> COULEUR=SBase$Age
> CH.COL=heat.colors(max(COULEUR)*1.25)
> COUL=CH.COL[COULEUR]
> plot(SBase$Year, res, xlab="", ylab="",
+ main = "",col=COUL,cex=0.7,xlim=c(1899,2005),axes=FALSE)
> axis(1)

mercredi 1 juillet 2009

Censure (et statistiques)

Je vais faire un petit billet pour répondre à une question de Sonia, sur la "censure à gauche" (dans un cadre statistique !). Il existe plusieurs types de censure en statistique, sur les modèles de durée. Soit Y la variable (positive) d’intérêt,

  • si au lieu d’observer Y on observe C, et si on sait que Y>C, on parle de censure à droite,
  • si au lieu d’observer Y on observe C, et si on sait que Y<C, on parle de censure à gauche,
  • si C est une variable aléatoire, on parle de censure aléatoire.
D’un point de vue statistique, un modèle de durée est un couple de variables, (Y,C) ou bien (Y,D) où D est la variable indicatrice de censure.
Le censure droite peut être visualisée ci-dessous. On observe la durée rouge, mais les observations sont parfois censurées (la durée non-observée est en bleu). Notons que la censure peut dépendre des observations, ou peut même être aléatoire. De plus, les variables Y et C ne sont pas forcément indépendantes. Un exemple classique est l’étude de la stérilité des couples, où passé un certain temps, les couples peuvent se lassser..Example: En assurance, les coûts de sinistres sont parfois censuré à droite: un cambriolage d’appartement est remboursé mais avec un plafond correspondant à la valeur de biens assurés. Le coût d’un sinistre peut être de 13000 euros, mais si l’assuré n’es couvert que jusqu’à 8000 euros, la base de donnée n’indique que le montant maximal. Les données sont alors censurées à droite. Un exemple connu est celui dit loss-alae (avec les indemnités de sinistres, qui sont plafonnés, et les frais associés), ici.
On essaye de déterminer l’âge à partir duquel des enfants savent accomplir une tâche. Au début de l’expérience (ou de la période d’observation) certains savent l’accomplir, et à la fin, certain ne savent toujours pas l’accomplir. Dans ce cas, les observations sont censurées soit à droite, soit à gauche, on parle éventuellement de censure par intervalle.
Le dessin ci-dessous montre la censure à gauche, avec également la censure par intervalle.Remarque: malgré la symétrie qu’il semble y avoir entre les deux types de censure, ce n’est pas forcément le cas. On cherche à estimer la loi d’une durée (aléatoire), par exemple une durée de chômage, caractérisée par une date (aléatoire) de début, notée A, et une date de fin (elle aussi aléatoire) notée B.
La censure à droite correspond à une non-observation de B, et pareil pour A. Sauf que B peut éventuellement ne jamais survenir. C’est en particulier le cas si A correspond à l’apparition de symptômes d’une maladie, et B correspond à la survenance de la maladie.
On peut raffiner un peu la terminologie, en particulier en introduisant une notion de troncature,
  • on dit qu’il y a troncature à gauche si Y n’est pas observable lorsqu’elle est inférieure à un seuil C>0 (fixé)
  • on dit qu’il y a troncature à droite si Y n’est pas observable lorsqu’elle est supérieure à un seuil C>0 (fixé)
Notons que le cas le plus fréquent est celui d’une censure à aléatoire à droite.
Pour aller un peu plus loin sur la pratique, R possède la library(survival) qui permet de modéliser la loi d’une durée avec une censure à droite. Il existe alors une classe d’objets crées à l’aide de la fonction Surv(). Parmi les options, il y a un paramètre type,
typecharacter string specifying the type of censoring. Possible values are "right", "left", "counting", "interval", or "interval2". The default is "right" or "counting" depending on whether the time2 argument is absent or present, respectively.
En effet, il y a un peu plus de censure que les cas que j’ai évoqué, par exemple le fait que l’on observe que tous les ans (et donc on n’a qu’une information partielle). Générons 20 données censurées, avec censure aléatoire,
> n=20; T=rexp(n); C=rep(2,n)
> X=apply(data.frame(T,C),1,min)
> censor= (T==X)*1
> T
 [1] 0.2410449437 2.3516699834 0.3005893449 0.2301904927 0.6113286791
 [6] 0.5029715366 0.6311333952 0.8279694889 0.6825748561 0.4645671406
[11] 0.3115108991 0.0001663509 0.4970689723 0.9466705741 0.3820180311
[16] 1.5033942144 0.0530316979 4.0514764393 0.2316851578 0.4973463849
> X
 [1] 0.2410449437 2.0000000000 0.3005893449 0.2301904927 0.6113286791
 [6] 0.5029715366 0.6311333952 0.8279694889 0.6825748561 0.4645671406
[11] 0.3115108991 0.0001663509 0.4970689723 0.9466705741 0.3820180311
[16] 1.5033942144 0.0530316979 2.0000000000 0.2316851578 0.4973463849
> censor
 [1] 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1
> SX=Surv(X,censor)
> SX
 [1] 0.2410449437  2.0000000000+ 0.3005893449  0.2301904927  0.6113286791
 [6] 0.5029715366  0.6311333952  0.8279694889  0.6825748561  0.4645671406
[11] 0.3115108991  0.0001663509  0.4970689723  0.9466705741  0.3820180311
[16] 1.5033942144  0.0530316979  2.0000000000+ 0.2316851578  0.4973463849   
> plot(survfit(SX))

Il s’agit de l’estimateur de Kaplan-Meier. Mais je ferais un billet par la suite, si je trouve le temps... En attendant, je peux renvoyer vers quelques références ici, ou encore en français.

Si on travaille avec une censure par intervalle, c’est un peu plus complet. Par exemple, avec library(survival)
> n=100
> X1=rep(NA,n)
> X2=C1=C2=Cens1=Cens2=Y1=Y2=TYPE=Duree=X1
> for(i in 1:n){
+ X=rnorm(15)
+ X1[i]=mean(X)-qt(.975,15)*sqrt(var(X))
+ X2[i]=mean(X)+qt(.975,15)*sqrt(var(X))
+ C1[i]=-1.96
+ C2[i]=1.96
+ Cens1[i]=(X1[i]<C1[i])
+ Cens2[i]=(X2[i]>C2[i])
+ Y1[i]=max(X1[i],C1[i])
+ Y2[i]=min(X2[i],C2[i])
+ TYPE[i]=1
+ if(Cens1[i]==1){TYPE[i]=2}
+ if(Cens2[i]==1){TYPE[i]=0}
+ if(((Cens1[i]==1)&(Cens2[i]==1))==TRUE){TYPE[i]=3}
+ Duree[i]=Y2[i]-Y1[i]
+ }
> S=Surv(time=Y1,time2=Y2,event=TYPE,type="interval")
> S
  [1] -1.737262         [-1.960000, 1.96] [-1.960000, 1.96] [-1.960000, 1.96]
  [5] -1.960000-        -1.332074         -1.817311+        [-1.960000, 1.96]
  [9] -1.960000-        [-1.960000, 1.96] [-1.960000, 1.96] [-1.960000, 1.96]
 [13] [-1.960000, 1.96] [-1.960000, 1.96] -1.887473+        -1.790832      
 [17] [-1.960000, 1.96] [-1.960000, 1.96] -1.862076+        [-1.960000, 1.96]
 [21] [-1.960000, 1.96] [-1.960000, 1.96] [-1.960000, 1.96] -1.716272+     
 [25] -1.558675+        [-1.960000, 1.96] -1.960000-        [-1.960000, 1.96]
 [29] -1.932491+        -1.545382         -1.960000-        -1.960000-     
 [33] [-1.960000, 1.96] -1.960000-        -1.657818         [-1.960000, 1.96]
 [37] -1.960000-        [-1.960000, 1.96] -1.877989         -1.957118+     
 [41] [-1.960000, 1.96] [-1.960000, 1.96] [-1.960000, 1.96] -1.960000-     
 [45] -1.856793         -1.273652         [-1.960000, 1.96] [-1.960000, 1.96]
 [49] [-1.960000, 1.96] [-1.960000, 1.96] -1.359959+        -1.634583+     
 [53] -1.212742         [-1.960000, 1.96] [-1.960000, 1.96] -1.647137+     
 [57] [-1.960000, 1.96] -1.880130+        -1.616234+        -1.831402      
 [61] [-1.960000, 1.96] -1.960000-        [-1.960000, 1.96] [-1.960000, 1.96]
 [65] [-1.960000, 1.96] [-1.960000, 1.96] -1.960000-        -1.960000-     
 [69] [-1.960000, 1.96] -1.383674         [-1.960000, 1.96] [-1.960000, 1.96]
 [73] -1.713565+        -1.567787+        -1.954177         [-1.960000, 1.96]
 [77] -1.628864+        -1.809845         [-1.960000, 1.96] -1.416453      
 [81] -1.744155         -1.960000-        -1.576735         [-1.960000, 1.96]
 [85] [-1.960000, 1.96] -1.594431+        [-1.960000, 1.96] [-1.960000, 1.96]
 [89] -1.960000-        -1.960000-        [-1.960000, 1.96] -1.664785      
 [93] -1.692345+        [-1.960000, 1.96] [-1.960000, 1.96] [-1.960000, 1.96]
 [97] [-1.960000, 1.96] [-1.960000, 1.96] [-1.960000, 1.96] [-1.960000, 1.96]

Voici un petit schéma pour visualiser ces données censurées,(les vraies durées sont en bleu, et on observe les durées rouge). Le hic est que l’estimation de Kaplan-Meier ne semble marcher que pour la censure à droite. Et plus généralement, comme noté ici, "note that not all functions will accept all types of data. For example, interval-censored data will not be accepted by the majority of the functions in survival".  Heureusement, il existe des dizaines d’autres packages pour les modèles de durée sous R (décrits ici). Mais les méthodes les plus développées semblent être des techniques Bayesiennes. Ceci est évoqué dans ce papier (ici). Je pense qu’il serait temps que je fasse des billets sur la statistique et l’économétrie bayesienne !
Sinon si quelqu’un connait des codes pour estimer la distribution de la longueur de l’intervalle sur l’exemple précédant, je suis intéressé !

mardi 30 juin 2009

Cartes avec R (partie 3)

J’avais parlé dans un précédant billet (ici) des fonds de cartes avec R. Pour reprendre rapidement, on peut faire des cartes simplement avec des commandes de la forme suivante,
> library(maps)
> map(database="world",regions="France")
Cette dernière commande permet de tracer une carte. Bon, le soucis avec la France (d’un point de vue de la programmation sous R, je ne veux me froisser avec personnes) ce sont ses territoires d’outre-mer.
> M1=map(database="world",regions="France",xlim=c(-5,10),ylim=c(40,52))
> str(M1)
’data.frame’:   27 obs. of  5 variables:
 $ montant: num   1180374 10897008  6662276  9516513  2102222 ...
 $ Y1     : num  2003 2003 2003 2003 2003 ...
 $ Y2     : num  2004 2005 2006 2007 2008 ...
 $ Z1     : num  1 1 1 1 1 1 2 2 2 2 ...
 $ Z2     : num  1 2 3 4 5 6 1 2 3 4 ...
Pour faire quelquechose d’un peu plus joli, on peut utiliser une autre carte. 
> M1=map("france")

Remarque: il faut juste faire attention, sur les cartes un peu grandes sur le style de projection utilisé, qui peut donner des résultats plus ou moins curieux.... Mais c’est un sujet un peu compliqué, et hors sujet (pour l’instant, on verra si je trouve le temps un jour).
J’avais déjà abordé (ici) l’utilisation des départements français avec R. voici une autre méthode, basé sur le fichier dept.rda comprenant la liste des 95 départements français (nom et code). Il est disponible ici. En reprenant le code donné sur la page , on obtient
 > my.cols <- c(rgb(231/255,240/255,251/255),rgb(180/255,210/255,244/255),
               rgb(129/255,180/255,237/255),rgb(0/255,78/255,162/255))
> load("D:\\dept.rda")
> set.seed(1234)
> xx <- data.frame(names=dept[sample(1:95,15),1],n=round(seq(5,300,length=15)))
> xx$grp <- cut(xx$n,breaks=c(0,50,100,250,1000),labels=FALSE)
> map(’france’)
> map(’france’,regions=xx$names,col=my.cols[xx$grp],fill=TRUE,add=TRUE)

  • Utilisation de fichiers shp
Sur le site ici on peut récupérer des fonds de cartes gratuit au format shd (je renvoie ici pour plus de détails sur les cartes avec le langage S). En particulier, la France est dans le fichier zippé ici, ou encore (mais qui semble ressembler au premier), pour une version plus fine.On a aussi des données sur les communes ici ou , voire encore ici ou . Il y a dans ce lot des cartes dites RGC - par code postale. Le soucis est que ces cartes sont au format txt. Il semble (ici) qu’il soit possible de convertir en csv puis en shd, mais sans succès pour l’instant...
Par contre on peut toujours bricoler puisqu’on a les coordonnées de toutes les communes.... 
> B=read.table("http://perso.univ-rennes1.fr/arthur.charpentier/gc_2008b.csv",sep=";", header=TRUE)
> plot(B$XLAMB2,B$YLAMB2,col="red",cex=.2,pch=19)
> plot(B$XLAMB93,B$YLAMB93,col="green",cex=.1,pch=19)
> plot(B$LONGI_GRD,B$LATI_GRD,col="purple",cex=.1,pch=19)
> plot(B$LONGI_DMS,B$LATI_DMS,col="blue",cex=.1,pch=19)

On peut alors directement utiliser un fichier d’élections, par exemple le pourcentage de votes exprimés lors de l’élection présidentielle de 2002 (ce qui n’a aucun sens, je sais bien, un ville de 200 électeurs étant représentée comme une ville de 200 000). Les points rouges correspondent aux communes où le taux de votes exprimés était inférieur à 70%, et en vert, les communes où il était supérieur à 90%. L’exercice n’avait a priori aucun intérêt, pourtant on voit clairement se détacher des régions sur cette carte.
On peut aussi regarder les communes qui ont été déclarées victimes d’une catastrophe naturelle, par exemple les inondations. Une étude par mois donne la carte dynamique suivante
(on retrouve l’absence de corrélation et la forte corrélation spatiale sur ces cartes).
Il existe aussi des bases locales, par exemple les réserves naturelles Bretonnes, ici, ou les zones phytogéographiques, . Bon, promis, après j’arrête, on peut aussi trouver des données sur les routes ici (sur toute l’Europe). Voici quelques exemples de mise en oeuvre, avec tout d’abord des fonds de région et de départements,
> library(maptools)
> SHP="http://perso.univ-rennes1.fr/arthur.charpentier/fr.shp"
> M3=readShapePoly(SHP))
> plot(M3) 

et
> SHP="http://perso.univ-rennes1.fr/arthur.charpentier/fra.shp"
> M4=readShapePoly(SHP))
> plot(M4)

Notons qu’on peut importer autre chose que des régions (i.e. des polygones): on peut lire des lignes ou des points. Par exemple
> SHP="http://perso.univ-rennes1.fr/arthur.charpentier/railways.shp"
> M5=readShapeLines(SHP)
> plot(M5)
> map("france")
> lines(M5 ,col="red")
ou encore
> SHP="http://perso.univ-rennes1.fr/arthur.charpentier/waterways.shp"
> M6=readShapeLines(SHP)
> plot(M6)
> map("france")
> lines(M6 ,col="blue")

C’est joli non ?
Côté routes, je me contente de faire un dessin sur la Bretagne, le fichier est suffisement lourd comme ça
.
On pourrait continuer indéfiniment, la solution la plus simple semblant être de trouver des fichiers gratuits de cartes au format shp.
  • Les autres formats de fond de carte

Sinon il est aussi possible d’utiliser des fichiers de type .ai. C’est un peu plus vicieux, mais on peut les ouvrir via Adobe Image, et ensuite les sauver... Par exemple, j’ai récupéré le fichier des circonscriptions électorales. On peut alors l’utiliser pour visualiser la couleur politique du député (bon, c’est un peu facile je sais, mais je n’ai pas d’autres idées). A suivre...
Il existe aussi les fichiers dcw (Digital Chart of the World), qui se trouvent un peu partout sur internet, ici par exemple.
Beaucoup de choses se développent en ce moment sur ce sujet, par exemple ici, ou encore ici, ou (ou même pour des choses un peu plus techniques). A suivre donc...

PS et promis, la prochaine fois, je parle de lissage spatial...

jeudi 4 juin 2009

Aide mémoire, les couleurs avec R

Ayant toujours du mal à me souvenir du nom des couleurs avec R, je me permets de faire un petit billet. On peut trouver beaucoup d’information ici.
>     SetTextContrastColor <- function(color)
 {    ifelse( mean(col2rgb(color)) > 127, "black", "white")    }
>     TextContrastColor <- unlist( lapply(colors(), SetTextContrastColor) )
>  colCount <- 25 
> rowCount <- 27
> plot( c(1,colCount), c(0,rowCount), type="n", ylab="", xlab="",
+   axes=FALSE, ylim=c(rowCount,0))

> for (j in 0:(rowCount-1)) {
+   base <- j*colCount
+   remaining <- length(colors()) - base
+   RowSize <- ifelse(remaining < colCount, remaining, colCount)
+   rect((1:RowSize)-0.5,j-0.5, (1:RowSize)+0.5,j+0.5,
+     border="black",
+     col=colors()[base + (1:RowSize)])
+   text((1:RowSize), j, paste(base + (1:RowSize)), cex=0.7,
+     col=TextContrastColor[base + (1:RowSize)])  }

Avec ce code assez simple, on peut récupérer le graphique suivant qui présente toutes les couleurs avec leur code

mardi 2 juin 2009

UseR! à Rennes, en juillet prochain

Les journées UseR!, de la conférence annuelle des utilisateurs de R se tiendront à l’Agrocampus à Rennes (ici) les 8, 9 et 10 juillet prochain. La date pour la soumission est dépassée depuis longtemps, mais les inscriptions sont toujours ouvertes, en particulier pour les tutorials (ici). Le programme pour les trois jours est également en ligne (ici). Rendez-vous ensuite pour plusieurs billets sur les nouveaux outils incroyables que j’aurais découvert durant ces trois jours !

mardi 26 mai 2009

Cartes avec R (partie 3)

Je continue un peu les cartes avec R puisqu’un collègue faisant du panel spatial m’a posé la question. Oui, on peut facilement faire des cartes permettant de visualiser la valeur moyenne les résidus par département. La principale difficulté est que R identifie mal les départements, il donc il faut bricoler un peu.. Pour reprendre quelques code évoqués dans un billet précédant
> library(maps);
> CP.CP<-read.table("http://perso.univ-rennes1.fr/arthur.charpentier/code-departement-CP.txt")$V1
> CP.R <-read.table("http://perso.univ-rennes1.fr/arthur.charpentier/code-departement-R.txt")$V1
> nom.dt.r <- function(k) { CP.R[(CP.CP==k)] };
> library(nlme)
> BASE=read.table("http://perso.univ-rennes1.fr/arthur.charpentier/txchom.csv",sep=";",header=TRUE)
> MOY.DPT=gsummary(BASE, groups = BASE$num_dep,FUN=mean)
> Z1=MOY.DPT$txchom;     R1=range(Z1)
> Z2=(Z1-R1[1])/(R1[2]-R1[1]+1)*100+1
> couleur = rev(heat.colors(100))
> couleur2= rep(0,150)
> for(j in 1:95){
+ if(sum( MOY.DPT$dpt==j)>0){  couleur2[
nom.dt.r(j)]=couleur[Z2[MOY.DPT$num_dep==j]]}}
> map("france", fill = TRUE, col = couleur2)
Le code ci-dessus permet de représenter le taux de chômage moyen (sur l’ensemble des années) dans le département. Mais on peut aussi visualiser, ci-dessous, l’évolution du taux de chômage. Il va de soi que tout cela peut être fairt avec des résidus de panel au lieu de faire le taux de chômage...

jeudi 7 mai 2009

Animation avec R

Dans mes slides de cours, je génère souvent beaucoup de graphiques pour donner l’illusion d’avoir une animation (ou alors je fais des vidéos, comme je l’avais fait pour le cours de chaînes de Markov à l’ENSAI). Mais un peu par hasard, je suis tombé sur la library(animation) qui permet - simplement - de faire ça.
Par exemple, pour expliquer la notion d’intervalle de confiance, j’ai l’habitude de présenter un graphique que l’on peut aussi présenter sous forme animée. Pour s’en convaincre, il suffit d’éxécuter le code suivant sous R
library(animation)
ani.options(ani.height = 400, ani.width = 600, outdir = getwd(), nmax = 100,
    interval = 0.15, title = "Demonstration of Confidence Intervals",
    description = "This animation shows the concept of the confidence
    interval which depends on the observations: if the samples change,
    the interval changes too. At last we can see that the coverage rate
    will be approximate to the confidence level.")
ani.start()
par(mar = c(3, 3, 1, 0.5), mgp = c(1.5, 0.5, 0), tcl = -0.3)
conf.int()
ani.stop()
On obtient alors quelque chose qui ressemble à ça
(même si cette fonction génère une page html incluant une animation - et non un fichier gif animé comme ici). Sinon, pour comprendre la construction d’une moyenne mobile, on peut faire
oopt = ani.options(ani.height = 400, ani.width = 400, outdir = getwd(), nmax = 50,
    title = "Demonstration of Moving Window Auto-Regression",
    description = "Compute the AR(1) coefficient for the data in the
    window and plot the confidence intervals. Repeat this step as the
    window moves.")
ani.start()
par(mar = c(2, 3, 1, 0.5), mgp = c(1.5, 0.5, 0))
mwar.ani(lty.rect = 3, pch = 21, col = "red", bg = "yellow",type=’o’)
ani.stop()
ani.options(oopt)
On obtient alors quelque chose qui ressemble à ça....
Pour plus d’exemples, on peut trouver plein de choses sur le blog de Yihui Xie (ici).
Remarque: sinon l’outil idéal pour apprendre à générer des (beaux) graphiques est la même que pour apprendre à programmer: reprendre les exemples qui marchent. Et pour celà, il existe l’incroyable site de Romain François, ici.

Cartes avec R (partie 2)

Un très court complément sur les cartes. Comme je le disais ici, on peut rajouter ce qu’on veut sur un fond de carte. Par exemple, on peut tracer la trajectoire d’un ouragan avec des points indiquant l’intensité.
> FLOYD=read.table("http://perso.univ-rennes1.fr/arthur.charpentier/Floyd.txt")
> couleur = rev(heat.colors(100))
> map("world",xlim=c(-90,-55),ylim=c(20,50),fill=TRUE,col="light green")
> h=2
> for(i in 1:length(FLOYD$x)){
+ points(FLOYD$x[i],FLOYD$y[i],col=couleur[FLOYD$z[i]/3],cex=1,pch=19)
+ text (FLOYD$x[i]+h, FLOYD$y[i] , labels=FLOYD$z[i],cex=0.6) }


Cartes avec R (partie 1)

J’ai déjà parlé un peu de cartographie avec R (ici). En fait, de manière un peu schématique, il convient de noter que les cartes sont composées de deux types d’éléments,

  • un fond de carte,
  • la description de certains éléments
Le fond de carte signifie que l’on insère un "fond" correspondant à une carte, sur laquelle on va superposer des éléments graphiques. On peut d’ailleurs mettre n’importe quoi comme fond, à condition d’avoir une image de type pnm (portable anymap, la convertion pouvant se faire en ligne, ici par exemple). A partir du fichier fond.pnm (il semble qu’il faille le copier en local), on peut faire
> library(pixmap)
> bck <- read.pnm("D:\\fond.pnm")
> plot(bck) 

par définition, le coin  en bas à gauche de l’image est le point (0,0). L’a résolution de l’image étant 1600x902, on obtient les coordonnées du coin en haut à droite. Pour s’en convaincre il suffit de rajouter
> abline(v=0,lwd=5)
> abline(v=1600,lwd=5)
> abline(h=0,lwd=5)
> abline(h=902,lwd=5)

Mais sinon, on peut rajouter à peu près n’importe quoi, comme un histogramme, ou une densité lissée
>plot(bck)
>X=rnorm(250)
>xdens=density(X)
>lines((xdens$x+4)*200,xdens$y*1200+200,col="red",lwd=5) 


Mais côté carte, il y a souvent beaucoup plus d’information, comme la localisation des départements (comme ici) ou des pays. Par exemple, on peut récupérer sur internet des fichiers comme celui ci
>library(maptools)
>load(url("http://spatial.nhh.no/R/etc/TM_WORLD_BORDERS_SIMPL-0.2.RData"))

où les pays sont localisés par leur nom. Avec le code ci-dessous, je colorie la France et le Brésil avec des couleurs prise de manière aléatoire,
>  country2    = c("France","Brazil")
> country.all = wrld_simpl$NAME
> n.all       = length(country.all)
> col.map     = numeric(n.all)
> for (i in 1:length(country2)){col.map[grep(country2[i],country.all)] = runif(1)}
> c2=col.map!=0   
> col.map2=col.map
> col.map2[!c2]=rgb(.95,.96,.97) 
> col.map2[c2]= rgb(patramp(col.map[c2])/255)
> plot(wrld_simpl,col=col.map2,axes=T) 


Je pense que je continuerais un de ces jours ce billet, si j’arrive à mettre la main sur des fonds de carte détaillés pour la France ou l’Europe (si quelqu’un a ces fichiers sous la main, je suis intéressé).

Scatterplot et histogrammes avec R

Chose promise, chose due, un exemple de graphique avec R,
> library(evd); data(lossalae)
> x <- lossalae$Loss; y <- lossalae$ALAE
> xhist <- hist(log(x), plot=FALSE) ; yhist <- hist(log(y), plot=FALSE)
> top <- max(c(xhist$counts, yhist$counts))
> nf <- layout(matrix(c(2,0,1,3),2,2,byrow=TRUE), c(3,1), c(1,3), TRUE)
> par(mar=c(3,3,1,1)) ; plot(x, y, xlab="", ylab="",log="xy",col="red")
> par(mar=c(0,3,1,1));  barplot(xhist$counts, axes=FALSE, ylim=c(0, top), space=0,col="light green")
> par(mar=c(3,0,1,1));  barplot(yhist$counts, axes=FALSE, xlim=c(0, top), space=0, horiz=TRUE,col="light blue")


mercredi 6 mai 2009

Effets individuels avec R

Toujours pour répondre à une question d’élève, je vais parler un peu des modèles sur variables qualitatives (lorsque la variable à expliquer est binomiale). Par exemple, pour poursuivre un peu des exemples traités dans des billets récents (ici ou ), je vais définir une variable décrivant un "prestige élevé" pour une profession.
> prestige<-read.table("http://perso.univ-rennes1.fr/arthur.charpentier/Prestige.txt",header=TRUE)
> seuil= 50; prestige$PE =as.factor
(prestige$prestige > seuil)
Les modèles classiques en économétrie des variables qualitatives (probit ou logit) sont des cas particuliers des modèles linéaires généralisés, avec comme loi une loi binomiale. La fonction de lien canonique est la fonction de répartition de la loi logistique (ce qui donne un modèle logit), mais on peut prendre une fonction de répartition de la loi normale centrée réduite (ce qui donone un modèle probit)
 > REG=glm(Y~X1+X2,data=base,family=binomial(link = "logit"))
> REG=glm(Y~X1+X2,data=base,family=binomial(link = "probit"))
Formellement, on suppose que
F est une fonction de répartition, soit d’une loi normale dans le cas probit, soit d’une loi logistique dans le cas logit. L’utilisation de R peut s’avérer compliqué au premier abord car ces méthodes sont vues comme de simples cas particuliers de modèles beaucoup plus généraux, où la loi de Y appartient à la famille exponentielle (comme la loi normale, la loi binomiale ou la loi de Poisson, pour les plus connues). Le principal avantage est que la syntaxe et l’analyse des sorties est très proche de la régression classique (la plupart des outils de la fonction lm() se retrouvent sur la fonction glm())
Remarque: Pour construire un modèle où Y est binomiale, on change de famille de modèle (on passe de lm à glm), mais pour le cas où une des variables explicatives X est binomiale (ou prenant plus de modalités, comme des classes d’âge, ou des classes de revenu), il suffit de la définir "proprement", c’est à dire en tant que facteur. Je renvoie à la discussion sur les modèles GAM (ici) où la date de survenance est prise en tant que facteur dans les modèles GLM (via la commande as.factor()) mais en tant que valeur numérique dans les modèles GAM.
Voilà pour l’introduction. Mais la question portait plus précisément sur l’étude des effets individuels, oc’est à dire que l’on s’intéresse à
de manière générale dans un modèle linéaire généralisé (par exemple probit).
La moyenne des effets marginaux s’estime alors en considérant
Sous R, on peut les récupérer facilement. Par exemple pour un modèle probit, la fonction lien est la fonction de réparition d’une loi normale centrée réduite, i.e. dnorm(), aussi, on utilise
> REG=glm(PE~income+education,data=prestige,family=binomial(link = "logit"))
> mean(dnorm(predict(REG,type="link"))) * coef(REG)
  (Intercept)        income     education
-1.247750e+00  4.685419e-05  8.488106e-02

On peut aussi faire sommairement une étude graphique,
 > require(vcd)
> spine(PE~income,  data = prestige,  breaks = quantile(prestige$income)

Pour information, ce type de graphique est parfois appelé spinogram dans la littérature.
Si on veut étudier plus d’effets, John Fox a développé la library(effects) qui est dédiée à ce problème. 
Sinon, pour aller plus loin, je renvoie à plusieurs livres, dont Micro-Econometrics for Policy, Program, and Treatment Effects de Myoung-Jae Lee, ou encore Modern Applied Statistics with S.

- page 1 de 3