6  Manipulations des bases de données

Programme du chapitre

Commandes et expressions introduites

SECTION COMMANDES
Fusion append - merge - frlink - ffrval
Transposition reshape long reshape wide
Allongement expand
Base d’indicateurs collapse contract

6.1 Fusion de bases

  • Deux types de fusions:
    • La fusion verticale non controlée - empilement - (append)
    • la fusion horizontale contrôlée - appariement - (merge).

6.1.1 Append

  • Consiste simplement à ajouter des observations entre plusieurs bases, avec ou non un même jeu de variables.

On va générer les deux bases de données avec la commande input (non traité dans cette formation: help input).

clear 
input str6 id v1 v2
  "A" 8 2 
  "B" 1 2 
  "C" 2 4
end

list

save base1, replace

     +--------------+
     | id   v1   v2 |
     |--------------|
  1. |  A    8    2 |
  2. |  B    1    2 |
  3. |  C    2    4 |
     +--------------+
file base1.dta saved
clear 
input str20 id v1 v2 v3
  "D" 2 5 10
  "E" 12 1 8 
end
list

save base2, replace

     +-------------------+
     | id   v1   v2   v3 |
     |-------------------|
  1. |  D    2    5   10 |
  2. |  E   12    1    8 |
     +-------------------+
file base2.dta saved

La syntaxe de la commande append consiste à ajouter une ou plusieurs bases à la base active avec l’argument using.

append using base1
sort id
list

     +-------------------+
     | id   v1   v2   v3 |
     |-------------------|
  1. |  A    8    2    . |
  2. |  B    1    2    . |
  3. |  C    2    4    . |
  4. |  D    2    5   10 |
  5. |  E   12    1    8 |
     +-------------------+

On peut sélectionner les variables de la base qui sera empilée à la base active avec l’option keep.
Dans l’exemple, si la base active est base1, on peut ne pas vouloir ajouter la variable v3 seulement renseignée pour les observations de base2.

use base1, clear
append using base2, keep(id v1 v2)
list 
(variable id was str6, now str20 to accommodate using data's values)

     +--------------+
     | id   v1   v2 |
     |--------------|
  1. |  A    8    2 |
  2. |  B    1    2 |
  3. |  C    2    4 |
  4. |  D    2    5 |
  5. |  E   12    1 |
     +--------------+

Si les informations précédentes étaient ventilées dans trois bases, une par variable v, et avec le même niveau d’observation (A,B,C,D,E dans les 3 bases), l’utilisation de append conduirait à une structure empilée non souhaitable avec une réplication des id.

Pour obtenir la base finale proprement appariée, il convient de faire une fusion horizontale contrôlée par une une clé d’identification.

6.1.2 Merge

Stata demande que les bases soient soit triées (sort) sur la clé d’appariement en amont de l’opération. Sinon un message d’erreur sera renvoyé.

  • La base active (ouverte) est appelée base master
  • La base qui sera appariée à la base ouverte est appelée base using 1

Syntaxe minimale 1 avec préfixes:

merge [1:1] [1:m] [m:1] id_variables(s) using nom_base
  • Ici on peut apparier plus de deux bases.
  • On dispose d’une sécurité si les niveaux d’identification sont différents.

6.1.2.1 Même niveau d’identification

Partons des informations suivantes: - Base1 comprend la variable d’identification id (observations A,B,C) et de deux variables numériques v1 et v3 - Base2 comprend la même variable d’identification id (observations B,C,D) et de la variable numérique v3

Le niveau d’identification est identique dans les deux bases. Il s’agit donc d’un merge 1:1 [One to One]

On va de nouveau générer les bases avec input.

clear 
input str1 id v1 v2 
"A" 8 2 
"B" 1 2
"C" 2 4 
end
list

sort id
save base1, replace

     +--------------+
     | id   v1   v2 |
     |--------------|
  1. |  A    8    2 |
  2. |  B    1    2 |
  3. |  C    2    4 |
     +--------------+
file base1.dta saved

Rappel: bien faire le sort sur la base using

clear
input str1 id v3 
"B" 10 
"C" 8
"D" 10 
end
list

sort id
save base2, replace 

     +---------+
     | id   v3 |
     |---------|
  1. |  B   10 |
  2. |  C    8 |
  3. |  D   10 |
     +---------+
file base2.dta saved
merge 1:1 id using base1

    Result                      Number of obs
    -----------------------------------------
    Not matched                             2
        from master                         1  (_merge==1)
        from using                          1  (_merge==2)

    Matched                                 2  (_merge==3)
    -----------------------------------------
  • L’output affiche le résultat de l’appariement à l’aide d’un t ltrer si nécessaire les observations selon le résultat de l’apariement. Contrairement à d’autres applications, cette opération n’est pas effectuée en amont avec des fonctions où des options spécifiques. Par exemple avec R: left_join, right_join, inner_join. _merge = 1 : observations qui se trouvent seulement dans la base active (master) _merge = 2 : observations qui se trouvent seulement dans la base using (appariée) _merge = 3 : observations communes aux bases master et using.

  • Les variables de la base master/active sont positionnées en tête de colonnes.

sort id
list

     +-------------------------------------+
     | id   v3   v1   v2            _merge |
     |-------------------------------------|
  1. |  A    .    8    2    Using only (2) |
  2. |  B   10    1    2       Matched (3) |
  3. |  C    8    2    4       Matched (3) |
  4. |  D   10    .    .   Master only (1) |
     +-------------------------------------+

Si on souhaite seulement conserver les observations communes aux deux bases (_merge=3):

keep if _merge==3
list
(2 observations deleted)

     +---------------------------------+
     | id   v3   v1   v2        _merge |
     |---------------------------------|
  1. |  B   10    1    2   Matched (3) |
  2. |  C    8    2    4   Matched (3) |
     +---------------------------------+
Variable _merge et appariements successifs

Pensez à supprimer la variable *_merge* si plusieurs opérations d’appariement sont effectués. La commande ne prévoit pas d’écraser la variable de la fusion précédente.

Situation avec plus d’une base à apparier

On ne peux pas utiliser la syntaxe avec préfixe (ici merge 1:1).

On va ajouter une nouvelle base qui sera appariée avec les deux premières, qui seront donc les deux bases de type using.

clear
input str1 id str3  v4 
"A" "Non" 
"B" "Oui" 
"C" "Oui" 
end

list 

sort id

     +----------+
     | id    v4 |
     |----------|
  1. |  A   Non |
  2. |  B   Oui |
  3. |  C   Oui |
     +----------+
merge id using base1 base2

order id v1 v2 v3 v4 _merge1 _merge2 _merge 

list
(you are using old merge syntax; see [D] merge for new syntax)

     +------------------------------------------------------+
     | id   v1   v2   v3    v4   _merge1   _merge2   _merge |
     |------------------------------------------------------|
  1. |  A    8    2    .   Non         1         0        3 |
  2. |  B    1    2   10   Oui         1         1        3 |
  3. |  C    2    4    8   Oui         1         1        3 |
  4. |  D    .    .   10               0         1        2 |
     +------------------------------------------------------+

On obtient maintenant 3 variables _merge:

  • *_merge1. Donne le résultat de l’appariement entre la nouvelle base et base1*: 0 si seulement dans une seule des deux bases (D), 1 si dans les deux bases (A,B,C).
  • *_merge2. Donne le résultat de l’appariement entre la nouvelle base et base2*: 0 si seulement dans une seule des deux bases (A,D), 1 si dans les deux bases (B,C).
  • *_merge*. Résume rapidement le matching entre les bases: on retrouve au moins une fois les observations (A,B,C) dans l’un des deux appariement (_merge=3), on trouve une observation (D) qui ne se trouve que dans une base using (_D_merge=2).

Si l’on souhaite conserver les observations communes aux trois bases, on peut sommer les valeurs de *_merge1* et *_merge2* et conserver les observations dont la valeurs de cette somme est égale au nombre d’appariements; ou faire une sélection des observations avec un filtre conditionnel, ici:

keep if _merge1==1 & _merge2==1
list

drop _merge*
(2 observations deleted)

     +------------------------------------------------------+
     | id   v1   v2   v3    v4   _merge1   _merge2   _merge |
     |------------------------------------------------------|
  1. |  B    1    2   10   Oui         1         1        3 |
  2. |  C    2    4    8   Oui         1         1        3 |
     +------------------------------------------------------+
Commande join du package ftools

[A tester]

  • Documentation.
  • Permet de gagner 70% de durée d’exécution lorsque la volumétrie dépasse 100000 observations
  • Gère en amont le tri des bases appariée.

6.1.2.2 Niveaux d’identification différents

Un merge de type 1:1 n’est pas possible. Dans l’exemple qui suit la base period_act liste pour deux personnes le statut d’activité observé pour plusieurs périodes soit des observations multiples pour chaque individus, et la base sexe donne une caractéristique unique pour chaque individu. Selon le statut des bases appariée (master ou using), l’appariement est de type 1:m ou m:1.

  • Si la base active est à observations multiples sur la clé d’identification: m:1
  • Si la base active est à observations uniques sur la clé d’identification: 1:m

On va de nouveau générer les données avec input

clear 
input id périodes str8 Activité
1 1 "Emploi"
1 2 "Emploi"
1 3 "Chômage"
2 1 "Chômage" 
2 2 "Chômage"
2 3 "Emploi"
2 4 "Chômage" 
end 
list 
sort id 
save "period_act", replace

     +--------------------------+
     | id   périodes   Activité |
     |--------------------------|
  1. |  1          1     Emploi |
  2. |  1          2     Emploi |
  3. |  1          3    Chômage |
  4. |  2          1    Chômage |
  5. |  2          2    Chômage |
     |--------------------------|
  6. |  2          3     Emploi |
  7. |  2          4    Chômage |
     +--------------------------+
file period_act.dta saved
clear
input id str6 sexe 
1 "Homme"  
2 "Femme"  
end 
list
sort id 
save "sexe", replace

     +------------+
     | id    sexe |
     |------------|
  1. |  1   Homme |
  2. |  2   Femme |
     +------------+
file sexe.dta saved

Si on effectuait un merge 1:1, Stata renverrait le message d’erreur suivant:

merge 1:1 id using activités

variable id does not uniquely identify observations in the using data
r(459);

Ici la base active est la base sex. Le prefixe qui doit être utilisé est donc 1:m 2

merge 1:m id using period_act
sort id période
list 

    Result                      Number of obs
    -----------------------------------------
    Not matched                             0
    Matched                                 7  (_merge==3)
    -----------------------------------------

     +------------------------------------------------+
     | id    sexe   périodes   Activité        _merge |
     |------------------------------------------------|
  1. |  1   Homme          1     Emploi   Matched (3) |
  2. |  1   Homme          2     Emploi   Matched (3) |
  3. |  1   Homme          3    Chômage   Matched (3) |
  4. |  2   Femme          1    Chômage   Matched (3) |
  5. |  2   Femme          2    Chômage   Matched (3) |
     |------------------------------------------------|
  6. |  2   Femme          3     Emploi   Matched (3) |
  7. |  2   Femme          4    Chômage   Matched (3) |
     +------------------------------------------------+
Astuce

Le tri de la base est régulièrement modifié après ce type d’appariement. Penser donc à retrier les données proprement, surtout quand il s’agit comme ici d’informations biographiques (sort id périodes)

De nouveau les préfixes sont optionnels, et permettent seulement de contrôler l’appariement. On peut sans soucis fusionner des informations contextuelles avec des informations multiples avec seulement merge. Un avertissement se renvoyé à l’exécution de la commande

use sexe, clear
merge id using period_act
sort id périodes
list
(you are using old merge syntax; see [D] merge for new syntax)
variable id does not uniquely identify observations in period_act.dta

     +-------------------------------------------+
     | id    sexe   périodes   Activité   _merge |
     |-------------------------------------------|
  1. |  1   Homme          1     Emploi        3 |
  2. |  1   Homme          2     Emploi        3 |
  3. |  1   Homme          3    Chômage        3 |
  4. |  2   Femme          1    Chômage        3 |
  5. |  2   Femme          2    Chômage        3 |
     |-------------------------------------------|
  6. |  2   Femme          3     Emploi        3 |
  7. |  2   Femme          4    Chômage        3 |
     +-------------------------------------------+

6.1.2.3 Appariement avec des frames

L’utilisation des frames présentent plusieurs avantages:

  • Il n’est pas nécessaire de trier les bases concernées par l’appariement.
  • On peut sélectionner avec la commande frget la ou les variables qui seront récupérées dans la base master. On apparie donc pas des bases en tant que telles, on récupère de l’information de frames liées.
  • Mieux encore, on peut réaliser des opérations entre observations individuelles et observations contextuelles sans passer par un appariement. Avec les frames, l’opération d’appariement doit être plutôt compris comme un système de liaison entre bases, le transfert d’informations n’étant qu’une opération optionnelle.

Au niveau des désavantages:

  • Si on ne travaille pas exclusivement sous frames, les bases devront être transformées en frame (voir exemple)
  • Absence de variable de type *_merge* qui permet de contrôler le résultat de l’appariement.
  • les prefixes sont uniquement 1:1 et m:1. Cela signifie dans le second cas que la frame active lors de l’opération de liaison doit toujours être celle dont la clé d’identification est de type multiple (niveau individuel).
  • Peut-être le plus embêtant est l’absence d’appariement pour les informations correspondant à **_merge=2** (Informations seulement présentes dans la base using). Le dernier exemple illustre ce point.

On reprend l’exemple précédent, en transformant dans un premier temps les deux bases en frames.

frame reset

frame create period_act
frame period_act: use period_act
frame create sexe
frame sexe: use sexe

frame dir
  default     0 x 0
  period_act  7 x 3; period_act.dta
  sexe        2 x 2; sexe.dta

On doit se positionner sur la frame period_act (type m)

frame change period_act

Pour lier les frames on utilise la commande frlink.

Syntaxe

frlink 1:1/m:1 id_variable(s), frame(nom_frame) gen(variable_lien)

Ici on fait un appariement de type m:1, la clé d’identification est de nouveau id. On lie la frame active à la frame sexe et la variable de liaison (ici un alias de la variable id) est appelée link.

frlink m:1 id, frame(sexe) gen(link)
(all observations in frame period_act matched)

Pour importer la variable sexe dans la frame period_act, on utilise la commande frget, en précisant la ou les variable que l’on souhaite récupérer, ainsi que la variable de liaison (une même frame peut avoir plusieurs liaisons. Voir plus loin).

frget sexe , from(link)

frame period_act: order link, last
list
(1 variable copied from linked frame)

     +-----------------------------------------+
     | id   périodes   Activité    sexe   link |
     |-----------------------------------------|
  1. |  1          1     Emploi   Homme      1 |
  2. |  1          2     Emploi   Homme      1 |
  3. |  1          3    Chômage   Homme      1 |
  4. |  2          1    Chômage   Femme      2 |
  5. |  2          2    Chômage   Femme      2 |
     |-----------------------------------------|
  6. |  2          3     Emploi   Femme      2 |
  7. |  2          4    Chômage   Femme      2 |
     +-----------------------------------------+
Liaison des frames en présence d’information incomplète

La liaison de frames peut être problématique en présence d’informations incomplètes. Pour faire simple, la liaison des frames permet de faire des appariements de type **_merge=1** et **_merge=3** (présence dans la master seulement ou présence dans la master et la using) mais ne permet pas de récupérer des informations présentes seulement dans la base using).

Pour illustrer cela on va générer une nouvelle frame, de type individus-périodes, avec une variable additionnelle tvc.

  • Pour id= 1, on a pas d’information dans la frame period_act pour période=4.
  • Pour id= 2, on a pas d’information dans la frame tvc pour les périodes 3 et 4.

Création de la nouvelle frame (voir le .do, la compilation pour générer ce support complexifie un peu l’opération):

frame create tvc
frame change tvc


clear
input id périodes tvc 
1 1 0   
1 2 0   
1 3 1  
1 4 0  
2 1 1  
2 2 0 
end

list 

save tvc, replace
frame tvc: use tvc

     +---------------------+
     | id   périodes   tvc |
     |---------------------|
  1. |  1          1     0 |
  2. |  1          2     0 |
  3. |  1          3     1 |
  4. |  1          4     0 |
  5. |  2          1     1 |
     |---------------------|
  6. |  2          2     0 |
     +---------------------+
file tvc.dta saved

Liaison des frames et récupération de la variable tvc dans period_act

frame change period_act
frlink 1:1 id périodes, frame(tvc) gen(link2)

frget tvc, from(link2)

list
(2 observations in frame period_act unmatched)
(2 missing values generated)
(1 variable copied from linked frame)

     +-------------------------------------------------------+
     | id   périodes   Activité    sexe   link   link2   tvc |
     |-------------------------------------------------------|
  1. |  1          1     Emploi   Homme      1       1     0 |
  2. |  1          2     Emploi   Homme      1       2     0 |
  3. |  1          3    Chômage   Homme      1       3     1 |
  4. |  2          1    Chômage   Femme      2       5     1 |
  5. |  2          2    Chômage   Femme      2       6     0 |
     |-------------------------------------------------------|
  6. |  2          3     Emploi   Femme      2       .     . |
  7. |  2          4    Chômage   Femme      2       .     . |
     +-------------------------------------------------------+

On voit bien que la valeur de tvc pour id=1 et périodes=4 n’a pas été importée (**_merge=2** dans un appariement classique). En revanche, pour id=2, l’incomplétude de l’information dans la base tvc pour les périodes 3 et 4 est bien visible.

Avec un merge classique (on suppose que period_act n’a pas été appariée à sexe):

use tvc, clear
sort id périodes
save tvc, replace
use period_act, clear
sort id périodes
merge 1:1 id périodes using tvc
sort id périodes
list
file tvc.dta saved

    Result                      Number of obs
    -----------------------------------------
    Not matched                             3
        from master                         2  (_merge==1)
        from using                          1  (_merge==2)

    Matched                                 5  (_merge==3)
    -----------------------------------------

     +--------------------------------------------------+
     | id   périodes   Activité   tvc            _merge |
     |--------------------------------------------------|
  1. |  1          1     Emploi     0       Matched (3) |
  2. |  1          2     Emploi     0       Matched (3) |
  3. |  1          3    Chômage     1       Matched (3) |
  4. |  1          4                0    Using only (2) |
  5. |  2          1    Chômage     1       Matched (3) |
     |--------------------------------------------------|
  6. |  2          2    Chômage     0       Matched (3) |
  7. |  2          3     Emploi     .   Master only (1) |
  8. |  2          4    Chômage     .   Master only (1) |
     +--------------------------------------------------+

On a bien ici l’ajout de l’information correspondant à _merge=2 (Using only)

Un des intérêts des frames, est de faire des opérations entre informations individuelles et contextuelles sans passer par un appariement en amont. Par l’exemple, nous allons voir comment un appariement peut être évité lorsqu’on travaille sur ce genre d’information.

On va générer 2 bases, une individuelle et une contextuelle. La première contient un identifiant individuel (id), le nom de la zône d’appartenance (zone) et les valeurs observées d’une variable x. La seconde contient le nom des zônes et la valeur moyenne de la variable x dans ces espaces.

Création des frames:

frame reset 

clear 
input id str6 zone x
1 "zoneA" 10
2 "zoneA" 15
3 "zoneB" 9
4 "zoneB" 12
5 "zoneB" 10
6 "zoneB" 15
7 "zoneC" 6
8 "zoneC" 13
9 "zoneC" 16
end
list
save indiv, replace

     +-----------------+
     | id    zone    x |
     |-----------------|
  1. |  1   zoneA   10 |
  2. |  2   zoneA   15 |
  3. |  3   zoneB    9 |
  4. |  4   zoneB   12 |
  5. |  5   zoneB   10 |
     |-----------------|
  6. |  6   zoneB   15 |
  7. |  7   zoneC    6 |
  8. |  8   zoneC   13 |
  9. |  9   zoneC   16 |
     +-----------------+
file indiv.dta saved
clear
input str6 zone xmean
"zoneA" 11
"zoneB" 12
"zoneC" 13
end
list
save zone, replace

     +---------------+
     |  zone   xmean |
     |---------------|
  1. | zoneA      11 |
  2. | zoneB      12 |
  3. | zoneC      13 |
     +---------------+
file zone.dta saved
frame create indiv
frame indiv: use indiv
frame create zone
frame zone: use zone

Après avoir lié les deux frames (m:1), on va calculer directement la différence entre la valeur observée pour chaque individu de la variable x et sa moyenne par zone (xmean). On utilise la fonction frval comme argument de la commande generate.

frame change indiv
frlink m:1 zone, frame(zone) gen(link)
list
(all observations in frame indiv matched)

     +------------------------+
     | id    zone    x   link |
     |------------------------|
  1. |  1   zoneA   10      1 |
  2. |  2   zoneA   15      1 |
  3. |  3   zoneB    9      2 |
  4. |  4   zoneB   12      2 |
  5. |  5   zoneB   10      2 |
     |------------------------|
  6. |  6   zoneB   15      2 |
  7. |  7   zoneC    6      3 |
  8. |  8   zoneC   13      3 |
  9. |  9   zoneC   16      3 |
     +------------------------+
gen = var1 - frval(nom_link, var2)
gen diffx = x - frval(link, xmean)
list

     +--------------------------------+
     | id    zone    x   link   diffx |
     |--------------------------------|
  1. |  1   zoneA   10      1      -1 |
  2. |  2   zoneA   15      1       4 |
  3. |  3   zoneB    9      2      -3 |
  4. |  4   zoneB   12      2       0 |
  5. |  5   zoneB   10      2      -2 |
     |--------------------------------|
  6. |  6   zoneB   15      2       3 |
  7. |  7   zoneC    6      3      -7 |
  8. |  8   zoneC   13      3       0 |
  9. |  9   zoneC   16      3       3 |
     +--------------------------------+

6.2 Transposition d’une base

6.2.1 Syntaxe et exemples

Cette opération permet d’allonger ou d’élargir une base, généralement sur des variables occurencées. Ces occurences peuvent être des séquences ou points chronologiques (valeur d’une variable sur plusieurs années), ou des individus composant un ménage.

Avec Stata, ces opérations de transpositions sont effectuées avec la commande reshape

  • De large à long: reshape long
  • De long à large: reshape wide

A noter que la seconde opération est plus gourmande en durée d’exécution. De nouveau si la volumétrie de la base est élevée, disons plus d’une million d’observations, on peut se reporter sur la commande greshape du package gtools. On peut trouver un benchmark sur des données simulées [liens].

Au niveau de la syntaxe:

  • Il est nécessaire d’avoir une variable d’identification pour réaliser l’opération: cela peut être un identifiant individuel3 si la variations des observations est relatives à des périodes, ou un identifiant ménage si la source de la variation sont les personnes le composant. Ce peut bien évidemment fonctionner avec des zônes géographiques: régions-départements, régions-communes, départements-communes.
    Cette variable d’identification doit être renseignée en option: i(var_id)
  • On indique dans l’expression principale le racine des variables occurencées: si la base est en format large avec les variables revenu1980, revenu1981,….,revenu1990, la racine sera donc revenu. Les occurences peuvent être des lettres (A,B,D…) ou des mots (un,deux,trois…).
  • Information sur les occurences: selon le type de transposition on doit indiquer en option la variable qui contiendra ou qui contient les occurences. Cette option est j(nom_variable)
    • si la base est en format large et qu’on souhaite l’allonger, on indique obligatoirement la variable qui sera créée et qui reportera les valeurs des occurences.
    • si la base est en format long et qu’on souhaite l’élargir, on indique obligatoirement la variable qui contient les occurences.
  • Selon la transposition, le nom de commande est suivi de long ou wide

Syntaxe de large à long:

reshape long racines_variables_occurencées, i(var_id) j(var_occurences)

Syntaxe de long à large:

reshape wide racines_variables_occurencées, i(var_id) j(var_occurences)

Exemple

On part de la base suivante

clear 
input id x1 x2 x3 x4
1 10 20 12 25
2 12 22 15 30
3 15 25 33 30
4 21 17 22 27
5 13 15 14 18
end

list

     +------------------------+
     | id   x1   x2   x3   x4 |
     |------------------------|
  1. |  1   10   20   12   25 |
  2. |  2   12   22   15   30 |
  3. |  3   15   25   33   30 |
  4. |  4   21   17   22   27 |
  5. |  5   13   15   14   18 |
     +------------------------+

On allonger la base sur les variables x1 à x4. La racine est donc x. Pour le choix de la nouvelle variable qui aura pour chaque id les valeurs 1 à 4, on ne peux pas choisir x, qui sera créée automatiquement. Selon le type d’information contenu dans l’occurence, on peut utiliser un nom indiquant une période, un membre de ménage ou une zône géographique. Ici on ca suposer que les occurences sont de nature temporelle, et on choisira t comme nom à la variable de l’option j().

reshape long x , i(id) j(t)
(j = 1 2 3 4)

Data                               Wide   ->   Long
-----------------------------------------------------------------------------
Number of observations                5   ->   20          
Number of variables                   5   ->   3           
j variable (4 values)                     ->   t
xij variables:
                           x1 x2 ... x4   ->   x
-----------------------------------------------------------------------------

On remarque que Stata donne quelques informations sur le résultats de l’opération: variables créées, nombre d’observations dans le nouveau format

list

     +-------------+
     | id   t    x |
     |-------------|
  1. |  1   1   10 |
  2. |  1   2   20 |
  3. |  1   3   12 |
  4. |  1   4   25 |
  5. |  2   1   12 |
     |-------------|
  6. |  2   2   22 |
  7. |  2   3   15 |
  8. |  2   4   30 |
  9. |  3   1   15 |
 10. |  3   2   25 |
     |-------------|
 11. |  3   3   33 |
 12. |  3   4   30 |
 13. |  4   1   21 |
 14. |  4   2   17 |
 15. |  4   3   22 |
     |-------------|
 16. |  4   4   27 |
 17. |  5   1   13 |
 18. |  5   2   15 |
 19. |  5   3   14 |
 20. |  5   4   18 |
     +-------------+

On peut repasser au format de départ (large) avec reshape wide

reshape wide x , i(id) j(t)
(j = 1 2 3 4)

Data                               Long   ->   Wide
-----------------------------------------------------------------------------
Number of observations               20   ->   5           
Number of variables                   3   ->   5           
j variable (4 values)                 t   ->   (dropped)
xij variables:
                                      x   ->   x1 x2 ... x4
-----------------------------------------------------------------------------
list

     +------------------------+
     | id   x1   x2   x3   x4 |
     |------------------------|
  1. |  1   10   20   12   25 |
  2. |  2   12   22   15   30 |
  3. |  3   15   25   33   30 |
  4. |  4   21   17   22   27 |
  5. |  5   13   15   14   18 |
     +------------------------+

Bien évidemment les variable fixes ne doivent pas être renseigné dans la commande, les valeurs sont conservées

clear 
input id x1 x2 x3 x4 fixe
1 10 20 12 25 0
2 12 22 15 30 1
3 15 25 33 30 0
4 21 17 22 27 1
5 13 15 14 18 0

end
list

reshape long x, i(id) j(t)
list

     +-------------------------------+
     | id   x1   x2   x3   x4   fixe |
     |-------------------------------|
  1. |  1   10   20   12   25      0 |
  2. |  2   12   22   15   30      1 |
  3. |  3   15   25   33   30      0 |
  4. |  4   21   17   22   27      1 |
  5. |  5   13   15   14   18      0 |
     +-------------------------------+
(j = 1 2 3 4)

Data                               Wide   ->   Long
-----------------------------------------------------------------------------
Number of observations                5   ->   20          
Number of variables                   6   ->   4           
j variable (4 values)                     ->   t
xij variables:
                           x1 x2 ... x4   ->   x
-----------------------------------------------------------------------------

     +--------------------+
     | id   t    x   fixe |
     |--------------------|
  1. |  1   1   10      0 |
  2. |  1   2   20      0 |
  3. |  1   3   12      0 |
  4. |  1   4   25      0 |
  5. |  2   1   12      1 |
     |--------------------|
  6. |  2   2   22      1 |
  7. |  2   3   15      1 |
  8. |  2   4   30      1 |
  9. |  3   1   15      0 |
 10. |  3   2   25      0 |
     |--------------------|
 11. |  3   3   33      0 |
 12. |  3   4   30      0 |
 13. |  4   1   21      1 |
 14. |  4   2   17      1 |
 15. |  4   3   22      1 |
     |--------------------|
 16. |  4   4   27      1 |
 17. |  5   1   13      0 |
 18. |  5   2   15      0 |
 19. |  5   3   14      0 |
 20. |  5   4   18      0 |
     +--------------------+

6.2.2 Mise en garde

Complétude du nom de la racine

Bien penser à mettre l’intégralité de la racine, partie fixe de la variable occurencée:

clear 
input id x_1 x_2 x_3 x_4
1 10 20 12 25
2 12 22 15 30
3 15 25 33 30
4 21 17 22 27
5 13 15 14 18
end

list

     +----------------------------+
     | id   x_1   x_2   x_3   x_4 |
     |----------------------------|
  1. |  1    10    20    12    25 |
  2. |  2    12    22    15    30 |
  3. |  3    15    25    33    30 |
  4. |  4    21    17    22    27 |
  5. |  5    13    15    14    18 |
     +----------------------------+
reshape long x , i(id) j(t)

renverra le message d’erreur suivant:

variable t contains all missing values
r(498);

Omission de variables occurencée

Contrairement à l’allongement, l’élargissement est plus contraignant, toutes les variables non fixes doivent être renseignées.

Si on omet des variables occurencées dans l’allongement, elle sont conservées tel quel et les valeurs sont répliquées d’une ligne à l’autre:

clear 
input id x1 x2 y1 y2 fixe
1 10 20 12 25 0
2 12 22 15 30 0
3 15 25 33 30 1
4 21 17 22 27 1
5 13 15 14 18 0
end
list

reshape long x , i(id) j(t)
list

     +-------------------------------+
     | id   x1   x2   y1   y2   fixe |
     |-------------------------------|
  1. |  1   10   20   12   25      0 |
  2. |  2   12   22   15   30      0 |
  3. |  3   15   25   33   30      1 |
  4. |  4   21   17   22   27      1 |
  5. |  5   13   15   14   18      0 |
     +-------------------------------+
(j = 1 2)

Data                               Wide   ->   Long
-----------------------------------------------------------------------------
Number of observations                5   ->   10          
Number of variables                   6   ->   6           
j variable (2 values)                     ->   t
xij variables:
                                  x1 x2   ->   x
-----------------------------------------------------------------------------

     +------------------------------+
     | id   t    x   y1   y2   fixe |
     |------------------------------|
  1. |  1   1   10   12   25      0 |
  2. |  1   2   20   12   25      0 |
  3. |  2   1   12   15   30      0 |
  4. |  2   2   22   15   30      0 |
  5. |  3   1   15   33   30      1 |
     |------------------------------|
  6. |  3   2   25   33   30      1 |
  7. |  4   1   21   22   27      1 |
  8. |  4   2   17   22   27      1 |
  9. |  5   1   13   14   18      0 |
 10. |  5   2   15   14   18      0 |
     +------------------------------+

En revanche si on part d’une base longue avec plusieurs dimensions variables

(j = 1 2)

Data                               Wide   ->   Long
-----------------------------------------------------------------------------
Number of observations                5   ->   10          
Number of variables                   6   ->   5           
j variable (2 values)                     ->   t
xij variables:
                                  x1 x2   ->   x
                                  y1 y2   ->   y
-----------------------------------------------------------------------------
list

     +-------------------------+
     | id   t    x    y   fixe |
     |-------------------------|
  1. |  1   1   10   12      0 |
  2. |  1   2   20   25      0 |
  3. |  2   1   12   15      0 |
  4. |  2   2   22   30      0 |
  5. |  3   1   15   33      1 |
     |-------------------------|
  6. |  3   2   25   30      1 |
  7. |  4   1   21   22      1 |
  8. |  4   2   17   27      1 |
  9. |  5   1   13   14      0 |
 10. |  5   2   15   18      0 |
     +-------------------------+
reshape wide x, i(id) j(t)

renverra le message d’erreur suivant:

(j = 1 2)
variable y not constant within id
Your data are currently long. You are performing a reshape wide. You typed something like

. reshape wide a b, i(id) j(t)

    There are variables other than a, b, id, t in your data. They must be constant within id because that is the only way they can fit into wide data without loss
    of information.

    The variable or variables listed above are not constant within id. Perhaps the values are in error. Type reshape error for a list of the problem observations.

    Either that, or the values vary because they should vary, in which case you must either add the variables to the list of xij variables to be reshaped, or drop them.

6.3 Allongement d’une base

Section très courte. Pariculièrement utile lorsqu’on manipule des données biographiques avec des durées, et pour faire la mise en forme nécessaire pour une analyse à durée discrète. La commande expand permet de répliquer les lignes, sur une valeur fixe qu’on indique ou sur des valeurs non constantes renseignés dans une variable.

Dans le premier cas la syntaxe est: expand valeur Dans le second cas la synataxe est: expand nom_variable

Exemple:

clear 
input id duree e
1  3 0 
2  4 1
3  2 1 
end

list

     +----------------+
     | id   duree   e |
     |----------------|
  1. |  1       3   0 |
  2. |  2       4   1 |
  3. |  3       2   1 |
     +----------------+

Allongement de la base:

expand duree
(6 observations created)

Si on veut faire une analyse à durée discrère, avec les variables de comptage (chapitre 5):

bysort id: gen t=_n
bysort id: replace e=0 if t<_N
list
(4 real changes made)

     +--------------------+
     | id   duree   e   t |
     |--------------------|
  1. |  1       3   0   1 |
  2. |  1       3   0   2 |
  3. |  1       3   0   3 |
  4. |  2       4   0   1 |
  5. |  2       4   0   2 |
     |--------------------|
  6. |  2       4   0   3 |
  7. |  2       4   1   4 |
  8. |  3       2   0   1 |
  9. |  3       2   1   2 |
     +--------------------+

Remarque: si la valeur sur laquelle est allongée la base a une valeur négative (par exemple des durées négatives), un message indique leur présence.

6.4 Créer des bases d’indicateurs

Dans ce qui suit il est fortement recommandé d’utiliser les frames (Stata 16 minimum). Pour faire ce type d’opérations deux commandes sont disponibles:

  • la plus utilisée, collapse permet de créer une base d’indicateurs dédiées aux variables quantitatives: moyenne, médiane et autes quantiles, ….
  • la moins utilisée, contract, est dédiée aux variables catégorielles (effectifs et effectif cumulés, proportions et proportions cumulées).

Pour les pondérations admises, se reporter à l’aide des commandes4.

Ecrasement de la base d’origine

Attention la base sur laquelle on travaille va être écrasée. Si ce n’est pas souhaité:

  • Utiliser les commandes preserve restore avant et après l’opération.

  • Générer une frame avec les variables qui seront transformées en indicateurs. On pourra conserver les deux bases dans la sessions, et les utiliser en parallèle.

6.4.1 collapse

Les indicateurs disponibles sont les suivants:

        mean         means (default)
        median       medians
        p1           1st percentile
        p2           2nd percentile
        ...          3rd-49th percentiles
        p50          50th percentile (same as median)
        ...          51st-97th percentiles
        p98          98th percentile
        p99          99th percentile
        sd           standard deviations
        semean       standard error of the mean (sd/sqrt(n))
        sebinomial   standard error of the mean, binomial (sqrt(p(1-p)/n))
        sepoisson    standard error of the mean, Poisson (sqrt(mean/n))
        sum          sums
        rawsum       sums, ignoring optionally specified weight except observations with a weight of zero are excluded
        count        number of nonmissing observations
        percent      percentage of nonmissing observations
        max          maximums
        min          minimums
        iqr          interquartile range
        first        first value
        last         last value
        firstnm      first nonmissing value
        lastnm       last nonmissing value
  • Par défaut c’est la moyenne qui est utilisée.
  • Les résultats peuvent être stratifiées avec une option by().

Syntaxe avec un seul indicateur

collapse [(statistique autre que moyenne) varlist [, by(varlist)] 

Dans les exemples, on utilisera preserve restore pour retrouver la base de départ.

Exemples

clear
sysuse auto

preserve 
collapse price
list
restore

preserve 
collapse price mpg, by(foreign)
list
restore

preserve 
collapse (median) price mpg, by(foreign)
list
restore

preserve 
collapse (median) price mpg if rep78!=., by(foreign rep78)
list
restore
(Note: Below code run with echo to enable preserve/restore functionality.)

. clear

. sysuse auto
(1978 automobile data)

. preserve

. collapse price

. list

     +---------+
     |   price |
     |---------|
  1. | 6,165.3 |
     +---------+

. restore

. preserve

. collapse price mpg, by(foreign)

. list

     +------------------------------+
     |  foreign     price       mpg |
     |------------------------------|
  1. | Domestic   6,072.4   19.8269 |
  2. |  Foreign   6,384.7   24.7727 |
     +------------------------------+

. restore

. preserve

. collapse (median) price mpg, by(foreign)

. list

     +---------------------------+
     |  foreign     price    mpg |
     |---------------------------|
  1. | Domestic   4,782.5     19 |
  2. |  Foreign     5,759   24.5 |
     +---------------------------+

. restore

. preserve

. collapse (median) price mpg if rep78!=., by(foreign rep78)

. list

     +----------------------------------+
     | rep78    foreign     price   mpg |
     |----------------------------------|
  1. |     1   Domestic   4,564.5    21 |
  2. |     2   Domestic     4,638    18 |
  3. |     3   Domestic     4,749    19 |
  4. |     4   Domestic     5,705    18 |
  5. |     5   Domestic   4,204.5    32 |
     |----------------------------------|
  6. |     3    Foreign     4,296    23 |
  7. |     4    Foreign     6,229    25 |
  8. |     5    Foreign     5,719    25 |
     +----------------------------------+

. restore

. 

On voit que la variable indicateur prend le nom de la variable. On ne peut donc pas générer une liste d’indicateurs sans renommer les variables.

Syntaxe avec plusieurs indicateurs

Dans l’expression principal, on doit donner un nom différent à chaque variable pour chaque indicateur…ce n’est pas très pratique, Stata aurait pu prévoir un moyen de générer par défaut des nom de variable comme mean_varname, min_varname….

Dans le cas de deux indicateurs (median, min) pour deux variable (price, mpg).

collapse [(stat1) varname11 = var1 varname21= var2  (stat2 ) varname12 = var1 varname22= var2 [, by(varlist)] 
preserve
collapse (median) pricemed = price mpgmed=mpg  (min) pricemin = price mpgmin= mpg , by(foreign)
list
restore
(Note: Below code run with echo to enable preserve/restore functionality.)

. preserve

. collapse (median) pricemed = price mpgmed=mpg (min) pricemin = price mpgmin= 
> mpg , by(foreign)

. list

     +--------------------------------------------------+
     |  foreign   pricemed   mpgmed   pricemin   mpgmin |
     |--------------------------------------------------|
  1. | Domestic    4,782.5       19      3,291       12 |
  2. |  Foreign      5,759     24.5      3,748       14 |
     +--------------------------------------------------+

. restore

. 

Remarque: pour des variables codées sous forme d’indicatrice, on peut générer des proportions ou des pourcentages facilement, ce qui rend la commande contract caduque avec deux modalités (exemple: variable foreign).

6.4.2 contract

Même principe, mais le nombre d’indicateurs est limité (effectifs ou proportion, cumulées ou non). Il n’y a pas d’option by mais on peut directement croiser les dimensions avec plusieurs variables. Je n’ai jamais utilisé cette commande en dehors de la formation, donc je n’en donnerai que deux exemples:

preserve 
contract rep78 foreign 
list
restore


preserve 
contract rep78 foreign,  percent(percentage) 
list
restore
(Note: Below code run with echo to enable preserve/restore functionality.)

. preserve

. contract rep78 foreign

. list

     +--------------------------+
     | rep78    foreign   _freq |
     |--------------------------|
  1. |     1   Domestic       2 |
  2. |     2   Domestic       8 |
  3. |     3   Domestic      27 |
  4. |     3    Foreign       3 |
  5. |     4   Domestic       9 |
     |--------------------------|
  6. |     4    Foreign       9 |
  7. |     5   Domestic       2 |
  8. |     5    Foreign       9 |
  9. |     .   Domestic       4 |
 10. |     .    Foreign       1 |
     +--------------------------+

. restore

. preserve

. contract rep78 foreign, percent(percentage)

. list

     +-------------------------------------+
     | rep78    foreign   _freq   percen~e |
     |-------------------------------------|
  1. |     1   Domestic       2       2.70 |
  2. |     2   Domestic       8      10.81 |
  3. |     3   Domestic      27      36.49 |
  4. |     3    Foreign       3       4.05 |
  5. |     4   Domestic       9      12.16 |
     |-------------------------------------|
  6. |     4    Foreign       9      12.16 |
  7. |     5   Domestic       2       2.70 |
  8. |     5    Foreign       9      12.16 |
  9. |     .   Domestic       4       5.41 |
 10. |     .    Foreign       1       1.35 |
     +-------------------------------------+

. restore

. 

  1. Cela peut être plusieurs bases.↩︎

  2. m:1 renvoit un message d’erreur. Dans ce sens, la base active doit être period_act et la base using sexe.↩︎

  3. Cela peut être une zône géographique↩︎

  4. La question des pondérations sera traitée dans le chapitre suivant↩︎