h1

Oh attention danger avec MERGE et IF

mars 11, 2008

Attention

Oh 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.

3 commentaires

  1. Bonjour,

    Merci pour cet excellent site, très précis et très clair, qui m’apprend pas mal de choses.

    Je vous suggérerais de créer une thématique supplémentaire qui recenserait toutes les bizarreries rencontrées dans SAS. Cela permettrait de bien mettre en valeur toutes les erreurs potentielles rencontrées si on ne fait pas attention.

    J’ai moi même été confronté à ce genre de problème mais pas avec merge, mais avec set.
    Voici un petit exemple que je donnais à mes élèves du temps où j’encadrais quelques étudiants :
    début du code sas :
    /*Lorsqu’on crée une base à partir de 2 existantes et qu’on effectue des
    corrections sur une variable présente dans une seule des 2 tables originelles,
    les corrections risquent d’être folkloriques.
    La bonne méthode est de le faire en 2 étapes data :
    1 – Réunion des 2 bases.
    2 – Correction sur la base créée.
    */

    *Illustration du problème.;
    data f1;
    do i=1 to 1000;
    a=ranuni(5);
    b=ranuni(6);
    output;
    end;
    run;
    *La variable c n’existe que dans f2;
    data f2;
    do i=1 to 1000;
    a=ranuni(7);
    b=ranuni(8);
    c=ranuni(9);
    output;
    end;
    run;
    *Mauvaise méthode : on fait tout en 1 fois;
    data ft1;
    set f1 f2;
    if c=0 and a>0.9 then b=1;
    if a<0.4 then do;
    b=0;
    c=0;*Sera appliqué à tous les individus de f1 à partir du 1er cas a0.9 then b=1;
    if a<0.4 then do;
    b=0;
    c=0;
    end;
    run;
    *On constate les différences;
    proc compare data=ft1 compare=ft2;
    run;


  2. bonjour; merci pour ce site qui m’aide personnellement, enormement .
    en fait je voulais poser une question si je peux trouvé une solution a mon blem sur SAS je vous explique:
    j’ai deux table1 et table2 avec une variable en commun qui s’appel ‘groupe’ . je veux faire un marge des deux table et creer une troisieme table3 ; le blem c’est que dans ‘groupe’ il ya des observation qui n’existe pas dans table1 et vis-vers-sa. kan j’essai de faire un merge .le journal sas me dit que une des table n’est pas correctement trier. il me faut un algorthme qui definit une condition du genre :
    if groupe in table1 or if groupe in table2.
    j’attend vos idée avec impatience . merci cordialemnt.


  3. Pourrais-tu envoyer une version raccourcie de tes data sets et de ton message d’erreur. Les données sont telles bien triées au préalable ? Il faut le même ordre que dans l’instruction BY.

    Deux choses auxquelles il faut suivre avec attention :
    – des variables ayant le même nom dans les deux data sets mais non listées dans le BY
    – plus d’une valeur par variable groupe dans les deux data sets.

    Sinon dans ton cas, tu peux aussi utiliser une procédure SQL.

    1. FULL JOIN servira de jointure.
    2. La variable commune aux deux avec ON.
    3. Un alias à chacune des tables sources est donné, disons a pour la table1 et b pour la table2. De cette manière on peut préciser pour une variable donnée de quelle table elle vient avec un mot court. Cet alias est option si les datasets sont dans une bibliothèque temporaire mais indispensable s’il s’agit de datasets permanents. On utilise alors le nom de la table pour préciser la source d’une variable.
    4. Pour voir les valeurs des deux sources, il faut faire appel à COALESCE.

    Voici un exemple :

    data table1;
    groupe=2;
    y=88;
    output;
    groupe=1;
    y=99;
    output;
    run;

    data table2;
    groupe=2;
    z=11;
    output;
    groupe=3;
    z=12;
    output;
    run;

    *option 1;

    proc sql;
    select coalesce(a.groupe,b.groupe) as groupe,
    y, z
    from table1 a
    full join
    table2 b
    on a.groupe=b.groupe;
    quit;

    *option 2;

    proc sort data=table1;
    by groupe;
    run;

    proc sort data=table2;
    by groupe;
    run;

    data table1_2;
    merge table1 table2;
    by groupe;
    run;

    proc print data=table1_2;
    run;



Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :