📖 Cours - Module V — Conditions, boucles et tables multiples
- Écrire des traitements conditionnels avec IF/THEN/ELSE et le bloc DO/END
- Utiliser le bloc SELECT pour différencier un traitement selon les modalités d'une variable
- Regrouper des variables similaires dans un tableau (ARRAY) pour leur appliquer un même traitement
- Découper une table en plusieurs sous-tables avec OUTPUT
- Concaténer et fusionner des tables, et maîtriser les quatre types de jointures
1. La formule conditionnelle IF
Le traitement conditionnel permet de réaliser une ou plusieurs instructions selon certaines conditions.
if CONDITION then INSTRUCTION ; else INSTRUCTION ;
La ligne ELSE n'est pas obligatoire. Si plusieurs instructions doivent être réalisées pour une même condition, il faut passer par un bloc DO ... END :
if <condition> then do ;
<bloc d'instructions> ;
end ;
else do ;
<bloc d'instructions> ;
end ;
data work.employes ;
set MALIB.EMPLOYEES ;
if COUNTRY = "USA" then TRIGRAMME = substr(DIVISION, 1, 3) ;
else TRIGRAMME = "***" ;
keep DIVISION TRIGRAMME COUNTRY ;
run ;
2. Le bloc SELECT
L'instruction SELECT est plus lisible qu'une série de IF lorsqu'il s'agit de différencier un traitement selon les modalités d'une même variable.
data TABLE_CREEE ;
set TABLE_INITIALE ;
select (VARIABLE) ;
when (MODALITE1) instruction1 ;
when (MODALITE2) instruction2 ;
otherwise instruction ;
end ;
run ;
data work.secteurs ;
set MALIB.EMPLOYEES ;
select (scan(DIVISION, 1, "&")) ;
when ("INFO") SECTEUR = "Informatique" ;
when ("RH") SECTEUR = "Ressources Humaines" ;
when ("MKT") SECTEUR = "Marketing" ;
otherwise SECTEUR = "Autres" ;
end ;
run ;
3. Les boucles finies
Pour les traitements itératifs à l'intérieur d'une observation, on utilise les boucles DO.
data TABLE_CREEE ;
set TABLE_INITIALE ;
do i = 1 to 10 ;
<bloc d'instructions> ;
end ;
run ;
Nous reverrons ces structures sous leur forme macro (%DO ... %TO ... %END) au module IX, où elles servent à générer du code plutôt qu'à traiter des lignes. La différence est fondamentale et c'est l'une des confusions les plus tenaces chez les débutants en macro-langage.
4. Les tableaux (ARRAY)
Un tableau (ARRAY) regroupe plusieurs variables sous un nom commun, ce qui permet de leur appliquer le même traitement à l'intérieur d'une boucle DO, sans écrire une instruction par variable.
Contrairement à un tableau au sens R ou Python, un ARRAY SAS n'est pas un objet qui existe en dehors de l'étape DATA : c'est une facilité d'écriture, valable uniquement pendant l'exécution de l'étape DATA qui le déclare. Il doit être redéclaré dans chaque étape DATA qui l'utilise.
array NOM_TABLEAU {n} VAR1 VAR2 ... VARn ;
do i = 1 to n ;
NOM_TABLEAU{i} = <traitement> ;
end ;
Exemple : remplacer par 0 toutes les valeurs manquantes des variables NOTE1 Ã NOTE5.
data work.notes ;
set work.notes ;
array notes{5} note1-note5 ;
do i = 1 to 5 ;
if notes{i} = . then notes{i} = 0 ;
end ;
drop i ;
run ;
drop i ; en fin d'étape DATA quand elle ne sert qu'à parcourir le tableau.Si les variables à regrouper partagent déjà un suffixe numérique consécutif, comme NOTE1 à NOTE5, on peut les désigner par la notation abrégée var1-varn plutôt que de toutes les nommer. C'est la même notation déjà rencontrée avec mean(of note1-note5) au module IV.
Voir le corrigé
data work.notes2 ;
set work.notes ;
array notes{5} note1-note5 ;
moy = mean(of note1-note5) ;
do i = 1 to 5 ;
if notes{i} = . then notes{i} = moy ;
end ;
drop i ;
run ;
La moyenne doit être calculée avant la boucle de remplacement, sinon MEAN intégrerait les zéros ou les valeurs déjà remplacées au lieu des seules notes réellement obtenues.
5. Créer plusieurs tables en une seule étape DATA
Les tables à créer doivent être déclarées au niveau de l'instruction DATA. L'instruction OUTPUT indique la table qui reçoit l'enregistrement lu.
data work.OUTPUT1 work.OUTPUT2 ;
set work.TABLE ;
if <CONDITION1> then output OUTPUT1 ;
if <CONDITION2> then output OUTPUT2 ;
run ;
OUTPUT est particulièrement utile pour découper une table en plusieurs sous-tables en un seul balayage, ce qui est bien plus efficace que d'écrire autant d'étapes DATA que de sous-tables.
6. Concaténer des tables
On parle de concaténation lorsque l'on ajoute à une table les enregistrements d'une autre table : on empile des lignes. Les tables peuvent ne pas avoir le même nombre de variables.
data TABLE_SORTIE ;
set TABLE1 TABLE2 ;
run ;
7. Fusionner des tables : MERGE et les jointures
On parle de fusion lorsque l'on ajoute à une table les variables d'une autre table : on ajoute des colonnes. Il faut alors associer correctement les observations, donc disposer d'une ou plusieurs variables identifiant les observations. C'est la clé de jointure.
data TABLE_COMMUNE ;
merge TABLE1 TABLE2 ;
by CLE_DE_JOINTURE ;
run ;
Au-delà de la clé, il faut déterminer quelles valeurs conserver en sortie. L'option IN= crée un indicateur booléen signalant si l'observation provenait de la table concernée :
data work.TABLE_COMMUNE ;
merge work.TABLE1 (in = A) work.TABLE2 (in = B) ;
by CLE_DE_JOINTURE ;
if A and not B ;
run ;
Les quatre jointures se construisent ainsi :
| Jointure | Condition à écrire | Résultat |
|---|---|---|
| Jointure interne | if A and B ; | Uniquement les clés présentes dans les deux tables |
| Jointure à gauche | if A ; | Toutes les clés de la première table |
| Jointure à droite | if B ; | Toutes les clés de la seconde table |
| Jointure complète (full join) | aucune condition | Toutes les clés des deux tables |
Un cinquième cas revient souvent en pratique : les lignes présentes dans A mais absentes de B, obtenues avec if A and not B ;. C'est la façon canonique de répondre à la question « quels clients n'ont passé aucune commande ? ».
8. Deux compléments à connaître : RETAIN, FIRST. et LAST.
L'instruction RETAIN permet de conserver la valeur d'une variable d'une itération de l'étape DATA à la suivante. C'est ce qui rend possibles les cumuls.
data destination ;
set source ;
retain num_obs 0 ;
num_obs + 1 ;
run ;
SAS propose cependant une variable automatique _N_ qui désigne le nombre d'itérations réalisées de l'étape DATA en cours. Dans le cas simple d'une recopie de table, elle correspond exactement au numéro de l'observation courante :
data destination ;
set source ;
num_obs = _n_ ;
run ;
Lors d'une étape DATA utilisant une instruction BY, SAS crée pour chaque valeur distincte des variables d'agrégation deux variables booléennes temporaires : FIRST.variable vaut 1 si l'occurrence de la modalité est la première, LAST.variable vaut 1 si elle est la dernière.
proc sort data = SASHELP.PRDSAL3 out = work.ventes ;
by PRODUCT ;
run ;
data work.cumul ;
set work.ventes ;
by PRODUCT ;
retain ventes_cumulees 0 ;
if first.PRODUCT then ventes_cumulees = 0 ;
ventes_cumulees + ACTUAL ;
run ;
9. Exercices d'application
Voir le corrigé
data work.employes ;
set malib.employees ;
if country = "USA" then trigramme = substr(division,1,3) ;
else trigramme = "***" ;
keep division trigramme country ;
run ;
Voir le corrigé
data work.employes2 ;
set malib.employees ;
if country = "USA" then trigramme = substr(division,1,3) ;
else trigramme = "***" ;
div2 = scan(division, 2, "&") ;
keep division trigramme country div2 ;
run ;
Voir le corrigé
data work.secteurs ;
set malib.employees ;
select (scan(division,1,"&")) ;
when ("INFO") secteur = "Informatique" ;
when ("RH") secteur = "Ressources Humaines" ;
when ("MKT") secteur = "Marketing" ;
otherwise secteur = "Autres" ;
end ;
run ;
Voir le corrigé
data work.hommes work.femmes ;
set sashelp.classfit ;
if sex = "M" then output work.hommes ;
else output work.femmes ;
run ;
data work.tous ;
set work.hommes work.femmes ;
run ;
Voir le corrigé
proc sort data=malib.prdsale96 out=work.p96 ; by product ; run ;
proc sort data=malib.prdsale97 out=work.p97 ; by product ; run ;
data work.interne ;
merge work.p96 (in=a) work.p97 (in=b) ;
by product ;
if a and b ;
run ;
data work.gauche ;
merge work.p96 (in=a) work.p97 (in=b) ;
by product ;
if a ;
run ;
data work.droite ;
merge work.p96 (in=a) work.p97 (in=b) ;
by product ;
if b ;
run ;
data work.complete ;
merge work.p96 (in=a) work.p97 (in=b) ;
by product ;
run ;
Voir le corrigé
data work.texas ;
set sashelp.prdsal3 ;
where state = "TX" and date = "01JAN1997"d and product = "BED" ;
keep state product date actual ;
retain compt 0 ventes_cumulees 0 ;
compt + 1 ;
ventes_cumulees + actual ;
run ;
Voir le corrigé
proc sort data=sashelp.prdsal3 out=work.tri ;
by product ;
where state = "TX" and date = "01JAN1997"d ;
run ;
data work.cumul_produit ;
set work.tri ;
by product ;
retain ventes_cumulees ;
if first.product then ventes_cumulees = 0 ;
ventes_cumulees + actual ;
run ;
Le retour à zéro à chaque
first.product est ce qui distingue ce cumul à remise à zéro d'un cumul global comme celui de l'exercice V.6.- QCM — QCM Module V — 5 questions, auto-évaluation
Couleur de fond
Police
Crénage de la police
Visibilité de l’image
Hauteur de ligne
Surbrillance de lien
Alignement du texte
Taille de police
Espacement des lettres
Couleur de texte
Largeur de paragraphe