Posts Tagged ‘merge’

Mettre des données côte-à-côte pour votre reporting
mai 24, 2010Lorsque vous devez présenter vos données (faire du reporting), vous pouvez vous trouver dans la situation suivante : mettre côte-à-côte des données qui n’ont rien à voir entre elles. La situation peut se résoudre très rapidement avec un merge sans instruction BY. Mais que faire dans le cas où vous devez quand même grouper vos données par une clé (exemple l’identifiant du client) mais dans chaque source plus d’une observation par clé ? C’est ce que je vous propose de découvrir dans cet article.
1. Les données pour l’exemple
Deborah a deux lignes d’observation et Patrick aussi.
data demography;
length cl_name $10 criteria $10 ;
input cl_name $ criteria $ crit_value ;
datalines;
deborah age 15
deborah height 1.66
patrick age 14
patrick height 1.75
;
run;
Deborah a acheté 4 articles (DVD, téléphone portable, une radio et des écouteurs (4 lignes d’observations pour Deborah) tandis que Patrick a acheté deux articles.
data sell;
length cl_name $10 achat $10;
input cl_name $ achat $;
datalines;
deborah dvd
deborah mobile
deborah radio
deborah headset
patrick mobile
patrick tv
;
run;
2. Le résultat sans instruction BY
data mix_demo_sell;
merge demography
sell;
by cl_name;
run;
Vous vous retrouvez avec un merge MANY-to-MANY qui ne résous par votre problème. Pensez toujours à vérifer votre log après un MERGE. Ce type de note est souvent signe d’une erreur de raisonnement dans votre programme.
proc print data=mix_demo_sell;
run;
On observe ici un RETAIN implicite propre au merge.
3. Ajouter un compteur pour chaque client
Pour contourner le problème, on ajouter un identifiant supplémentaire dans les deux tables.
Dans la table DEMOGRAPHY, le client DEBORAH a deux observations. On aura donc CNT=1 et CNT=2.
data demography;
set demography;
by cl_name;
if first.cl_name then cnt=1;
else cnt+1;
run;
Dans la table SELL, le client DEBORAH a quatre observations. On aura donc CNT=1, CNT=2, CNT=3 et CNT=4.
data sell;
set sell;
by cl_name;
if first.cl_name then cnt=1;
else cnt+1;
run;
Il ne reste plus qu’à combiner les deux tables à partir de la variable client (CL_NAME) et de la variable CNT.
data mix_demo_sell;
merge demography
sell;
by cl_name cnt;
run;
proc print data=mix_demo_sell;
run;
Le résultat désiré se présente ainsi :
Lecture complémentaire

Deux méthodes pour sélectionner des données en se basant sur un second data set
janvier 26, 2009Avec IF/SELECT/WHERE, OUTPUT/DELETE vous savez comment garder une partie des données disponible en fonction de la valeur de variables. Mais comment faire si les données servant de critère sont dans un autre data set ?
Voici un exemple :
- D’un côté, on a un data set SAS avec tous les effets secondaires (adverse events) de tous les patients. Un patient peut avoir plusieurs effets secondaires et donc plusieurs lignes. Il peut aussi ne pas être présent s’il aucun effect secondaire n’a été enregistré.
- De l’autre côté on a un data set contenant seulement les patients répondant aux critères du protocol d’étude clinique (une ligne par patient).
Comment garder tous les effects secondaires de ces patients valides par protocole et seulement de ceux-là ?. SAS a deux possibilités :
- un MERGE dans une étape data utilisé avec son option (IN=)
- un PROC SQL avec la condition WHERE… IN ().
Vous trouverez un rappel sur le MERGE en lisant : « La base de la jointure de deux data sets avec MERGE« .
1. Les data sets AE_MULTI et PAT_UNIQ servent d’exemple
Une ou plusieurs lignes par patients dans le data set AE_MULTI : le data set AE_MULTI contient six effets secondaires (6 lignes d’observations) se référant à 4 patients (numéros : 1, 2, 4 et 5).
data ae_multi; input patref ae_id; datalines; 1 1 1 2 2 1 4 1 4 2 5 1 ; run;
Une seule ligne par patient dans le data set PAT_UNIQ : le data set PAT_UNIQ contient trois patients (3 observations) : numéros 2, 3 et 4.
data pat_uniq; input patref; datalines; 2 3 4 ; run;
En d’autres termes, on souhaite garder les observations de AE_MULTI si et seulement si le patient est aussi enregistré dans le data set PAT_UNIQ. Trois observations sont à conserver : celles du patient 2 avec ses deux effets secondaires et celle du patient 4 avec son effet secondaire.
patref ae_id 2 1 4 1 4 2
2. Deux solutions
Dans ce cas du MERGE, on annote (flag) les données avec des variables temporaires (AE et PAT).
- Si la valeur de PATREF est présente dans le fichier AE_MULTI, alors AE=1, sinon AE=0.
- Si la valeur de PATREF est présente dans le fichier PAT_UNIQ, la variable PAT=1, sinon elle est égale à 0.
Si le patient est à la fois dans les deux data sets (si AE=1 et PAT=1), alors les données sont envoyées (ouputted) dans le data set VERSION1.
Comme se sont les variables du data set AE_MULTI qui nous intéresse et non celles du data set PAT_UNIQ, on ne garde parmi les variables de PAT_UNIQ seulement la variable PATREF servant de lien et listée dans l’instruction BY.
data version1; merge ae_multi (in=ae) pat_uniq (in=pat keep=patref); by patref; if ae and pat; run;
Avec la procédure SQL, on sélectionne toutes les données disponibles dans le data set AE_MULTI en précisant que les valeurs de la variable PATREF doit aussi être présentes dans une autre sélection, celle définie entre parenthèses.
proc sql; create table version2 as select * from ae_multi where patref in (select patref from pat_uniq); quit;
Entre les deux méthodes, on notera deux différences :
- Avec le merge, il est possible de lier des data sets ayant plus d’une variable commune (by pays centre patient;).
- Avec la procédure SQL, on peut multiplier les données dans le WHERE. Par exemple, on pourrait à la fois choisir les patients qui sont dans le data set PAT_UNIQ et exclure les effets secondaires qui sont aussi présents dans un autre fichier que AE.

Savoir interpréter une note liée au MERGE
juin 5, 2008Dans un cas particulier, une jointure many-to-many avec un MERGE, SAS génère une note. Il est très important de savoir l’interpréter. En effet, il est fréquent de vouloir un FULL JOIN (PROC SQL) mais d’utiliser maladroitement le MERGE (Data Step). Je vous propose donc de voir la différence entre les deux approches.
Rappel : si dans chacun des deux data sets à fusionner, il y a des doublons pour les variables communes, il s’agit d’une jointure MANY-TO-MANY.
Données utilisées pour illustrer le sujet : voici deux data sets appelés FRST_MANY et SECOND_MANY avec chacun trois variables. Les variables X et Y sont présentes dans les deux data sets. Dans le premier data set, trois lignes d’observations ont pour valeur x=A, y=B. Dans le second data set, deux lignes d’observations ont pour valeurs x=A, y=B et deux autres x=B, y=D.
frst_many second_many
a x y x y b
1 A B B D 2
2 A B B D 8
9 A B A B 4
3 C D A B 3
5 B D E F 6
1. Premier Choix, le FULL JOIN de la PROC SQL : on veut que chaque ligne d’observations de FRST_MANY soit dupliquée s’il y a plusieurs lignes d’observations dans SECOND_MANY ayant les mêmes BY variables ; et inversement.
En d’autres termes, vu que x=A, y=B apparaît trois fois dans le premier data set et deux fois dans le second, il y aura six lignes d’observations après la fusion des jeux de données.
De même, vu qu’il y a une observation x=B, y=D dans le premier jeu et deux dans le second jeux, il y aura deux observations après la fusion et la variable a=5 du premier jeux sera dupliquée pour chaque ligne.
final
a x y b
1 A B 3
2 A B 3
9 A B 3
1 A B 4
2 A B 4
9 A B 4
5 B D 2
5 B D 8
3 C D .
. E F 6
En terme de programmation SAS, cela donne :
proc sql;
create table final as
select a,
coalesce(one.x,two.x) as x,
coalesce(one.y,two.y) as y,
b
from frst_many one
full join
second_many two
on one.x=two.x and
one.y=two.y;
quit;
2. Second Choix, MERGE : pour chaque combinaison de BY variables, le nombre de lignes dans le data set final correspond au nombre de ligne le plus important parmi les deux data sets d’origine.
Dans ce cas, SAS génère la note suivante, très importante :
NOTE: MERGE statement has more than one data set with repeats of BY values.
Le mieux est encore de regarder l’exemple pour comprendre ce qui se passe.
Vu qu’il y a trois lignes d’observations pour x=A, y=B dans le premier jeu, et seulement deux dans le second, il y aura trois lignes d’observations au final pour ces BY variables. La deuxième et dernière valeur de la variable b du second data set (b=3) sera dupliquée pour les lignes supplémentaires.
Vu qu’il y a deux lignes d’observations pour x=B, y=D dans le second jeu et une seule dans le premier, la valeur de la variable a du premier data set (a=5) sera également dupliquée pour la ligne supplémentaire.
final
a x y b
1 A B 4
2 A B 3
9 A B 3
5 B D 2
5 B D 8
3 C D .
. E F 6
Pour obtenir ce résultat, il faut passer par un MERGe et si besoin trier les données :
proc sort data=frst_many;
by x y;
run;
proc sort data=second_many;
by x y;
run;
data final;
merge frst_many
second_many;
by x y;
run;
Annexe : syntaxe pour créer les data sets et ainsi tester la PROC SQL et le MERGE.
data frst_many;
input a x $ y $;
datalines;
1 A B
2 A B
9 A B
3 C D
5 B D
;
run;
data second_many;
input x $ y $ b;
datalines;
B D 2
B D 8
A B 4
A B 3
E F 6
;
run;

La base de la jointure de deux data sets avec MERGE
mai 29, 2008Tout d’abord, une jointure c’est quoi ? Une jointure est le rapprochement de plusieurs data sets pour n’en former plus qu’un. Maîtriser les jointures est primordial pour un programmeur. On peut citer deux raisons : fusionner des données est un travail récurrent ; une mauvaise jointure a des conséquences sur toute la suite du travail. La syntaxe de SAS peut paraître triviale. L’important est de connaître ses données et de savoir clairement ce qu’on attend à la fin. Prenez le temps qu’il faut pour acquérir cette compétence, vous ne le regretterez pas.
Les jointures peuvent être définies selon trois critères.
- Ajouter des variables : on distingue d’un côté les jointures où le but principal est d’empiler des observations les une en dessous des autres (SET, UNION,…) des jointures où le premier but est d’ajouter des variables (MERGE, JOIN,…).
- Avoir des variables communes aux deux data sets : selon les situations des variables communes doivent être précisées. Parfois, néanmoins, le but est différent et aucune variable commune n’est listée. On s’intéressera au cas le plus fréquent : des variables communes listées.
- Jointure dans un data set : enfin la syntaxe du data step (SET, MERGE) se distingue de celle de la procédure SQL. Dans le cas présent, on se concentrera sur celle du data step.
Objectif : En résumé, il s’agira de présenter la base de la jointure MERGE, propre au data step, où les variables communes sont listées dans une instruction BY. Voici donc pour commencer trois des quatre situations de base du MERGE avec des variables communes.
Exemples : Dans les exemples qui suivent, il y a deux data sets à chaque fois. Le premier a pour variable A, X, Y, et le second a les variables X, Y et B. Les variables X et Y sont les variables communes. Le résultat de la jointure est un data set nommé FINAL. En fin d’article, vous trouverez le code pour créer rapidement ces différents data sets sources.
1. Différents noms de jointure : si on a deux data sets qui ont une ou plusieurs variables communes, on aura le choix entre plusieurs jointures :
- ONE-TO-ONE : si dans chaque data set, cette variable (ou la combinaison de ces variables) n’apparaissent qu’une fois, la jointure des deux data sets sera une jointure ONE-TO-ONE.
- ONE-TO-MANY ou MANY-to-ONE : si un des deux data sets a pour cette variable plusieurs fois la même valeur, la jointure s’appellera ONE-TO-MANY ou MANY-to-ONE.
- MANY-TO-MANY : maintenant si dans chacun des deux data sets il y a des doublons pour les variables communes, il s’agit d’une jointure MANY-TO-MANY.
2. Des doublons dans aucun des data sets
Dans l’exemple ci-dessous, chacune des combinaisons x=,y= n’apparaît qu’une fois. Une jointure des deux data sets sera ONE-TO-ONE.
Avant deux data sets
frst_one second_one
a x y x y b
1 A B B D 2
3 C D A B 4
5 B D E F 6
Après un seul data set
final
a x y b
1 A B 4
3 B D 2
5 C D .
. E F 6
Lister plus de deux data sets ONE-TO-ONE-TO-ONE-TO…: dans ce cas particulier, il est possible de lister plus de deux de data sets ayant tous des BY variables uniques.
2. Des doublons parmi les variables communes dans un et un seul des data sets.
S’il y a des doublons dans un des deux data sets, des lignes supplémentaires seront ajoutées. Et les observations de l’autre data sets seront dupliquées pour chaque doublons.
MANY-TO-ONE : Ici, c’est le premier data set qui a des doublons. La valeur b=4 est répétée pour chacun des x=A, Y=B du premier data set.
Avant deux data sets
frst_many second_one
a x y x y b
1 A B B D 2
2 A B A B 4
9 A B E F 6
3 C D
5 B D
Après un seul data set
final
a x y b
1 A B 4
2 A B 4
9 A B 4
3 B D 2
5 C D .
. E F 6
ONE-TO-MANY : A l’inverse, ici, c’est le second data set qui a des doublons. C’est donc la valeur a=1 qui est répété pour chaque x=A, Y=B et a=5 pour chacune des combinaisons x=B, y=D du second data set.
Avant deux data sets
frst_one second_many
a x y x y b
1 A B B D 2
3 C D B D 8
5 B D A B 3
A B 4
E F 6
Après un seul data set
final
a x y b
1 A B 3
1 A B 4
5 B D 2
5 B D 8
3 C D .
. E F 6
Après la jointure, il est possible de garder seulement certaines observations. Cela fera l’objet d’un autre article. Jeudi prochain, nous verrons le cas particulier du MANY-TO-MANY.
3. En langage SAS, cela donne quoi?
Quelque soit le type de jointure parmi les trois listées (ONE-TO-ONE, MANY-TO-ONE et ONE-TO-MANY) la syntaxe du MERGE est la même. Je choisi dans cet exemple de nommer le premier data set FRST_… et l’autre SECOND_… Le data set créé s’appelle FINAL. Vous trouverez en bas de l’article le code pour créer ces data sets selon qu’il y a des doublons (FRST_MANY, SECOND_MANY) ou pas (FRST_ONE, SECOND_ONE).
L’instruction BY implique que les données soient préalablement triées de la même manière. Si vous êtes sûr que l’ordre est bon, vous pouvez vous passer d’un tri. Mais c’est rare. Du coup, on a le choix entre un PROC SORT ou un ORDER BY (« GROUP BY ») dans une PROC SQL.
proc sort data=frst_…;
by x y;
run;
proc sort data=second_…;
by x y ;
run;
data final;
merge frst_… second_…;
by x y;
run;
Annexe : créer les data sets pour tester les jointures
data frst_one;
input a x $ y $;
datalines;
1 A B
3 C D
5 B D
;
run;
data second_one;
input x $ y $ b;
datalines;
B D 2
A B 4
E F 6
;
run;
data frst_many;
input a x $ y $;
datalines;
1 A B
2 A B
9 A B
3 C D
5 B D
;
run;
data second_many;
input x $ y $ b;
datalines;
B D 2
B D 8
A B 3
A B 4
E F 6
;
run;

Oh attention danger avec MERGE et IF
mars 11, 2008Oh attention danger ! Cela me fait penser à une chanson de Sardou. Mais c’est aussi la phrase qu’il faut avoir à l’esprit quand on veut combiner par un MERGE deux jeux de données et en même temps mettre à jour une variable avec une condition IF.
Lorsque MERGE et IF sont utilisés dans un seul data step pour actualiser une variable, le programmeur a souvent en tête un MERGE puis un IF. C’est à dire d’équivalent de deux data steps, un pour le MERGE et un pour IF. Hors dans les faits, SAS agit différemment.
Il est donc essentiel de savoir repérer la situation pour utiliser deux steps au lieu d’un. Pour cela je vous propose de passer par un exemple.
1. Les données d’origine : je vous propose en exemple deux jeux de données appelés ONE et TWO ayant une variable commune ID et une variable unique, X dans le premier cas, Y dans le second. On compte plusieurs ID identiques dans ONE. Chaque ID est unique dans TWO. On fait donc un merge MANY-TO-ONE.
—ONE—
id x
1 999
1 888
1 777
2 66
—TWO—
id y
1 10
2 12
2. La méthode claire en deux étapes : quand x est égal à 999, l’observation de Y est mise à jour. Dans l’exemple, seule la première observation de Y est concernée.
Dans un premier temps, les données sont combinées.
data safe;
merge one two;
by id;
run;
id x y
1 999 10
1 888 10
1 777 10
2 666 12
Dans un second temps, la variable Y est mise à jour.
data safe;
set safe;
if x=999 then y=999;
run;
id x y
1 999 999
1 888 10
1 777 10
2 666 12
3. La méthode risquée : en regardant le résultat, on remarque la mise à jour de la variable Y ne concerne plus seulement la première observation mais est étendue à l’ensemble des observations de l’ID concerné (ID=1)-
data danger;
merge one two;
by id;
if x=999 then y=999;
run;
id x y
1 999 999
1 888 999
1 777 999
2 666 12
En conclusion, les deux notations sont correctes. Il est seulement important de savoir clairement le résultat qu’on recherche. Le premier cas reste le plus fréquent. Lorsqu’il s’agit de mettre à jour une variable une fois un MERGE terminé via une IF condition, il faut le faire en deux étapes pour éviter des sorties différentes de ses attentes.

Retrouver la valeur suivante avec LAG ou un MERGE
mars 5, 2008
Dans un précédent article, la fonction LAG a été présentée. Il s’agissait alors de créer une nouvelle variable contenant la valeur précédente d’une variable existante. Pour récupérer la valeur suivante cette fois, je vous propose deux méthodes : utiliser la fonction LAG avec un tri décroissant ou faire un MERGE.
1. Trier par ordre décroissant et utiliser la fonction LAG : pour retrouver l’information suivante plutôt que l’information précédente, il vous suffit de trier les observations par ordre décroissant au préalable. Dans notre exemple précédent, (1, 2, 3, 4, 5) devient (2, 3, 4, 5, .). Afin de retrouver l’ordre d’origine, vous aurez besoin d’un second tri après. Cette fois-ci, c’est la dernière observation par patient qui sera manquante puisqu’il n’y a pas d’observation après pour un patient donné. En SAS, cela veut dire qu’il faudra utiliser LAST après le tri final ou FIRST avant le tri final.
proc sort data=test;
by patient descending dt;
run;
data next_dt;
set test;
by patient;
next_dt=lag(dt);
if first.patient then next_dt=.;
run;
proc sort data=next_dt;
by patient dt;
run;
2. Extraire la valeur suivante avec un MERGE : en extrayant la variable date sans sa première observation dans un jeu de donnée, on obtient la liste des valeurs suivantes. Il suffit ensuite d’ajouter ces valeurs au jeu de données d’origine pour avoir la 2ème date comme valeur suivante pour la première observation, etc. Un MERGE sans instruction BY est suffisant. Comme avant, on actualise la dernière observation par BY variable via LAST.
proc sort data=test;
by patient dt;
run;
data next_dt;
merge test
test (firstobs=2 rename=(dt=next_dt));
run;
data next_dt;
set next_dt;
by patient;
if last.patient then next_dt=.;
run;