R: Représentation d'une évolution de données par catégories et sous catégories

Pour commencer l’année 2015, je vous propose un nouveau billet sur la représentation de données.

En réalité, avec les bilans de fin d’année, j’ai eu besoin de présenter un jeu de données que je ne peux pas diffuser (et qui ne vous intéresserait pas). Globalement, il s’agit d’une évolution de données sur plusieurs années, classées par catégories et sous-catégories. Les outils classiques des tableurs ne permettent pas d’obtenir des graphiques lisibles.

Plutôt que de conserver cette méthode au fond de mes ordinateurs, je vous propose de vous la partager ici. J’espère qu’elle vous donnera des idées de traitements de données.

Evolution1968-2011.png

À titre d’exemple je vous propose de visualiser l’évolution de population des grandes métropoles de la future région Alca (Alsace-Lorraine-Champagne-Ardennes). N’oubliez pas que l’objectif principal de ce billet est la représentation et l’exploration de données et non leurs interprétations. Par contre vous pourrez réutiliser les outils présentés dans ce billet pour explorer par vous-même vos jeux de données.

Le jeu de données utilisé provient des recensements de la population française de 1968, 1975, 1982, 1990, 1999, 2006, 2011. Le fichier est diffusé sur le site de l’INSEE. «Population selon le sexe et l’âge quinquennal de 1968 à 2011». Décompressé il atteint la taille conséquente de 113M.

Sur l’image ci-dessous vous voyez qu’il contient de multiples onglets où l’on trouve l’intégralité des données recensées par département ou par commune.

sheets.png

Les colonnes contiennent les valeurs pour chaque commune par sexe et tranche d’âge.

cols.png

J’ai choisi de ne m’intéresser qu’aux recensements de 1968, 1982, 1999, et 2011 pour les seules communes de Nancy, Metz, Reims et Strasbourg. Manipuler un fichier de tableur de 113M demande beaucoup de ressources. Les traitements peuvent alors devenir très long. Il est plus simple d’exporter en CSV les onglets qui nous intéressent. On obtient alors 4 fichiers textes de 5M.

Le petit programme perl suivant va nous permettre de très rapidement traiter ces données pour extraire les villes qui nous intéressent et additionner les valeurs des colonnes pour les tranches d’âge choisies. Il est facile à adapter si vous voulez examiner d’autres villes, département ou tranches d’âges.

#!/usr/bin/perl
use strict;
use warnings;

my $fichier = $ARGV[0];
if ( $#ARGV < 0 || !-f $fichier ) {
 print " ./parse.pl fichier \n";
 exit;
};

open my $f ,'<'.$fichier; my @lignes="<$f">;
close $f;

# Définition des tranches d'âge
my %Tranches = ('0-19' => [(6..13)],  # 0-19 ans colonnes 6 a 13
 '20-39' => [(14..21)],
 '40-59' => [(22..29)],
 '60-79' => [(30..37)],
  '80+'  => [(38..45)]                # 80 ans et plus
);

my %Res = (); # Les résultats

# Traitement
foreach my $ligne ( @Lignes ) {
   chomp $ligne;
   my @t = split ',',$ligne;
   # $t[5]  : nom ville, $t[4]  : departement 
   my $ville = $t[5] || '';
   # choix des villes
   next if $ville ne 'METZ'
        && $ville ne 'NANCY'
        && $ville ne 'STRASBOURG'
        && $ville ne 'REIMS';

   $Res{$ville}->{'total'} = 0;

   foreach my $age ( sort keys %Tranches ) {
     $Res{$ville}->{$age} = 0;
     for my $i ( @{$Tranches{$age}} ) { # tableau (a..b)
        my $c = $t[$i];
        $c =~ s/[^\d+]//g; # substitue les valeurs non numérique
        $Res{$ville}->{$age} += $c; # on additionne les colonnes 
     };
     $Res{$ville}->{'total'} += $Res{$ville}->{$age};
    };
}

# Affichage
print "Tranches,Total";
foreach my $age (sort keys %Tranches) {print ','.$age;}
print "\n";

foreach my $ville (sort keys %Res) {
  print $ville . ',' . ($Res{$ville}->{total} || 0);
  foreach my $age (sort keys %Tranches) {
     print ','.($Res{$ville}->{$age} || 0);
  }
  print "\n";
}

On obtient alors 4 fichiers textes, facilement lisibles et de petite taille.

$ perl parse.pl com1968.csv > v1968.csv
$ cat v1968.csv
Tranches,Total,0-19,20-39,40-59,60-79,80+
METZ,106724,39228,31384,22260,12320,1532
NANCY,123044,37784,38068,26240,18092,2860
REIMS,153584,54696,45744,31580,18724,2840
STRASBOURG,248992,83524,74560,53308,34268,3332

Le logiciel R aurait certainement pu traiter l’ensemble du fichier de données mais j’ai préféré l’utiliser uniquement pour la réalisation du graphique. Ainsi on obtient des traitements génériques facilement réutilisables.

J’utilise un peu prêt le même code pour les données qui ne vous concernent pas et ce billet.

require(data.table)
require(reshape2)
require(ggplot2)

# Chargement des fichiers de données
v1 <- read.csv("v1968.csv")
v1 <- data.table(v1)
colnames(v1) <- c("Tranches","Total","a0_19","a20_39","a40_59","a60_79","a80_")
v1.m <- melt(v1[,list(Tranches,a0_19,a20_39,a40_59,a60_79,a80_)])

v2 <- read.csv("v1982.csv")
v2 <- data.table(v2)
colnames(v2) <- c("Tranches","Total","a0_19","a20_39","a40_59","a60_79","a80_")
v2.m <- melt(v2[,list(a0_19,a20_39,a40_59,a60_79,a80_)])

v3 <- read.csv("v1999.csv")
v3 <- data.table(v3)
colnames(v3) <- c("Tranches","Total","a0_19","a20_39","a40_59","a60_79","a80_")
v3.m <- melt(v3[,list(a0_19,a20_39,a40_59,a60_79,a80_)])

v4 <- read.csv("v2011.csv")
v4 <- data.table(v4)
colnames(v4) <- c("Tranches","Total","a0_19","a20_39","a40_59","a60_79","a80_")
v4.m <- melt(v4[,list(a0_19,a20_39,a40_59,a60_79,a80_)])

# Mise en forme des données
v <- cbind(v1.m,v2.m$value,v3.m$value,v4.m$value)
colnames(v) <- c("Tranches","variable"," 1968"," 1982"," 1999"," 2011")

v.m <- melt(v, id.vars=c("Tranches", "variable"))

# Graphique
theme_update(axis.text.x = element_text(angle = 90,hjust = 1),
 panel.grid.major = element_line(colour = "grey80"),
 panel.grid.minor = element_blank(),
 panel.background = element_rect(fill = "grey90", color = "grey90"),
 strip.text.x = element_text(angle = 75),
 strip.background = element_rect(fill = "grey90", color = "grey90"),
 axis.ticks = element_blank(), legend.position = "right")

b <- ggplot(v.m,aes(x = variable.1,y=value,fill=variable)) +
 geom_bar(position = "stack",stat = "identity") + facet_grid(~ Tranches )

# Légendes et couleurs
b <- b +  labs(x="Années",y = "Population", fill = "Tranches d'âge",
   title ="Évolutions urbaines 1968/2011")

impPalette <- c("#CC3300", "#FF6633", "#FF9966", "#FFCC66","#FFAA66")
b <- b + scale_fill_manual(values=impPalette,
 breaks=c("a0_19","a20_39","a40_59","a60_79","a80_"),
 labels=c("0 - 19","20 - 39","40 - 59","60 - 79","80 et plus")
 )

b <- b + scale_y_continuous(breaks=seq(0,300000,30000))

# Génération image 
png("Evolution1968-2011.png", 1000, 800, res = 120)
b
graphics.off()

En observant les données traitées la réalisation du graphique n’est pas très compliquée.

Ainsi la fonction melt permet de transformer les tableaux dans un format long

> v1.m
      Tranches variable value
 1:       METZ    a0_19 39228
 2:      NANCY    a0_19 37784
 3:      REIMS    a0_19 54696
 4: STRASBOURG    a0_19 83524
 5:       METZ   a20_39 31384
...

puis cbind permet d’assembler les diverses années

> v
      Tranches variable  1968  1982  1999  2011
 1:       METZ    a0_19 39228 34820 32250 27019
 2:      NANCY    a0_19 37784 24092 23562 22378
 3:      REIMS    a0_19 54696 56460 48949 44006
 4: STRASBOURG    a0_19 83524 70460 67933 67483
 5:       METZ   a20_39 31384 41888 43874 40134
...

Le passage en format long va permettre de créer un graphique

> v.m
      Tranches variable variable.1 value
 1:       METZ    a0_19       1968 39228
 2:      NANCY    a0_19       1968 37784
 3:      REIMS    a0_19       1968 54696
 4: STRASBOURG    a0_19       1968 83524
 5:       METZ   a20_39       1968 31384
 6:      NANCY   a20_39       1968 38068
...

ggplot permet alors de représenter le graphique en barres superposées : position = “stack” et groupées par la colonne Tranches : facet_grid(~ Tranches ).

Les deux scripts en langage perl et R permettent de rapidement explorer la grande quantité de données des recensements.

L’objectif de ce billet n’est pas d’interpréter ces données même si l’on remarque aisément les baby-boomers des années 60 ou l’augmentation du nombre de personnes très âgées.