Posts Tagged ‘best.’

h1

Quand compilation et exécution font la différence, un exemple

août 21, 2008

SAS effectue plusieurs lectures d’un programme. A la première lecture, c’est la compilation. A la seconde, c’est l’exécution. Connaître ces notions vous aidera à comprendre les exemples ci-dessous : pourquoi le premier code proposé ne fonctionne pas alors que les autres passent. Les fonctions PUT, VVALUE, le dictionnaire DICTIONARY.COLUMNS et le DATA _NULL_ serviront dans les exemples.

1. Un premier exemple avec la fonction PUT

Rappel sur la fonction PUT : Une fonction PUT permet de convertir une variable numérique en variable texte ou une variable texte en une autre variable texte. Elle est composée de deux paramètres. D’un côté, il y a la variable d’origine. De l’autre côté, il y a le format à appliquer sur cette variable d’origine. C’est donc la valeur sous forme formatée qui devient une valeur texte. Reportez vous à l’article « Convertir une variable caractère en numérique et inversement » pour plus de détails.

La phase de compilation : A la compilation, SAS  vérifie que la variable d’origine et le format associé sont tous les deux du même type. Il faut qu’une variable numérique est un format qui s’applique à une variable numérique. De manière identique, il faut un format caractère pour une variable texte.

La phase d’exécution : Si on ne connaît pas à l’avance le type de la variable, on peut avoir envie de définir une condition : si la variable est numérique applique tel format, sinon applique tel autre format. Hors une condition IF/THEN n’est visible par SAS qu’à la phase d’exécution.

En d’autres termes, SAS tentera d’appliquer un format numérique à une variable numérique avant de regarder si la fonction PUT est définie dans une condition.

data import_excel;
   retain type ‘CHAR’;
   study = ‘999’;
   output;
   study = ‘888’;
   output;
run;

data study_new;
   set import_excel;
   if type=‘NUM’ then study_new=put(study,best.);
   else study_new=study;
run;

Le résultat : Dans l’exemple, un format numérique (BEST.) est appliqué à une variable texte (STUDY). La première partie de la condition ne s’applique pas car le type de la variable n’est pas égal à NUM. Mais SAS cherche un format $BEST. qui n’existe pas. Il est obligé de s’arrêter là.

28 data study_new;
29 set ref;
30 if upcase(type)=’NUM’ then study_new=put(study,best.);
                                                  —–
                                                  48

ERROR 48-59: The format $BEST was not found or could not be loaded.

31 else study_new=study;
32 run;

NOTE: The SAS System stopped processing this step because of errors.
WARNING: The data set WORK.STUDY_NEW may be incomplete.
When this step was stopped there were 0 observations and 3 variables
.

Un exemple où le type de la variable est inconnu : en important un fichier EXCEL (PROC IMPORT/MIXED=YES), le type de la variable sous SAS peut-être inconnu. La variable sera caractère si une cellule contient du texte. Sinon, elle sera numérique.

2. Une solution rapide

Une fonction Vxxx: la fonction VVALUE retourne une valeur texte. Elle utilise le format associé à la variable en interne pour construire la valeur sous forme formatée. La nouvelle variable aura une longueur de 200.

data study_new;
   set ref;
   if type=’NUM’ then study_new=vvalue(study);
   else study_new=study;
run;

3. Une solution plus lourde mais pouvant s’appliquer à plusieurs variables

Une autre solution est de générer le code à exécuter. Si la variable est numérique, c’est l’instruction avec PUT qui apparaîtra, sinon c’est l’autre instruction. Cette approche fait appel à la notion de dictionnaire et de DATA _NULL_.

3.1 Créer un data set contenant le nom des variables et leur type à partir du dictionnaire (dictionary) appelé COLUMNS

La première étape consiste à créer un data set, nommé DICT_REF, contenant la variable STUDY et son type.

Choix du dictionnaire : Le dictionnaire (dictionary) COLUMNS est un data set de référence, créé de manière automatique par SAS. Il répertorie toutes les variables contenues dans tous les data sets de toutes les bibliothèques actives. Il contient donc une ligne par variable.

Chaque ligne du dictionnaire contient plusieurs informations caractérisant cette variable dont :

  • la bibliothèque d’origine (variable LIBNAME)
  • le data set d’origine (variable MEMNAME)
  • le nom de la variable (variable NAME)
  • le type de la variable (variable TYPE).

Prendre un sous-ensemble du dictionnaire : Ici seule la variable STUDY est utile. Elle provient du data set EXCEL_IMPORT sauvegardé de manière temporaire dans la bibliothèque WORK.

Mettre en majuscule : Le type de la variable est soit « num » soit « char », toujours en minuscule. Le nom de la variable peut avoir un mélange de majuscules et minuscules selon la manière dont est saisi le nom lors de sa création. Pour éviter des surprises, le nom de la variable et le type sont mis en majuscule grâce à la fonction UPCASE. L’avantage des dictionnaires, c’est qu’ils peuvent lister plus d’une variable.

proc sql;
   create table dict_ref as
      select upcase(name) as name,
             upcase(type) as type
      from dictionary.columns
      where upcase(libname) = ‘WORK’ and
            upcase(memname) = ‘EXCEL_IMPORT’ and
            upcase(name)    = ‘STUDY’;
quit;

3.2 Ecrire le code et l’appeler

La deuxième étape consiste à créer un programme nommé TMP_STUD.SAS donc le nom et l’emplacement est défini dans l’instruction FILENAME. Pour écrire dans ce fichier, l’instruction FILE est ajoutée dans le DATA _NULL_. Pour plus de précisions sur l’instruction PUT, reportez-vous à l’article « Ecrire un texte avec l’instruction PUT« .

filename stud ‘C:/sasref/tmp_stud.sas’;

data _null_;
   set dict_ref;
   file stud;
   put ‘data study_new;’;
   put @3 ‘set excel_import;’;
   if type=‘NUM’ then put @3 ‘study_new=put(‘ name ‘,9.);’;
   else put @3 ‘study_new=’ name ‘;’;
   put ‘run;’;
run;

%include stud;
filename stud;

L’écriture du programme est fonction des informations contenues dans le DICT_REF. Si plus d’une variable est sélectionnée, il faudrait préciser deux choses :

  • Les instructions DATA et SET ne sont à écrire qu’une fois. Elles sont ajoutées lors de la première boucle fait en interne autour de l’étape DATA via « if _N_=1 ».
  • L’instruction RUN apparaît une fois en fin de programme. Il faut donc l’ajouter une fois le dernier record du fichier de référence atteint. L’option END= de l’instruction SET crée une variable interne prenant la valeur 0 pour tous les records sauf le dernier où elle prend la valeur 1. La condition est donc basée sur cette variable.

filename stud ‘C:/sasref/tmp_stud.sas’;

data _null_;
   set dict_ref end=eof;
   file stud;
   if _N_=1 then
      do;
         put ‘data study_new;’;
         put @3 ‘set excel_import;’;
      end;

   if type=‘NUM’ then put @3 ‘study_new=put(‘ name ‘,9.);’;
   else put @3 ‘study_new=’ name ‘;’;
   if eof then
 put ‘run;’;
run;

%include stud;
filename stud;

Le code sauvegardé dans le fichier TMP_STUD.SAS se présente donc ainsi, vu que la variable STUDY est de type caractère.

data study_new;
   set excel_import;
   study_new=STUDY ;
run;

L’instruction %INCLUDE permet l’exécution de ce code.

h1

Convertir une variable caractère en numérique et inversement

avril 21, 2008

Cet article est maintenant réécrit. Vous le retrouvez sur www.programmeur-pro.com.

Passer d’une variable numérique à une variable caractère ou inversement est fréquent en langage de programmation SAS. Les fonctions INPUT et PUT permettent de changer ainsi le type de la variable. Dans un premier temps, je vous propose deux exemples pour illustrer les deux situations. Dans un second temps, on verra deux emplois supplémentaires de la fonction PUT : ajouter des zéros avant et après le nombre, et passer d’une valeur caractère à une autre valeur caractère.

Exemples d’application : dans la vie courante, il est fréquent de créer une variable texte à partir de plusieurs autres. Dans le lot, il y a souvent une variable numérique. Celle-ci doit être convertie en texte avant la concaténation. A l’inverse, on peut vouloir extraire le chiffre d’une chaîne de caractère et le sauvegarder dans une variable numérique.

Note : Dans un data step, on est obligé de créer de donner un nom différent à la variable d’origine et à la nouvelle variable. Il est alors courant de renommer au préalable la variable d’origine pour pouvoir utiliser son nom pour la nouvelle variable. Ensuite, la variable d’origine est supprimée. Dans une procédure SQL, le même nom peut être utilisé.

1. Du caractère au numérique et inversement

La fonction INPUT est composée de deux paramètres : la variable texte ou directement la chaîne de caractère d’un côté, l’informat de l’autre.

Du caractère au numérique : ici, on indique à la machine qu’il faut lire la variable d’origine comme une variable texte pouvant atteindre une longueur de 16 caractères. Pour cela on utilise l’informat $16. On peut aussi choisir un informat $CHAR. : ici $CHAR16. (SAS Online Doc. : INPUT Function, Informats by Category)

data char_to_num;
  x_char = ‘123456789.123456’;
  x_num = input(x_char,$16.);
*x_num = 123456789.123456;
run;

Note : Pensez à ajouter un format sur la variable numérique si vous ne la lisez pas intégralement dans votre output.

Du numérique au caractère : dans l’exemple ci-dessous, on indique que la valeur à créer sera numérique avec 16 chiffres/point dont 6 après la virgule. C’est l’information donnée par le format numérique 16.6. Bien sûr, on peut avoir la longueur nombre à convertir peut-être plus petit sans risquer d’affecter la valeur. Une autre possibilité est d’utiliser le format BEST16. Si aucun nombre n’est précisé (BEST.) cela revient à BEST8. SAS cherche alors la meilleure réponse possible permettant d’entrer 8 chiffres/point. Les décimales pourront être tronquées s’il n’y a pas assez de place, voir les entiers.

data num_to_char;
  y_num = 123456789.123456;
  y_char = put(y_num,16.6);
*y_char = ‘123456789.123456’;
run;

2. Les plus de la fonction PUT

Ajouter des zéros aux extrémités du nouveau texte : le format z. permet de remplacer les espaces vides par des zéros. Dans l’exemple ci-dessous, la nouvelle variable aura une longueur de 8 caractères. Les deux derniers seront les chiffres après la virgule. Comme il n’y en a qu’un seul dans la variable d’origine, un zéro sera ajouté à la fin. Il reste deux espaces en début à remplir avec des zéros.

data num_char_zero;
   z_num = 123.1;
   z_char = put(z_num,z8.2);
  *z_char = ‘00123.10’;
run;

Passer d’une valeur caractère à une autre : la valeur caractère d’origine peut aussi être du texte et non des chiffres. Dans cette situation, la nouvelle variable prend la valeur d’un format caractère souvent défini par le programmeur.

proc format;
  value $cntry
  FR = ‘France’
  LU = ‘Luxembourg’
  CH = ‘Suisse’;
run;

data char_to_char;
  a1_char=’LU’;
  a2_char=put(a1_char,$cntry.);
  *a2_char=’Luxembourg’;
run;