Stata : gestion des données

Table des matières

Stata est reconnu pour faciliter la gestion et le recodage des données ainsi que l'automatisation de tâches répétitives. Ce chapitre a pour but de discuter les commandes essentielles permettant de manipuler des variables contenues dans un tableau de données. Une caractéristique de Stata est que le concept de variable est à prendre au sens statistique du terme, et non au sens informatique : Stata dispose de "macros" pour tout ce qui relève de la programmation, mais ceci fera l'objet d'un autre chapitre.

Gestion d'un tableau de données

Le format DTA

On a déjà vu un exemple de format natif Stata avec les données auto utilisées dans le chapitre précédent pour illustrer les principes de base de Stata : il s'agit des fichiers DTA. La spécification de ce type de fichier peut être consultée dans le manuel en ligne pour le mot clé dta. Il s'agit d'un format binaire qui a quelque peu évolué entre les versions 12, 13 et 14 de Stata. Si Stat/Transfer permet de passer d'un format à l'autre sans problème, le package foreign de R (read.dta) ne permet de lire que les fichiers Stata 12 ou inférieurs et il est préférable d'utiliser le package haven (read_dta) pour les versions 13 et plus. Cette librairie repose sur la librairie ReadStat, également utilisable en ligne de commande. Attention, dans ce cas, moins d'options sont disponibles (à la date de rédaction de ce chapitre), en particulier en ce qui concerne la gestion des dates et des formats de variable. Une autre solution consiste à utiliser le package readstata13. Pour les utilisateurs de Python, le package Pandas inclut un utilitaire pour la lecture de fichiers Stata (from pandas.io.stata import StataReader).

Les changements notables entre les formats DTA 12 (juillet 2011), 13 (juin 2013, help dta_117) et 14 (avril 2015, help dta ou help dta_119 car il s'agit de la même version que pour Stata 15) portent sur l'utilisation de chaînes de caratères longues, la gestion des facteurs et l'encodage UTF-8 des chaînes de caractères (incluant les noms de variable). Les versions DTA pour Stata 14 et 15 sont identiques, sauf dans le cas de Stata 15/MP qui autorise plus de 32767 variables et possède une structure légèrement différente. En pratique, c'est le support des caratères accentués pour les utilisateurs concernés qui est vraiment appréciable dans la version 15.

Les différentes méthodes permettant de lire des fichiers antérieurs ou postérieurs à la version utilisée de Stata sont décrit dans l'article Reading a Stata dataset with an older version of Stata.1 Si l'on souhaite connaître la version dans laquelle a été sauvé un fichier DTA sans avoir à lire l'en-tête du fichier binaire lui-même, il suffit d'utiliser la commande dtaversion (à partir de Stata 13). Quant à la commande saveold, elle permet de sauvegarder un tableau de données au format Stata 13 ou au format Stata 12 (avec l'option version(12)). Notons que dans le cas où un fichier a été enregistré avec des caractères accentués depuis Stata 15 vers Stata 13, grâce à saveold, traiter ce fichier depuis Stata 13 résultera en une perte du codage Unicode dans l'interface graphique, mais celui-ci reste toutefois géré à peu près correctement dans un terminal.

Les nouvelles versions majeures de Stata sont publiées à peu près tous les deux ans. Pour un historique du développement de Stata, voir l'article de Nick Cox paru dans le Stata Journal [1].

Propriétés d'un tableau Stata

Les données d'illustration sont tirées de [2] et sont disponibles sur le site de Stata Press. Il est possible de télécharger les données directement depuis le site de Stata à l'aide d'une commande telle que net from http://www.stata-press.com/data/kk3/, suivie de net install data, ou alors d'utiliser le fichier gsoep09.dta disponible dans le répertoire data/ de ce projet. Le fichier DTA situé dans le répertoire data/ correspond au fichier data1.dta dans l'archive ZIP ou sur le site Stata.

Voici les instructions permettant de charger les données en mémoire, en supposant que le répertoire de travail contienne bien un répertoire data/ dans lequel se trouve le fichier gsoep09.dta :

clear all
use data/gsoep09
describe, short
set more off
clear all
use data/gsoep09
(SOEP 2009 (Kohler/Kreuter))
describe, short

Contains data from data/gsoep09.dta
  obs:         5,411                          SOEP 2009 (Kohler/Kreuter)
 vars:            65                          13 Feb 2012 17:08
 size:       568,155                          
Sorted by:  persnr

La commande describe permet de décrire le tableau de données. Parmi ses différentes options, short permet de limiter la description à l'en-tête du tableau, c'est-à-dire les informations relatives au nombre d'observations et de variables et aux éventuelles annotations du tableau, tandis que simple permet de n'afficher que la liste des variables.

describe, simple
describe, simple
persnr       income       rooms        eqplif       pic          wor10
hhnr2009     hhinc        renttype     eqpnrj       lsat         wor11
state        hhsize       rent         hhtyp        wor01        wor12
ybirth       hhsize0to14  reval        area1        wor02        sample
sex          rel2head     eqphea       area2        wor03        intnr
mar          ymove        eqpter       dvisits      wor04        hhnr
edu          ybuild       eqpbas       heval        wor05        strata
yedu         condit       eqpgar       hsat         wor06        psu
voc          dsat         eqpalm       polint       wor07        dweight
emp          size         eqpsol       pia          wor08        xweights
egp          seval        eqpair       pib          wor09

Notons qu'il s'agit de données d'enquête, même si nous n'exploiterons pas vraiment les poids de sondage dans les illustrations de ce chapitre. Les dernières variables du tableau sont spécifiques à Stata et permettent d'identifier les unités de sondage (strata et psu) et les poids analytiques (dweight et xweights).

Pour obtenir un aperçu des premières lignes du tableau, et en restreignant la liste des variables affichées, voici comment l'on procéderait avec list :

list persnr-sex in 1/5
list persnr-sex in 1/5

     +-------------------------------------------------------+
     | persnr   hhnr2009             state   ybirth      sex |
     |-------------------------------------------------------|
  1. |   8501         85   N-Rhein-Westfa.     1932     Male |
  2. |   8502         85   N-Rhein-Westfa.     1939   Female |
  3. |  15001        150   N-Rhein-Westfa.     1946     Male |
  4. |  15002        150   N-Rhein-Westfa.     1953   Female |
  5. |  18201     111373    Mecklenburg-V.     1969     Male |
     +-------------------------------------------------------+

On reviendra en détail sur les listes de variables et le qualifieur if dans les sections suivantes. En attendant, il suffit de savoir que l'on peut indiquer une étendue de variables en indiquant le nom de la première variable séparé du nom de la dernière variable par un tiret et que l'instruction in 1/5 permet de ne lister que les observations allant de la ligne 1 à 5. Les lignes correspondent à des unités statistiques mais une des particularités de Stata est l'usage extensif de procédures de tri du tableau de données, par exemple pour calculer des statistiques agrégées par groupes d'unités statistiques, de sorte qu'il n'est pas recommendé de raisonner selon l'hypothèse qu'un numéro de ligne désigne une seule et même unité statistique (immutabilité).

Autres sources de données

En dehors des tableaux de données au format Stata, il est possible d'importer des sources de données de différents types. Outre les fichiers transport de SAS ou des bases de données relationnelles pour lequelles on dispose d'ODBC, Stata gère de manière assez simple les fichiers texte et Excel. Le cas échéant, le logiciel Stat/Transfer permet de passer de pratiquement n'importe quel format d'origine à un foramt Stata 13 (ou 15 avec la dernière version de Stat/Transfer).

Par défaut, Stata cherche les fichiers dans le répertoire de travail courant. On peut le changer avec la commande cd ou avec le navigateur de répertoire situé dans la barre d’état.

Considérons le fichier CSV, birthwt.csv, dont les premières lignes sont affichées ci-dessous :

low,age,lwt,race,smoke,ptl,ht,ui,ftv,bwt
0,19,182,2,0,0,0,1,0,2523
0,33,155,3,0,0,0,0,3,2551
0,20,105,1,1,0,0,0,1,2557
0,21,108,1,1,0,0,1,2,2594
0,18,107,1,1,0,0,1,0,2600

La commande import delimited de Stata 13 permet d'importer l'ensemble des données une fois que l'on a précisé le type de délimiteur de champs (ici, des virgules) et signalé la présence d'une ligne d'en-tête regroupant le nom des variables : import delimited "birthwt.csv", clear delimiter(comma) varnames(1). Les guillemets autour du nom du fichier sont, comme dans les cas des fichiers au format Stata, facultatifs si le nom du fichier ne contient pas d'espaces. L'extension est obligatoire en revanche.

Voici un autre cas de figure, birthwt.dat, dans lequel les données sont séparées par des espaces ou des taquets de tabulation, le fichier ne contenant pas de ligne d'en-tête :

0 19 182 2 0 0 0 1 0 2523
0 33 155 3 0 0 0 0 3 2551
0 20 105 1 1 0 0 0 1 2557
0 21 108 1 1 0 0 1 2 2594
0 18 107 1 1 0 0 1 0 2600

La commande infile permet de gérer ce type de fichier, sachant que dans ce cas il est nécessaire de préciser le nom des variables : infile low age lwt race smoke ptl ht ui ftv bwt using "birthwt.dat", clear. Notons que Stata préfère généralement les extensions de type raw (utilisé par défaut par la commande write) ou txt. La même commande infile permet également d'importer des données brutes accompagnées d'un dictionnaire de données ("codebook"). Voici un exemple de dictionnaire de données pour l'exemple précédent :

dictionary {
_first (1)
byte low "birthweight <2500g"
byte age "age of mother"
int lwt "weight at last menstrual period"
byte race "race"
byte smoke "smoked during pregnancy"
byte ptl "premature labor history (count)"
byte ht "has history of hypertension"
byte ui "presence , uterine irritability"
byte ftv "number of visits to physician during 1st trimester" int bwt "birthweight (grams)"
}

L'importation se réalise alors à l'aide de l'instruction infile using "birthwt.dct", using(birthwt.dat) clear. Encore une fois, les guillemets sont facultatifs si le nom de fichier est sans ambiguïté.

Une autre commande, infix, moins souple que infile, permet de gérer le cas des dictionnaires de données et des données en format fixe, tel qu'on peut encore le trouver dans les fichiers de données des années 80-90. Un exemple est disponible dans le fichier data/lowbwt.dat. Le fichier dictionnaire birthwt.dct contient cette fois-ci les instructions de formatage et de nommage des variables, ainsi que le nom du fichier de données lui-même :

infix dictionary using lowbwt.dat {
8 first
1 lines
int id 2-4
byte low 9-10
byte age 16-18
int lwt 22-25
byte race 31-32
byte smoke 39-40
byte ptl 47-48
byte ht 54-55
byte ui 60-61
byte ftv 66-67
int bwt 72-76
}

L'importation se réalise dans ce cas à l'aide de l'instruction infix using lowbwt.dct, clear.

Type de variables

On distinguera essentiellement les nombres et les caractères, et par extension les chaînes de caractères. Les variables catégorielles sont représentées sont valeurs discrètes auxquelles on associe le plus souvent des étiquettes textuelles, encore appelée "label".

Le mode de stockage des variables numériques, qui s'apparente à la précision de la variable numérique dans sa représentation machine, peut être de 5 types, par degré croissant de précision : byte, int, long, double et float. Les deux derniers types représentent des nombres réels (4 et 8-bytes IEEE float). Par exemple, les variables de type byte permettent de représenter des nombres allant de -127 à 1002 tandis que le type long correspond à un intervalle de valeurs de \([-2 147 483 647, 2 147 483 620]\). Le type byte est généralement utilisé pour le codage numérique des variables catégorielles (binaires ou à plusieurs niveaux). Il est préférable d'utiliser le type long, voire double, ou alors des chaînes de caractères (string) pour coder les identifiants uniques d’une base de données.

Dans le visualisateur de données (browse), les variables numériques apparaissent en noir, les variables catégorielles en bleu et les chaînes de caractères en rouge. Bien qu'il soit préférable de travailler exclusivement avec la console de commandes, la possibilité de visualiser les données à l'aide d'un tableur intégré est un grand plus de Stata. Notons que ce tableur est également accessible en mode édition.

Voici deux exemples de variables : le revenu (income), variable numérique stockée sous forme d'entiers, et le sexe (sex) des répondants, variable catégorielle à deux classes ou niveaux :

list income in 1/5
list sex in 1/5
list income in 1/5

     +--------+
     | income |
     |--------|
  1. |      . |
  2. |      . |
  3. |      0 |
  4. |  19955 |
  5. |  35498 |
     +--------+
list sex in 1/5

     +--------+
     |    sex |
     |--------|
  1. |   Male |
  2. | Female |
  3. |   Male |
  4. | Female |
  5. |   Male |
     +--------+

Les commandes summarize et tabulate permettent respectivement de construire des résumés numériques appropriés pour ces deux types de variable :

summarize income
summarize income

    Variable |       Obs        Mean    Std. Dev.       Min        Max
-------------+--------------------------------------------------------
      income |      4779     20540.6    37422.49          0     897756
tabulate sex
tabulate sex

              Gender |      Freq.     Percent        Cum.
---------------------+-----------------------------------
                Male |      2,585       47.77       47.77
              Female |      2,826       52.23      100.00
---------------------+-----------------------------------
               Total |      5,411      100.00

L'option nolabel de tabulate permet d'afficher les codes numériques au lieu des étiquettes associées à chacun des niveaux de la variable catégorielle.

tabulate sex, nolabel
tabulate sex, nolabel

     Gender |      Freq.     Percent        Cum.
------------+-----------------------------------
          1 |      2,585       47.77       47.77
          2 |      2,826       52.23      100.00
------------+-----------------------------------
      Total |      5,411      100.00

Il est possible d'obtenir la même information en utilisant codebook, l'avantage de cette dernière commande étant qu'elle fonctionne avec une variable ou une liste de variables (voire le tableau en entier si l'on ne spécifie aucune variable) et qu'elle affiche beaucoup plus d'informations sur le mode de représentation et le contenu de la variable :

codebook sex
codebook sex

-------------------------------------------------------------------------------
sex                                                                      Gender
-------------------------------------------------------------------------------

                  type:  numeric (byte)
                 label:  sex

                 range:  [1,2]                        units:  1
         unique values:  2                        missing .:  0/5411

            tabulation:  Freq.   Numeric  Label
                          2585         1  Male
                          2826         2  Female

Variables et liste de variables

Un concept clé dans Stata est la possibilité de travailler avec une seule variable, comme on l'a vu dans l'expression codebook sex, ou avec plusieurs variables. Dans ce dernier cas, on parle de "varlist" et il est généralement utile de bien vérifier lorsque l'on cherche de l'aide si la commande accepte une seule, voire deux variables, ou bien une varlist.

Pour spécifier une liste de variables, il suffit d'indiquer les noms de variables en les séparant par un espace, comme dans l'illustration suivante :

list wor01 wor02 wor03 in 5
list wor01 wor02 wor03 in 5

     +--------------------------------------------------------------+
     |              wor01                wor02                wor03 |
     |--------------------------------------------------------------|
  5. | Somewhat concerned   Somewhat concerned   Somewhat concerned |
     +--------------------------------------------------------------+

Il est également possible d'indiquer le nom de la première variable et le nom de la dernière variable d'une séquence de variables consécutives. Dans ce cas, le délimiteur d'étendue est le tiret :

list wor01-wor03 in 5
list wor01-wor03 in 5

     +--------------------------------------------------------------+
     |              wor01                wor02                wor03 |
     |--------------------------------------------------------------|
  5. | Somewhat concerned   Somewhat concerned   Somewhat concerned |
     +--------------------------------------------------------------+

Les noms de variable peuvent être interpolés par Stata à l'aide des symboles d'expressions rationelles ? (un seul caractère, n'importe lequel parmi les caractères autorisés) et * (un ou plusieurs caractères). Voici deux exemples d'utilisation :

list wor0? in 5
list wor* in 3
list wor0? in 5

     +--------------------------------------------------------------+
  5. |              wor01 |              wor02 |              wor03 |
     | Somewhat concerned | Somewhat concerned | Somewhat concerned |
     |--------------------+--------------------+--------------------|
     |              wor04 |              wor05 |              wor06 |
     | Somewhat concerned | Somewhat concerned | Somewhat concerned |
     |--------------------------------------------------------------|
     |              wor07  |          wor08  |               wor09  |
     | Somewhat concerned  | Very concerned  |  Somewhat concerned  |
     +--------------------------------------------------------------+
list wor* in 3

     +--------------------------------------------------------------+
  3. |              wor01 |              wor02 |              wor03 |
     | Somewhat concerned | Somewhat concerned | Somewhat concerned |
     |--------------------------------------------------------------|
     |          wor04  |              wor05  |               wor06  |
     | Very concerned  | Somewhat concerned  |  Somewhat concerned  |
     |--------------------------------------------------------------|
     |              wor07  |              wor08  |           wor09  |
     | Somewhat concerned  | Somewhat concerned  |  Very concerned  |
     |---------------------+---------------------+------------------|
     |              wor10  |              wor11  |           wor12  |
     | Somewhat concerned  | Somewhat concerned  |  Does not apply  |
     +--------------------------------------------------------------+

Enfin, on peut combiner les différentes approches comme dans l'exemple suivant :

list persnr sex wor01-wor03 in 1
list persnr sex wor01-wor03 in 1

     +----------------------------------------------------------------------+
     | persnr    sex            wor01                wor02            wor03 |
     |----------------------------------------------------------------------|
  1. |   8501   Male   Very concerned   Somewhat concerned   Very concerned |
     +----------------------------------------------------------------------+

L'usage de listes de variables facilite beaucoup de tâches qui pourrait apparaître fastidieuses autrement (lister explicitement une dizaine de variables) ou nécessiter de programmer une boucle (renommer un ensemble de variables). Voici par exemple comment renommer des variables en bloc à l'aide de rename :

rename wor* q*

La variable hhnr s'apparente à hhnr2009 puisqu'il s'agit d'un identifiant unique pour les foyers résidentiels. Cette variable peut être d'ores et déjà supprimée à l'aide de drop puisqu'elle ne sera pas exploitée :

drop hhnr
drop hhnr

Il est possible de rechercher une variable par mot-clé à l'aide de la commande lookfor. Cette commande recherche également le mot-clé dans les étiquettes des variables. De plus, la commande describe dispose d'options utiles pour filtrer les variables d'intérêt, comme l'illustrent les commandes suivantes :

describe, has(type numeric)
describe, not(type string)

Manipulation de variables

Syntaxe élémentaire des commandes Stata

De manière générale, les commandes Stata sont structurées de la manière suivante :

[by varlist:] command [varlist] [=exp] [if exp] [in range] [weight] [using filename] [,options]

Tous les éléments entre crochets sont optionnels. On distingue les options principales, situées avec la virgule, et les options secondaires situées après celle-ci. Les éléments clés sont le nom de la commande (command), les qualifieurs if et in permettant de sélectionner des unités statistiques (lignes du tableau) et le préfixe by qui autorise la répétition d'une même instruction pour chaque valeur prise par une variable ou par le croisement des valeurs d'une liste de variables (varlist). L'argument =exp est réservé au cas particulier où l'on construit une variable à partir d'une expression. L'option weight est utilisée pour appliquer des poids d'analyse aux observations ; il peut s'agir de poids de fréquence ("fweight"), de poids de probabilité ("pweight") et de poids analytiques ("aweight"). L'argument using filename permet de spécifier un fichier d'entrée ou de sortie pour certaines commandes.

Voici quelques illustrations de ces différentes options. Considérons le revenu annuel (en euros) et son résumé numérique produit avec summarize :

summarize income
summarize income

    Variable |       Obs        Mean    Std. Dev.       Min        Max
-------------+--------------------------------------------------------
      income |      4779     20540.6    37422.49          0     897756

Le nombre total d'observations affiché par summarize diffère du nombre total de lignes présentes dans la tableau, comme on peut le vérifier avec describe ou avec la commande count. Il est possible de dénombrer les valeurs manquantes avec la même commande et la fonction missing :

count
count if missing(income)
count
 5411
count if missing(income)
  632

La sélection des observations manquantes est réalisée avec le qualifieur if. Il est possible de raffiner le filtre de sélection en utilisant les opérateurs logiques habituels : le symbole & désigne la conjonction ("et" logique), | la disjonction ("ou"), ! la négation. On dispose également des opérateurs de comparaison unaire >, >=, < et <=. Il est également possible d'utiliser les fonctions inlist et inrange que l'on détaillera plus loin. Seules les observations vérifiant la condition logique spécifiée après le if seront sélectionnées. Voici un exemple où l'on dénombre les revenus non manquants parmi les femmes :

count if missing(income) & sex == 2
count if missing(income) & sex == 2
  367

Il est important de bien spécifier le code numérique et non l'étiquette associée à un niveau dans le cas d'une variable catégorielle.

Considérons à présent l'âge des répondants, que l'on peut reconstruire à partir de l'année de réalisation de l'enquête (2009) et de l'année de naissance des individus :

generate age = 2009 - ybirth
order age, after(ybirth)
summarize age
generate age = 2009 - ybirth
order age, after(ybirth)
summarize age

    Variable |       Obs        Mean    Std. Dev.       Min        Max
-------------+--------------------------------------------------------
         age |      5411    49.50712    18.12642         17        100

La commande order permet de déplacer la position d'une variables, ou plus généralement d'une varlist, en spécifiant en option la position relative par rapport à une variable déjà présente dans le tableau. Il est également possible d'utiliser les options first ou last pour placer la ou les variables en première ou dernière position du tableau, respectivement.

Voici comment résumer numériquement cette variable pour les seuls individus pour lesquels l'information concernant le revenu est connue :

summarize age if !missing(income)
summarize age if !missing(income)

    Variable |       Obs        Mean    Std. Dev.       Min        Max
-------------+--------------------------------------------------------
         age |      4779    48.15694    17.32985         17        100

Enfin, il est également possible de stratifier l'analyse selon le sexe à l'aide du préfixe by :

by sex, sort : summarize age if !missing(income)
by sex, sort : summarize age if !missing(income)

-------------------------------------------------------------------------------
-> sex = Male

    Variable |       Obs        Mean    Std. Dev.       Min        Max
-------------+--------------------------------------------------------
         age |      2320     47.9431    17.17362         17        100

-------------------------------------------------------------------------------
-> sex = Female

    Variable |       Obs        Mean    Std. Dev.       Min        Max
-------------+--------------------------------------------------------
         age |      2459    48.35868    17.47705         17         97

Comme on peut le constater, il est impératif de trier les données selon la variable de classification avant de calculer les statistiques de groupe. Le tri peut être réalisé à l'aide de sort avant d'appeler la commande summarize, ou directement via le préfixe by ; il s'agit alors d'une option à placer après la virgule. Il est également possible d'utiliser bysort, qui est strictement équivalent à by avec l'option sort.

Création et mise à jour de variables

On a déjà vu un exemple de création de variable dans les illustrations précédentes avec la commande generate. Voici une utilisation plus avancée où l'on construit une nouvelle variable à partir d'une expression mathématique, le logarithme du revenu :

generate lincome = log(income)
generate lincome = log(income)
(2001 missing values generated)

L'expression ci-dessus correspond bien à la syntaxe discutée dans la section précédente, command [varlist] [=exp]. Le résultat de cette instruction a généré de nombreuses valeurs manquantes, ce qui s'explique par la présence de revenus annuels valant 0, valeur pour laquelle le logarithme n'est pas défini, en plus des valeurs manquantes d'origine pour lesquelles le logarithme n'est pas non plus défini. Il y a au moins deux manières de pallier à ce problème : on peut remplacer l'expression log(income) par log(income+1) (l'ajout d'une unité ne devrait pas modifier foncièrement les analyses de cette variable étant donnée l'étendue des valeurs observées et la valeur de tendance centrale) ou alors on peut traiter les valeurs nulles de income comme des valeurs manquantes. Dans le second cas de figure, pour être à même de distinguer les valeurs manquantes d'origine des valeurs imputées, il convient d'utiliser un code de valeur manquante différent. Voici comment procéder :

cap drop lincome
mvdecode income, mv(0=.c)
generate lincome = log(income)
cap drop lincome
mvdecode income, mv(0=.c)
      income: 1369 missing values generated
generate lincome = log(income)
(2001 missing values generated)

Voici un résumé des valeurs manquantes présentes dans ces deux variables :

misstable summarize *income
misstable summarize *income
                                                               Obs<.
                                                +------------------------------
               |                                | Unique
      Variable |     Obs=.     Obs>.     Obs<.  | values        Min         Max
  -------------+--------------------------------+------------------------------
        income |       632     1,369     3,410  |   >500         46      897756
       lincome |     2,001               3,410  |   >500   3.828641    13.70765
  -----------------------------------------------------------------------------

On pourra vérifier que la transformation logarithmique a contribué à stabiliser quelque peu la variance et à symétriser la distribution, même si celle-ci reste loin d'une distribution normale.

label variable lincome "Annual income in euros (log)"
graph twoway histogram lincome, fraction bfcolor(gs3) blcolor(none)
graph export "fig-01-histogram-lincome.eps", replace

fig-01-histogram-lincome.png

Figure 1 : Distribution du log du revenu annuel (euros)

Étiquette et annotation

Il est préférable de travailler avec des noms de variables court, en minuscules, et groupés par ordre logique dans le tableau. Cela facilite le travail de sélection de variable isolées ou de groupes de variables (varlist), leur insertion dans des commandes ou dans des structures de contrôle, par exemple des boucles foreach. Ceci dit, il est toujours plus pratique de donner un descriptif même succinct de chacune des variables afin de pouvoir annoter automatiquement les axes des graphiques sur lesquels ces variables sont amenées à varier ou dans les tableaux de synthèse. C'est d'ailleurs une pratique assez courante dans le monde des enquêtes que d'annoter systématiquement les différents items d'un questionnaire avec l'intitulé de la question.

La commande label est une méta commande qui comporte plusieurs sous commandes. Ainsi, avec label variable il est possible de donner un intitulé bref à la variable elle-même. Prenons le cas de la variable lincome créée à l'étape précédente.

label variable lincome "Annual income in euros (log)"
label variable lincome "Annual income in euros (log)"

Une fois étiquetté, le libellé des variables apparaîtra dans les sorties de describe, codebook, les graphiques et les tableaux :

codebook lincome
codebook lincome

-------------------------------------------------------------------------------
lincome                                            Annual income in euros (log)
-------------------------------------------------------------------------------

                  type:  numeric (float)

                 range:  [3.8286414,13.707654]        units:  1.000e-07
         unique values:  3286                     missing .:  2001/5411

                  mean:   9.77026
              std. dev:   1.12441

           percentiles:        10%       25%       50%       75%       90%
                           8.25946   9.21433   10.0363   10.5168   10.8828

Quant aux variables catégorielles, on a vu qu'il s'agit essentiellement de variables représentées sous forme d'entiers consécutifs, \(\{1,2,\dots,k\}\), ou de valeurs 0/1 dans le cas des variables binaires, auxquels on associe des étiquettes. Ceci est réalisé avec les commandes label define et label values, comme illustré dans l'exemple suivant :

generate insample = !missing(lincome)
label define insample 0 "Not analyzed (income = .)" 1 "In sample (income > .)"
label values insample insample
generate insample = !missing(lincome)
 "
label values insample insample
tabulate insample
tabulate insample

                 insample |      Freq.     Percent        Cum.
--------------------------+-----------------------------------
Not analyzed (income = .) |      2,001       36.98       36.98
   In sample (income > .) |      3,410       63.02      100.00
--------------------------+-----------------------------------
                    Total |      5,411      100.00

Notons que l'on utilise souvent le même nom d'étiquette que le nom de la variable lorsque ce jeu d'étiquette de niveaux est réellement spécifique de cette variable. Le cas échéant, un même jeu d'étiquettes peut être appliqué à une liste de variables. C'est le cas par exemple pour les variables wor* :

label list concern3
label list concern3
concern3:
           1 Very concerned
           2 Somewhat concerned
           3 Not concerned at all
          .a Refusal
          .b Does not apply
          .c Inconsistent

Enfin, il est possible d'annoter un tableau ou une variable à l'aide de la commande note. Un usage courant consiste à indiquer pour le tableau sa date de création et la source des données, et pour les variables les éventuelles transformations ou révisions qu'elles ont subi.

Changement de mode de stockage et format

Si la précision automatiquement choisie par Stata n'est pas indispensable à l'interprétation des résultats ou si l'on souhaite simplement appliquer automatiquement un arrondi des valeurs, la commande format permet de modifier le format d'affichage global d'une ou plusieurs variables. Notons que les formats d'affichage peuvent également s'appliquer localement lors de l'utilisation de certaines commandes telles que summarize. Par exemple, en appliquant un format limitant l'affichage à 2 décimales, voici ce que la commande précédente donnerait :

format age %5.2f
summarize age, format
format age %5.2f
summarize age, format

    Variable |       Obs        Mean    Std. Dev.       Min        Max
-------------+--------------------------------------------------------
         age |      5411       49.51       18.13      17.00     100.00

Gestion des dates

Stata offre deux types de représentation pour les dates : les dates simples (jour, mois, année) sont gérées avec date tandis que les dates avec horaire (et fuseau horaire) sont gérées avec datetime. Les dates peuvent être représentées sous forme de chaînes de caractère ou de nombres (nombre de jours depuis le 01/01/1960 ou de ms depuis le 01/01/1960 minuit). Cette dernière représentation facilite la manipulation numérique des dates puisque les opérations arithmétiques classiques sont permises.

L’affichage des dates se personnalise à l’aide des formats %td et %tc. Stata dispose également des pseudo fonctions td() et tc(). Il est toujours possible de passer d’un format de représentation à l’autre. La fonction clock convertit les dates + heures stockées sous forme de texte en nombres. De même, date permet de convertir des dates simples en nombres.

Pour la conversion de dates gérées sous d’autres logiciels statistiques (SAS, SPSS, R), voir le manuel "[D] datetime" (help datetime). Les dates formatées sous MS Excel sont généralement traitées correctement (en utilisant import excel).

Recodage de variables numériques

Par recodage, on entend la discrétisation d'une variable numérique en variable catégorielle à plusieurs classes ou niveaux, ainsi que la transformation d'une variable catégorielle (création ou agrégation de niveaux).

xtile age4 = age, nq(4)
tabulate age4
xtile age4 = age, nq(4)
tabulate age4

4 quantiles |
     of age |      Freq.     Percent        Cum.
------------+-----------------------------------
          1 |      1,410       26.06       26.06
          2 |      1,395       25.78       51.84
          3 |      1,255       23.19       75.03
          4 |      1,351       24.97      100.00
------------+-----------------------------------
      Total |      5,411      100.00

Il existe d'autres façons d'aborder le même problème. Tout d'abord on peut procéder à un recodage "en ligne" à l'aide de autocode :

generate age5 = autocode(age, 5, 17, 100)
tabulate age5
generate age5 = autocode(age, 5, 17, 100)
tabulate age5

       age5 |      Freq.     Percent        Cum.
------------+-----------------------------------
       33.6 |      1,181       21.83       21.83
       50.2 |      1,719       31.77       53.59
       66.8 |      1,345       24.86       78.45
       83.4 |      1,030       19.04       97.49
        100 |        136        2.51      100.00
------------+-----------------------------------
      Total |      5,411      100.00

On peut également utiliser la commande egen cut qui permet de discrétiser une variable numérique en intervalles de classes réguliers ou irréguliers.

Enfin, la création d'une variable binaire ne pose pas de souci particulier :

quietly summarize age, detail
generate byte ageb = age >= r(p50) if !missing(age)
quietly summarize age, detail
generate byte ageb = age >= r(p50) if !missing(age)

Une formulation équivalente consisterait à utiliser les instructions suivantes :

generate byte ageb = 0 if !missing(age)
replace ageb = 1 if age >= r(p50)

Recodage de variables non-numériques

La commande encode permet de convertir une variable contenant du texte (chaîne de caractères) en variable catégorielle (codes numériques débutant à 1) : les modalités uniques de la variable sont utilisées comme étiquettes ("label") de la nouvelle variable générée. Une alternative consiste à utiliser egen group. Lorsque l'on utilise encode, l'option gen() permet de créer une nouvelle variable.

La commande decode effectue l’opération inverse : elle permet de convertir les étiquettes d’une variable catégorielle en contenu texte (il n’y a donc plus de codes numériques associés à la nouvelle variable). Pour convertir des nombres en caractères, on utilise la commande tostring (ou generate newvar = string(oldvar)). Enfin, la commande destring permet de convertir des nombres représentés sous forme de caractères par Stata (problème d’importation ou mauvaise manipulation).

Dans le cas des variables catégorielles (avec ou sans étiquettes), il est possible d'utiliser la fonction recode. Considérons la variable egp qui représente la classe socio-économique (selon la nomenclature allemande) des répondants. Cette variable est composée de 9 classes, en omettant les valeurs traitées comme manquantes (étiquettées "Refusal" et "Does not apply"). On peut construire très facilement le tableau d'effectifs associés à l'aide de tabulate, l'option missing permettant de dénombrer les valeurs manquantes :

tabulate egp, missing
tabulate egp, missing

                Social Class (EGP) |      Freq.     Percent        Cum.
-----------------------------------+-----------------------------------
                   Service class 1 |        354        6.54        6.54
                   Service class 2 |        739       13.66       20.20
        Higher routine non-manuals |        296        5.47       25.67
         Lower routine non-manuals |        373        6.89       32.56
                     Self-Employed |        213        3.94       36.50
            Skilled manual workers |        486        8.98       45.48
Semi- and unskilled manual workers |        627       11.59       57.07
                        unemployed |        312        5.77       62.83
                           Retired |      1,389       25.67       88.50
                           Refusal |         24        0.44       88.95
                    Does not apply |        598       11.05      100.00
-----------------------------------+-----------------------------------
                             Total |      5,411      100.00

Supposons que l'on souhaite recoder cette variable en 3 classes, en ignorant les classes "unemployed" et "Retired", ainsi que les valeurs manquantes. Pour cela, on utilisera la commande recode en indiquant le schéma d'agrégation des classes dans une liste de clauses et le nom de la nouvelle variable à générer puisque le cas échéant recode agit comme une commande replace. Voici un exemple d'utilisation :

recode egp (1/2=1) (3/5=2) (8/9=3) (15/18=.), gen(egp3)
label define egp3 1 "Service class 1/2" 2 "Non-manuals" 3 "Manuals"
label values egp3 egp3
tabulate egp3
recode egp (1/2=1) (3/5=2) (8/9=3) (15/18=.), gen(egp3)
(4435 differences between egp and egp3)
label define egp3 1 "Service class 1/2" 2 "Non-manuals" 3 "Manuals"
label values egp3 egp3
tabulate egp3

    RECODE of egp |
    (Social Class |
           (EGP)) |      Freq.     Percent        Cum.
------------------+-----------------------------------
Service class 1/2 |      1,093       35.40       35.40
      Non-manuals |        882       28.56       63.96
          Manuals |      1,113       36.04      100.00
------------------+-----------------------------------
            Total |      3,088      100.00

Utilisation d'expressions régulières

Plutôt que de sélectionner des observations selon des valeurs ou des ensembles de valeurs logiques ou numériques, il est tout à fait possible de rechercher des observations répondant à certains critères en utilisant des expressions régulières.

Stata dispose de trois commandes (des fonctions plus exactement) permettant d’effectuer des manipulations sur les chaînes de caractères à partir d’expressions régulières :

  • regexm : (m)atch une expression (utile pour créer une variable binaire)
  • regexr : (r)eplace une expression par une autre
  • regexs : (s)ubexpression obtenue à partir de regexm

Voir l’aide en ligne [D] functions pour les chaînes de caractères (help string_functions).

Voici un exemple d'application :

decode state, gen(state_)
generate inberlin = regexm(state_, "^Berl")
drop state_
tabulate state inberlin if inlist(state, 0, 1, 2)
decode state, gen(state_)
generate inberlin = regexm(state_, "^Berl")
drop state_
tabulate state inberlin if inlist(state, 0, 1, 2)

        State of |       inberlin
       Residence |         0          1 |     Total
-----------------+----------------------+----------
          Berlin |         0        208 |       208 
 Schleswig-Hols. |       166          0 |       166 
  Hamburg/Bremen |       101          0 |       101 
-----------------+----------------------+----------
           Total |       267        208 |       475

Traitement des données manquantes

Stata dispose de plusieurs codes de valeurs manquantes :

  • . est le codage par défaut (missing(var) ou var > .=) ;
  • .a–.z (valeurs manquantes étendues) peuvent être utilisés pour coder des valeurs manquantes ayant une signification différente (cas des sondages, par exemple).

Il est possible d’associer des étiquettes aux valeurs manquantes étendues grâce à label define afin de les lister lors de tris simple ou croisé. La commande misstable (sous-commande summarize ou pattern) fournit un résumé des données manquantes pour une ou plusieurs variables.

misstable pattern q01-q03
misstable pattern q01-q03

   Missing-value patterns
     (1 means complete)

              |   Pattern
    Percent   |  1  2  3
  ------------+-------------
       98%    |  1  1  1
              |
        1     |  0  0  0
       <1     |  1  1  0
       <1     |  1  0  1
       <1     |  1  0  0
       <1     |  0  0  1
       <1     |  0  1  0
       <1     |  0  1  1
  ------------+-------------
      100%    |

  Variables are  (1) q01  (2) q02  (3) q03

Les deux principales commandes permettant de gérer les valeurs manquantes sont indiquées ci-dessous :

  • mvdecode : permet de remplacer des valeurs existantes par un ou plusieurs codes de valeur manquante ; fonctionnement identique à recode
  • mvencode : permet de convertir des données manquantes en valeurs exploitables par Stata (texte ou nombre).

Voici un exemple d'utilisation pour recoder automatiquement les revenus nuls à un code de valeur manquante spécifique (.c), ce qui permet de faire la distinction entre les revenus réellement non renseignés (.) et les revenus valant 0 et que l'on peut souhaiter analyser séparément ou à l'aide de modèles statistiques autres que le modèle linéaire classique. On a déjà vu un exemple d'application de mvdecode plus haut. Voici un bref rappel de l'idée de base pour utiliser ces commandes :

mvdecode income, mv(0=.c)
generate lincome = log(income)
mvencode income, mv(.c=0)
summarize *inc*

Transformation d'un tableau

Sélection d'observations et tri

On a vu que la commande drop permet de supprimer une ou plusieurs variables dans un tableau de données. En réalité cette commande fonctionne également pour filtrer des observations, de même que keep qui permet, au contraire, de conserver des variables ou des observations. Dans l'enquête socio-économique, supposons que l'on souhaite ne conserver pour les analyses que les personnes majeures (age > 17), il suffirait d'utiliser l'une de ces deux commandes. Par exemple :

keep if age > 17 & !missing(age)
count
keep if age > 17 & !missing(age)
(66 observations deleted)
count
 5345

Les procédures de tri, comme on l'a déjà dit, sont essentielles pour travailler efficacement avec Stata. Stata dispose de deux commandes pour réaliser des tri croissants (sort) ou dans les deux directions (gsort), bien que dans la commande générique reste la commande sort. Celle-ci agit également comme option dans le cas du préfixe by. Si un tableau est trié sur une ou plusieurs variables, la commande describe l'indique à la suite de la liste des variables. Dans le cas de l'enquête socio-économique, les données sont triées selon la variable persnr.

Voici un exemple plus élaboré, tiré directement de l'ouvrage de [2] :

by hhnr2009 (rel2head), sort: generate agediff = ybirth - ybirth[_n-1] if rel2head == 2

Cette instruction permet de calculer la différence d'âge entre le père de famille (head) et sa partenaire (partner) dans chacun des foyers. La subtilité vient du tri primaire sur la variable hhnr2009 (foyer) puis du tri secondaire sur la variable rel2head (situation familiale des répondants) sans que ce dernier ne soit utilisé pour grouper les opérations sous le préfixe by. La condition if rel2head==2 permet de s'assurer que l'on effectue bien le calcule dans le cas où il existe au moins deux personnes dans le foyer.

tabulate rel2head if rel2head < 3
summarize agediff
tabulate rel2head if rel2head < 3

  Relationship |
    to HH Head |      Freq.     Percent        Cum.
---------------+-----------------------------------
          Head |      3,045       64.50       64.50
       Partner |      1,676       35.50      100.00
---------------+-----------------------------------
         Total |      4,721      100.00
summarize agediff

    Variable |       Obs        Mean    Std. Dev.       Min        Max
-------------+--------------------------------------------------------
     agediff |      1672    1.358852    5.168304        -27         33

Optimisation de la taille mémoire

La commande compress permet d'optimiser le mode de stockage des variables. Cette commande n'altère pas le contenu de la base de données et n'induit aucune perte de précision.

La taille d'un tableau de données peut être approximée de la manière suivante : il s'agit du rapport \((N\times V\times W + 4N) / 1024^2\), où \(N\) désigne le nombre d'observations, \(V\) le nombre de variables et \(W\) la taille moyenne des variables (entiers de 1 à 4, réels de 4 à 8).3

How big will my dataset be?

Dans le cas de l'enquête socio-économique, la taille en mémoire du tableau est d'environ 568 Ko :

describe, short
describe, short

Contains data from data/gsoep09.dta
  obs:         5,345                          SOEP 2009 (Kohler/Kreuter)
 vars:            73                          13 Feb 2012 17:08
 size:       684,160                          
Sorted by:  hhnr2009  rel2head
     Note:  dataset has changed since last saved

On ne gagnera rien à compresser ce tableau dans la mesure où il est déjà optimisé mais cela vaut souvent la peine de vérifier si le gain de taille est substantiel ou non avant de sauvegarder la version finale d'une base de données.

Agrégation

Par agrégation on entend le procédé qui consiste à réduire un ensemble d'observations à une valeur unique, typiquement un indicateur de tendance centrale ou l'effectif total, selon différentes variables de classification. Par exemple, dans cette enquête socio-économique, on pourrait vouloir calculer le revenu médian par "lander" (state) selon le sexe et la classe d'âge. Voici une manière de procéder avec la commande collapse :

preserve
collapse (p50) income, by(sex age4)
list
preserve
collapse (p50) income, by(sex age4)
list

     +-------------------------+
     |    sex   age4    income |
     |-------------------------|
  1. |   Male      1     13521 |
  2. |   Male      2   36036.5 |
  3. |   Male      3   33096.5 |
  4. |   Male      4         0 |
  5. | Female      1    8082.5 |
     |-------------------------|
  6. | Female      2     16830 |
  7. | Female      3     13250 |
  8. | Female      4         0 |
     +-------------------------+

Pour revenir au tableau d'origine, on utilisera restore :

restore
list sex age4 income in 1/5
restore
list sex age4 income in 1/5

     +------------------------+
     |    sex   age4   income |
     |------------------------|
  1. |   Male      4        . |
  2. | Female      4        . |
  3. |   Male      3        0 |
  4. | Female      3    19955 |
  5. | Female      3        . |
     +------------------------+

La commande contract permet de construire un tableau de données agrégées selon le même procédé mais en travaillant avec des effectifs ou des fréquences.

Fusion de sources de données

Mode de représentation rectangulaire

Tableaux de description avancés

Les commandes tabulate et summarize

Comme discuté précédemment, le préfixe by permet de répéter une même opération selon les valeurs prises par une ou plusieurs variables, de sorte que l'instruction suivante permet de construire très rapidement des résumés descriptifs : (c'est même en réalité la manière la plus rapide de calculer des statistiques simples)

bysort sex: summarize income
bysort sex: summarize income

-------------------------------------------------------------------------------
-> sex = Male

    Variable |       Obs        Mean    Std. Dev.       Min        Max
-------------+--------------------------------------------------------
      income |      2299    28448.26     48010.2          0     897756

-------------------------------------------------------------------------------
-> sex = Female

    Variable |       Obs        Mean    Std. Dev.       Min        Max
-------------+--------------------------------------------------------
      income |      2435     13454.2    21349.77          0     612757
graph twoway histogram lincome, by(sex) bfcolor(gs3) blcolor(none)
graph export "fig-01-histogram-lincome-sex.eps", replace

fig-01-histogram-lincome-sex.png

Figure 2 : Distribution du log du revenu annuel (euros) selon le sexe et la classe socio-économique

Cependant, le format de sortie ne se prête pas vraiment à une mise en forme avancée dans un rapport. On préférera donc pour l'exportation utiliser tabulate avec l'option summarize :

tabulate egp3, summarize(income)
tabulate egp3, summarize(income)

  RECODE of |
egp (Social |     Summary of Individual Labor
      Class |              Earnings
     (EGP)) |        Mean   Std. Dev.       Freq.
------------+------------------------------------
  Service c |   42975.732   59423.269        1090
  Non-manua |    26018.07   29292.522         876
    Manuals |   21239.347   14760.285        1110
------------+------------------------------------
      Total |   30302.683   40805.411        3076

Un diagramme en points [3], qui reste préférable à un diagramme en barres, pour le même indicateur de tendance centrale que ci-dessus peut être construit à l'aide de ces instructions :4

graph dot lincome, over(sex) over(egp3) ylabel(0(2)12) marker(1, ms(O)) ytitle("Log income")
graph export "fig-01-bar-lincome-sex.eps", replace

fig-01-bar-lincome-sex.png

Figure 3 : Distribution du log du revenu annuel (euros) selon le sexe et la classe socio-économique

La commande tabstat

La commande tabstat permet au contraire de spécifier la liste des statistiques d'intérêt via l'option stats. La variable de stratification est indiquée dans l'option by (il ne peut y en avoir qu'une seule). Pour reproduire le résumé en 5 points de Tukey disponible sous R, on peut formuler la commande de la manière suivante :

tabstat lincome, by(sex) stats(min q max)
tabstat lincome, by(sex) stats(min q max)

Summary for variables: lincome
     by categories of: sex (Gender)

             sex |       min       p25       p50       p75       max
-----------------+--------------------------------------------------
            Male |  3.828641  9.719625  10.34229  10.73068  13.70765
          Female |   5.09375  8.738494  9.701647  10.22274  13.32572
-----------------+--------------------------------------------------
           Total |  3.828641  9.214333  10.03631  10.51678  13.70765
--------------------------------------------------------------------

Le symbole q est équivalent à utiliser p25 p50 p75 pour reporter les trois quartiles.

En guise de représentation graphique, il existe les diagrammes en forme de boîtes à moustaches que l'on peut conditionner sur une variable de classification comme dans l'exemple suivant :

graph box lincome, over(sex)
graph export "fig-01-box-lincome-sex.eps", replace

fig-01-box-lincome-sex.png

Figure 4 : Distribution du log du revenu annuel (euros) selon le sexe

La commande table

La commande table est beaucoup plus souple et elle permet non seulement de choisir les statistiques d'intérêt mais également d'utiliser jusqu'à quatre variables de classification. Les statistiques d'intérêt sont indiquées dans l'option content. En l'absence de contenu à résumer, table se comporte comme tabulate twoway.

table egp3 sex, column
table egp3 sex, column

------------------------------------------
RECODE of egp     |
(Social Class     |         Gender        
(EGP))            |   Male  Female   Total
------------------+-----------------------
Service class 1/2 |    569     524   1,093
      Non-manuals |    290     592     882
          Manuals |    717     396   1,113
               .a |      1       2       3
               .b |    163     390     553
------------------------------------------

Attention, contrairement à tabstat, dans le cas où l'on spécifie l'option content le symbole q ne se substitue pas à p25 p50 p75. Concernant les critères de classification, on distingue les variables définissant les lignes et les colonnes, ainsi qu'une variable "super-colonne" en troisième position, indiquées juste avant le séparateur d'options, et une variable "super-ligne" indiquée dans une option by. Qui plus est, la commande table est "byable", ce qui signifie que l'on peut inclure jusqu'à cinq variables de stratification. Voici un exemple de tableau croisant les niveaux de deux variables catégorielles pour chacun desquels on calcule la médiane du revenu. Le formatage des résultats numériques, ici arrondi à l'entier le plus proche, se fait directement via l'option format :

table egp3 sex if !missing(egp3), content(p50 lincome) format(%5.0f)
table egp3 sex if !missing(egp3), content(p50 lincome) format(%5.0f)

----------------------------------
RECODE of egp     |
(Social Class     |     Gender    
(EGP))            |   Male  Female
------------------+---------------
Service class 1/2 |     11      10
      Non-manuals |     10      10
          Manuals |     10       9
----------------------------------

Analyses pondérées

Commandes additionnelles

Exportation des tableaux

Références

[1] N. Cox, “A brief history of Stata on its 20th anniversary,” The Stata Journal, vol. 5, no. 1, pp. 2--18, 2005.
[2] U. Kohler and F. Kreuter, Data Analysis Using Stata. Stata Press, 3 ed., 2012.
[3] W. S. Cleveland, The Elements of Graphing Data. Monterey, CA: Wadsworth, 1985.

Notes de bas de page:

1

Il existe également d'anciens utilitaires, comme use13, permettant de lire des fichiers version 13 sous Stata 10.

2

Le fait que le type byte ne s'étende pas jusqu'à +127 vient des codes de valeurs manquante simple (. = 101) et étendu (.a = 102 à .z = 127).

4

Par défaut, l'échelle pour ce type de graphique inclut le 0, voir le chapitre sur les graphiques.

Generated by Emacs 26.3 (Org mode 9.3.1) on 2022-05-13 ven. 18:01 (chl@aliquote.org)