Archive for the ‘Fonctions’ Category

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

9 points autour de la notion d’octet

juillet 28, 2008

L’octet (byte en anglais) est une unité de mesure informatique utilisée en SAS pour définir la longueur des variables. Il permet de stocker 1 caractère parmi une liste de 256. Une des listes de caractères les plus répandue est la table des ASCII (American Standard Code for Information Interchange). SAS dispose de deux fonctions RANK et BYTE pour passer d’un nombre à un de ces caractères et inversement. Ces notions sont à découvrir ou redécouvrir sous la forme de 9 points.

1. Des notions mathématiques mises à la sauce informatique

Deux valeurs possibles avec les booléens : Les booléens (boolean) sont des valeurs égales à 0 ou à 1. C’est une notation mathématique. On parle souvent de la logique des booléens. L’interprétation de ces valeurs est :

  • 0 pour faux (false)
  • 1 pour vrai (true)

En SAS, les syntaxes FIRST/LAST et END= du data step se servent de la logique des booléens.

Le bit est l’unité informatique de base : L’unité de mesure élémentaire en informatique, le bit (bit en anglais également) est basé sur le même principe. Le bit prend soit la valeur 0, soit la valeur 1.

L’octet est un groupement de 8 bits : Un octet (byte en anglais) est égal à la combinaison de 8 unités élémentaires, de 8 bits.

2. Le but du jeu

En informatique, le but du jeu est de n’utiliser que des valeurs 0/1 pour faire référence à des nombres entiers. Pour avoir un éventail de nombre entier assez large, il faut donc plusieurs bits.

Ensuite, pour chaque nombre entier une valeur peut être assignée. Par exemples, les nombres allant de 0 à 255 servent dans une table de référence pour les caractères, la table des ASCII.

3. Combien de valeurs différentes sont extraites avec x bits ? 

Tout d’abord, les bits sont mis les uns à la suite des autres.

  • Avec 1 bit : le bit prend soit la valeur 0 soit la valeur 1.
  • Avec 2 bits : les valeurs de 2 bits s’arrangent de 4 manières différentes à savoir 00, 01, 10 ou 11.
  • Avec 3 bits : les valeurs de 3 bits peuvent se présenter de 8 manières possibles 000, 001, 010, 011, 100, 101, 110, 111.

Généralisation : Pour savoir combien d’arrangements de 0 et 1 sont possibles, le nombre 2 (nombre de valeurs possibles dans un bit) est multiplié autant de fois qu’il y a de bits, soit 2x. En termes mathématiques, on parle du nombre d’arrangements avec répétition. Il s’agit bien du calcul avec répétition car les valeurs 0 et/ou 1 peuvent apparaître plusieurs fois.

Ecrire un exposant sous SAS : Pour mettre une valeur en exposant sous SAS, on fait suivre la base de 2 étoiles et de l’exposant. Voici un exemple pour une variable nommée EXPOSANT.

  • En langage mathématique : exposant=28
  • Sous SAS : exposant=2**8;

4. Quelle position pour mon bit ?

On commence par regarder celui qui est le plus à droite et on lui assigne la position 0. Celui qui suit aura une position 1, etc.

  • Avec 1 bit : le bit est en position 0.
  • Avec 2 bits : le premier bit est en position 1, le second en position 0.
  • Avec 3 bits : le premier bit est en position 2, le second en position 1 et le dernier en position 0.
  • Etc.

5. Création d’une liste de valeurs

Maintenant que la position (x) de chaque bit est connue, on va additionner des valeurs 2x à chaque fois que le bit est égal à 1. Voici donc quelques exemples avec 1, 2 et 3 bits. D’un côté, on a l’arrangement des bites, de l’autre la valeur que l’on peut en extraire.

Avec 1 bit, les valeurs finales sont entre 0 et 1.

  • « 0 » : 0
  • « 1 » : 20 = 1

Avec 2 bits, les valeurs finales sont entre 0 et 3.

  • « 00 » : 0 + 0 = 0
  • « 01 » : 0 + 20 = 0 + 1 = 1
  • « 10 » : 21 + 0 = 2 + 0 = 2
  • « 11″ : 21 + 20 = 2 + 1 = 3

Avec 3 bits, les valeurs finales sont entre 0 et 7.

  • « 000 » : 0 + 0 + 0 = 0
  • « 001 » : 0 + 0 + 20 = 0 + 0  + 1 = 1
  • « 010 » : 0 + 21+ 0 = 0 + 2 + 0 = 2
  • « 011 » : 0 + 21+ 20 = 0 + 1+ 2 = 3
  • « 100 » : 22 + 0 + 0 = 4 + 0 + 0 = 4
  • « 101 » : 22 + 0 + 20 = 4 + 0 + 1 =5
  • « 110 » : 22 + 21 + 0 = 4 + 2 + 0 = 6
  • « 111″ : 22 + 21+ 20 = 4 + 2 + 1 = 7

Avec 8 bits (1 octet) les valeurs vont de 0 à 255. Comme indiqué précédemment ces nombres servent pour la table des ASCII.

6. La table des ASCII et les fonctions RANK/BYTE

La table des ASCII regroupe les caractères en trois groupes :

  • 0-31 : les codes de contrôle (control code) comme « passage à la ligne »
  • 32-127 : les caractères imprimables (printable characters)
  • 128-255 : les caractères spéciaux (special characters) comme é, à, û…

Note pour les claviers étrangers : La liste des caractères spéciaux est pratique à l’étranger lorsqu’un clavier d’ordinateur ne dispose pas des accents. Ainsi pour obtenir la lettre « é », maintenez la touche « Alt » enfoncé et tapez le nombre 0233. Voici ceux que j’utilise le plus souvent :

  • 0224 à
  • 0226 â
  • 0231 ç
  • 0233 é
  • 0234 ê
  • 0235 è
  • 0238 î
  • 0244 ô
  • 0249 ù
  • 0251 û

Exemples d’applications : Dans le cadre des fonctions SAS, je vais me concentrer sur les valeurs 32 à 255 car ce sont les valeurs que j’ai rencontré dans des data sets SAS. J’ai aussi eu besoin de vérifier qu’une macro pouvait toujours fonctionner quand elle rencontrait ces caractères dans un data set. Pour se faire, j’ai eu besoin de créer un data set les contenant.

7. Convertir un nombre en caractère (la fonction BYTE)

Dans cet exemple, la fonction BYTE génère toutes les valeurs ASCII imprimables et les sauvegarde dans une variable ASCII. Pour ce faire, une boucle est construite avec les instructions DO et END. C’est l’occasion d’introduire rapidement sous forme d’exemple la notion de boucle.

data one (drop=i);
   do i=32 to 127;
   *do i=128 to 255;
      ascii=byte(i);
      output;
   end;
run;

La boucle est définie par variable i allant de 32 à 128 (et non 127) mais l’action est conduite seulement pour les valeurs 32 à 127. Les valeurs intermédiaires sont distantes d’une valeur 1 car l’incrémentation par défaut est 1. Pour changer cette valeur par défaut et disons prendre une valeur sur deux, on ajoute BY 2 dans l’instruction DO.

A chaque fin de boucle i est incrémenté par 1. Quand i=127, la valeur est calculée une dernière fois. Puis i est incrémenté  par 1. Avec i=128, la condition n’est plus remplie. Le contenu de la boucle est ignoré. SAS s’intéresse à l’étape suivante dans le data step. Ici l’étape suivante est la suppression de la variable i définissant la boucle.

A chaque nouvelle valeur de la variable i, la variable ASCII est recalculée. Puis le record est ajouté dans le data set ONE grâce à l’instruction OUTPUT.

8. Convertir un caractère ASCII en nombre (la fonction RANK)

Dans cet exemple, la fonction RANK retourne la valeur numérique de la table ASCII pour la lettre « é ». Cette valeur est sauvegardée dans la variable VAL_NUM.

data two;
   val_num=rank(‘é’);
run

9. Les multiples des octets dans le commerce

Dans le monde des disques durs…, et taille de fichiers…., vous entendez couramment parler de :

  • Kilooctet ou Ko (Kilo Byte KB en anglais),
  • Megaoctet ou Mo (Mega Byte MB),
  • Gigaoctet ou Go (Giga Byte GB),
  • Teraoctet ou To (Tera Byte TB).

A l’avenir, on entendre peut-être même parle de :

  • Petaoctet ou Po (Peta Byte PB),
  • Exaoctet ou Eo (Exa Byte EB),
  • Zebioctet ou Zo (Zebi Byte ZB),
  • Yobioctet ou Yo (Yobi Byte YB).

La Commission Electrotechnique International (International Electrotechnique Commission IEC) a développé un standard se basant sur des multiples de 10 de l’octet. Cependant, l’ancien standard peut encore être rencontré.

  • Nouveau standard : un Kilooctet est 1 000 octets (103). Un Megaoctet est 1 000 000 (106).
  • Ancien standard : un Kilooctet représente 1 024 octets (210). Pour le Megaoctet, on passe à 1 048 576 (220).

En résumé, en achetant un disque dur de 500 Go, le produit est plus intéressant s’il réfère à l’ancien standard car il aura une plus grande capacité. Par contre, si on a un fichier de 5 Mo à envoyer, il représente moins de volume si on parle avec le nouveau standard.

h1

Mes valeurs sont t’elles proches de la moyenne ? (écart-type)

juin 17, 2008

Pour résumer une série de mesures, il est courant de proposer la moyenne. Mais avoir une moyenne de 11 n’a pas le même sens selon que les valeurs soient dispersées entre 10 et 13, ou entre 0 et 20. Dans le premier cas, toutes les valeurs sont plus proches de la moyenne que dans le second cas. L’écart-type (ou standard deviation en anglais) reflète cette subtilité. Le statisticien aura pour rôle d’interpréter cette valeur. En comprenant le sens d’un écart-type,  le programmeur trouvera un outil supplémentaire pour vérifier la cohérence de ses résultats.

1. Des variables continues

La moyenne et l’écart-type sont des outils s’appliquant uniquement aux données numériques, suivant un ordre donné où l’écart entre chacune des valeurs potentielles est toujours le même. On peut donc parler de valeurs continues au sens large du terme.

Ainsi, l’âge d’une personne est une donnée continue qu’elle soit arrondie en années, en mois, en jours, en heure. La moyenne et l’écart-type auront une précision similaire.

2. Définition l’écart-type d’une population

L’écart-type ayant pour but de chiffrer l’écart entre les valeurs  et la moyenne. Il est donc logique de calculer la différence entre chaque valeur et la moyenne. Dans un premier temps, on a autant de différences que de valeurs. Dans un second temps, une valeur moyenne est extraite de ces différences.

1. Mettre au carré les différences : qui dit moyenne, dit somme des valeurs divisé par le nombre de valeur. Hors, la somme de valeurs positives et négatives s’annulent. Et dans notre cas, on a bien des valeurs inférieures et des valeurs supérieures à la moyenne. Dans le cas de l’écart-type, toutes les différences sont rendues positives en les multipliant par elles-mêmes (mises au carré).

C’est probablement pour des faciliter la résolution de calculs mathématiques que la mise au carré est préféré à la prise des valeurs absolu. Si vous avez une autre hypothèse, n’hésitez pas à en faire part.

2. Extraire la moyenne : on souhaite une moyenne. Donc la somme des différences (mises au carré) sont divisées par le nombre de différences. Si on s’arrête là, la statistique s’appelle la variance.

3. Exprimer la dispersion dans la même unité que la moyenne : A présent la somme des différences n’est plus dans la même unité que la moyenne. Pour parler dans la même unité, on prend la racine de l’ensemble du calcul.

3. Estimer l’écart-type d’une population à partir d’un échantillon

Contexte : il est fréquent de ne pas travailler sur la population qui nous intéresse mais sur un échantillon. Par exemple, si on mesure la pression artérielle systolique des patients d’une étude clinique pour savoir si la drogue a permis de la réduire, le statisticien n’est pas intéressé par la moyenne de ces patients mais bien celle de tous les personnes pouvant à l’avenir faire appel à cette drogue.

Le problème : De plus, les recherches statistiques ont permis de démontrer qu’en moyenne, la moyenne de tous les échantillons possibles est la même que celle de la population. Pour l’écart-type, c’est un peu moins simple, puisqu’il la moyenne des écarts-types de tous les échantillons n’est pas exactement égale à celle de la population.

La solution : Mais les chercheurs en statistique sont là ! Ils ont réussi à montrer qu’en enlevant 1 au nombre total de valeurs dans chacun des échantillons, on pouvait retrouver l’écart-type de la population (cf. des cours d’inférence qui semble si théorique au prime abord mais qui permettent d’accéder à l’arrière de la scène).

Vocabulaire : Et pour enrichir votre vocabulaire et surtout comprendre ces spécialistes sachez que si l’écart-type sera appelé un estimateur biaisé si le 1 n’est pas enlevé.

L’écart-type le plus utilisé est donc le second, celui où on divise les différences non pas par le nombre de différences mais le nombre de différences moins 1.

4. Comprendre la différence entre l’écart-type et l’erreur-type

Pour ceux qui auront une formation à composante statistique, vous pourrez être amené à expliquer en entretien ou à vos collègues la différence entre l’écart-type (standard deviation) et l’erreur-type (standard error). 

La première différence, c’est que l’écart-type s’applique à des données, alors que l’erreur-type s’applique à la statistique de la moyenne. 

A chaque fois, qu’un échantillon est pris, sa moyenne va servir à estimer la moyenne de la population. Bien-sûr, toutes les moyennes des échantillons ne sont pas identiques. Il existe une variabilité. Certains sont plus proches de la réalité que d’autre. Cette variabilité des résultats entre les échantillons est donnée par l’erreur-type. Ainsi un intervalle à l’intérieur duquel la moyenne de la population se tient pourra être estimé.

5. En langage mathématique, l’écart-type donne quoi ?

Pour désigner nos valeurs, le mathématicien utilise la lettre X.

  • Xi représente la ième valeur de l’échantillon. Si on a 15 valeurs alors i prend les valeurs de 1 à 15 ou plus généralement les valeurs de 1 à n.
  • La moyenne de ces Xi est symbolisée par un X avec une barre au dessus.

Pour calculer l’écart-type, on a parlé de trois étapes :

  1. sum(Xi-Xbar)2 Tout d’abord la différence entre chaque Xi et la moyenne X barre est calculée. Elles sont mises au carré. Puis, la somme de ces valeurs en est faite. On en profite pour préciser que les valeurs de i vont de 1 à n.
  2. sum(Xi-Xbar)2 / (n-1) Après, il s’agit de calculer la moyenne de ces valeurs
  3. racine(sum(Xi-Xbar)2 / (n-1)) Enfin, la statistique est convertie en une unité comparable à celle de la moyenne via la racine carré.

6. Et en langage SAS, comment trouver la valeur d’un écart-type ?

Dans tous les cas suivant, le dénominateur est n-1.

6.1 Fonction STD : La fonction STD (standard deviation) retourne la valeur de l’écart-type.

proc sql;
   select std(age) as std_age
   from sashelp.class;
quit;

6.2 Calcul manuel : dans un premier temps, la différence avec l’âge moyen est calculée pour chaque record. Chaque différence est mise au carré. Dans un deuxième temps, la somme de ces différences est divisée par le nombre de records moins 1. Enfin, la racine carrée du tout est prise.

proc sql;
   create table step1 as
      select (age-mean(age))**2 as step1
      from sashelp.class;
   select sqrt(sum(step1)/(count(*)-1)) as step2_3
      from step1;
quit;

6.3 Les procédures PROC MEANS et PROC SUMMARY : dans les exemples ci-dessous, j’ai volontairement choisi l’instruction ODS OUTPUT pour extraire les statistiques dans un data set.

proc means data=sashelp.class;
var age;
ods output Summary=proc_means;
run;

proc summary data=sashelp.class print;
   var age;
   ods output Summary=proc_summary;
run;

6.4 La procédure PROC UNIVARIATE : deux sorties fournies par la procédure UNIVARIATE sont indifféremment disponible.

proc univariate data=sashelp.class;
   var age;
   ods output Moments=proc_univ_opt1;
   ods output BasicMeasures=proc_univ_opt2;
run;

h1

Créer une date SAS de 3 manières

avril 28, 2008

Cet article a été réécrit. Il est disponible sur programmeur-pro.com

 

Le langage SAS utilise sa propre échelle de temps. Dans un premier temps, je vous rappèle comment est définie une date, une heure et une combinaison de l’heure et du jour. Puis, je vous propose trois alternatives pour convertir ou créer ces valeurs.

1. Rappel sur la notion de date SAS et datetime SAS

Date : Une date SAS est un nombre entier égal au nombre de jours écoulés depuis le 1er janvier 1960. Les dates avant 1960 sont donc négatives. Le 1er janvier 1960 est égal à zéro. Ainsi la différence entre deux dates SAS est un nombre de jours.

Time : Un time SAS est un nombre représentant le nombre de secondes écoulées depuis minuit. Il varie entre 0 et 86400 (60 secondes * 60 minutes *24 heures). La différence entre deux times SAS est un nombre de secondes.

Datetime : Un datetime SAS est un nombre représentant le nombre de secondes écoulées depuis le 1er janvier 1960. Ce nombre aura une valeur décimale si on utilise des dixièmes de secondes. Mais ceci est rare. La différence entre deux datetimes SAS est donc un nombre de secondes.

Avantages : Ces nombres facilitent les calculs sur le temps écoulé. De plus, les fonctions de temps SAS ont besoin de ces valeurs. Ainsi la fonction MONTH extrait le mois d’une date SAS (SAS Online Doc. : Liste des fonctions DATE).

Inconvénient et parade : pour lire ces dates/time/datetime, on préfère les voir en langage humain. Soit un format est appliqué sur la valeur numérique, soit une variable caractère est créée avec une fonction PUT et le nom du format. Ce sujet ne sera pas détaillé dans cet article.

SAS Online Doc : About SAS Date, Time and Datetime Values

2. Les fonctions MDY et DHMS

Créer une date avec la fonction MDY : La fonction MDY crée une date SAS. Elle a besoin de trois informations : le mois, le jour et l’année. Aux Etats-Unis, le mois apparaît en premier dans la date, suivi du jour et enfin du mois. Les trois paramètres de cette fonction sont donc des valeurs numériques. Le langage SAS ayant été créé aux Etats-Unis, l’ordre des paramètres de la fonction MDY est le même. Le nom de la fonction est lui-même parlant : M pour month, D pour day et Y pour year.

visit_dt = mdy(visit_m,visit_d,visit_y);

Créer un time avec la fonction HMS : la fonction HMS retourne un time SAS. Elle est composée de l’heure, des minutes et des secondes.

visit_hour = hms(vist_hr,visit_min,visit_sec);

Créer un datetime avec la fonction DHMS : Créer une datetime avec la fonction DHMS : la fonction DHMS créer une datetime SAS. Elle a 4 paramètres : la date SAS, l’heure, les minutes et les secondes.

visit_time = dhms(visit_dt, vist_hr,visit_min,visit_sec);

3. Lire un texte et le convertir en date/time/datetime

On peut lire une valeur texte et demander à SAS de l’interpréter comme une date. Il faut alors que ce texte suivre une des structures répertoriées par SAS. On parle d’informat. En voici la liste complète : SAS Online Doc., Informats by Category. La fonction INPUT est alors utilisée. Le premier paramètre est soit une valeur texte entre guillemets, soit une variable texte.

DATE informat : Une des notations les plus utilisées pour lire des dates est le jour suivi des trois premières lettres du mois en anglais et enfin de l’année exprimée avec 4 chiffres. La longueur totale étant de 9 caractères, l’informat s’appelle date9. DATE. a pour valeur par défaut 7. Cela impose une année à 2 chiffres.

jour = input(’25NOV1952′,date9.);

nov_dt = input(’25NOV52′,date7.); *attention à l’option globale YEARCUTOFF qui décidera s’il s’agit de 1952 ou 2052 par exemple (voir la note plus bas);

TIME informat : L’informat TIME. a pour longueur par défaut 8. Donc TIME. et TIME8. sont identiques.

heure = input(’08:15:00′,time.);

DATETIME informat : L’informat DATETIME. a pour longueur par défaut 18. Ainsi DATETIME. et DATETIME18. sont identiques.

jour_heure = input(’25NOV1952:08:15:10′,datetime.);

Note sur l’option YEARCUTOFF :

a. Identifier la valeur actuelle de YEARCUTOFF : pour savoir quelle est l’année de YEARCUTOFF, consultez la log après avoir soumis le code suivant :

proc options;
run;

b. Changer le yearcutoff : pour alterner cette valeur, utilisez l’instruction globale OPTIONS et le mot-clé YEARCUTOFF.

options yearcutoff=1950;

c. Interprétation : avec une YEARCUTOFF de 1920,

  • une année inférieure à 20 sera interprétée comme égale à une année 2000 :  20xx.
  • Une année supérieure ou égale à 1920 sera interprétée comme une année 1900 : 19xx

4. Ecrire manuellement quelques valeurs date/time/datetime

Une manière rapide de créer une date SAS si, et seulement si, on a très peu de valeurs à entrer est de faire suivre la valeur texte de d, t ou dt selon qu’il s’agisse d’une date, d’un time ou d’un datetime.

x = ‘ 25NOV1952’d;

x = ’08:15:00’t;

x = ’25NOV1952:08:15:10’dt;

SAS Online Doc. : SAS Constants in Expressions

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;

h1

La concaténation : 4 fonctions SAS 9

avril 16, 2008

Cet article a été réécrit. Il est maintenant disponible sur programmeur-pro.com.

Mettre des morceaux de textes à la suite les uns des autres et enregistrer le tout dans une variable, c’est ce qu’on appelle la concaténation. D’un côté, il y a la double barre. De l’autre côté, il y a les fonctions « CAT » disponibles depuis SAS 9. Voici donc un rapide tour d’horizon de ces notations.

A titre d’exemple, si vous avez plusieurs variables pour identifier de manière unique une ligne d’observations, vous pouvez construire une variable unique à partir d’une concaténation et ainsi manier plus facilement certaines fonctionnalités de la procédure SQL.

Pour illustrer ce sujet, on utilisera une variable x et une variable z sans blanc aux extrémités et une variable y avec des blancs avant et après sont utilisés.

x = ‘Pays’;
y = ‘  UK  ‘;
z = ‘2008’;

A chaque fois, plusieurs notations sont proposées. Toutes donnent le même résultat.

1. La traditionnelle double barre : qu’il s’agisse de la double barre || ou des deux points d’exclamations !!, la concaténation requiert des valeurs textes (SAS Online Doc. : Section sur « Concatenation Operator »). Il faudra donc convertir les valeurs numériques avec une instruction PUT par exemple.

a1 = x ||  y || z ;

a1 = ‘Pays’ || ‘  UK  ‘ || ‘2008’;

a1 = ‘Pays’ || y || z;

a1 = ‘Pays UK 2008’;

 

Cette notation sert aussi pour la concaténation de matrices (SAS IML) et la définition d’un CALL EXECUTE.

2. Les fonctions CATS, CATX, CATS et CATT : ces fonctions varient en fonction de la place que l’on souhaite accorder aux blancs des différents maillons de la chaîne et si on souhaite ajouter des séparateurs. Elles disposent au moins d’autant de paramètres que de maillons formant la chaîne à créer. Chaque morceau de texte est séparé par une virgule. Si en plus on souhaite ajouter un séparateur entre les différents composants, un paramètre supplémentaire est listé en tête.

Sans blanc aux extrémités : personnellement, j’utilise le plus souvent la fonction CATS qui enlève les blancs aux extrémités. Cela revient à faire d’utiliser la double barre sans agir sur les maillons de la chaînes à construire .

a2 = cats(x,y,z) ;

a2 = cats(‘Pays’,’  UK  ‘,’2008’);

a2 = cats(‘Pays’,y,z);

a2 = ‘PaysUK2008’;

Ajouter un séparateur : la fonction CATX enlève les blancs de début et de fin et ajoute des séparateurs entre chaque « mot ». Le symbole utilisé comme séparateur est le premier paramètre de la fonction.

a3 = catx(‘-‘,x,y,z) ;

a3 = catx(‘-‘,’Pays’,’  UK  ‘,’2008’);

a3 = catx(‘-‘,’Pays’,y,z);

a3 = ‘Pays-UK-2008’;

Garder tous les blancs : la fonction CAT n’enlève pas les blancs au début et fin de texte de chacun des éléments de la concaténation.

a4 = cat(x,y,z) ;

a4 = cat(‘Pays’,’  UK  ‘,’2008’);

a4 = cat(‘Pays’,y,z);

a4 = ‘Pays  UK  2008’;

Enlever les blancs de fin uniquement : la fonction CATT enlève les blancs en fin de chaîne. Le dernier T de CATT fait référence à « Trailing Blanks » c’est-à-dire les blancs de fin de chaîne.

a5 = catt(x,y,z) ;

a5 = catt(‘Pays’,’  UK  ‘,’2008’);

a5 = catt(‘Pays’,y,z);

a5 = ‘Pays  UK2008’;

Pour ma part, j’ai du mal à me souvenir qui fait quoi. L’important, dans un premier temps, est de savoir que ces fonctions existent. On recherche après, en tant voulu, l’information sur les nuances. Si, vous avez trouvez un moyen mnémotechnique pour mémoriser les différences, n’hésitez pas à le faire savoir.

h1

2 syntaxes pour calculer un âge

avril 9, 2008

Quel âge à mon patient au début de l’étude ? Et mon client, quel âge a t-il lors de la signature de son contrat x ? Ces questions simples a priori peuvent vite devenir un casse-tête avec SAS. Je vous propose deux approches qui vous permettront d’aborder succinctement plusieurs fonctions. Les fonctions les plus facile à comprendre MONTH, DAY, YEAR, INT/FLOOR sont traitées sous forme de notes. Les fonctions de base pour le calcul de l’âge YRDIF et INTCK sont introduites dans des sections distinctes. On ne parlera pas ici de la manière de créer une date SAS.

Note : les fonctions YEAR, MONTH et DAY permettent de retrouver respectivement l’année, le mois et le jour d’une date SAS. Elles n’ont donc que la date comme paramètre.

Note : la fonction INT (pour le mot anglais « integer ») retourne la partie entière d’un nombre. La fonction FLOOR retourne l’entier inférieur. En rappel, « floor » signifie le sol en anglais. Dans le cas d’entier positif, les fonctions INT et FLOOR donnent la même valeur. Cela s’applique donc à l’âge.

Présentation du jeu de donné utilisé comme exemple : pour illustrer ce calcul, je vous propose en fin d’article un data set avec :

  • une variable pour la date de début (strt_dt),
  • une autre pour la date de fin (end_dt).

1. La fonction YRDIF : la fonction YRDIF contient trois paramètres : la date de début, la date de fin et le mode de définition des mois et années. Dans notre cas, on choisira des mois et années comme sur le calendrier et non des mois de 30 jours ou des années de 360 jours. Le troisième paramètre aura donc la valeur ‘ACT/ACT’ ou son alias ‘ACTUAL’.

yrdiff_val = yrdif(strt_dt,end_dt,‘ACTUAL’);

La valeur retournée est un nombre avec des virgules. Or il nous faut un nombre entier. Pour ne retirer que la partie entière, on ajoute la fonction INT.

int_yrdiff_val = int(yrdif(strt_dt,end_dt,‘ACTUAL’));

Maintenant, dans le cas particulier du jour anniversaire, on se rend compte que selon qu’il s’agit d’une année bissextile ou non, on a une valeur supérieure ou inférieure à un. On ajoute donc une condition pour ce cas particulier. Si les mois et jours sont identiques, on fait la soustraction entre l’année de fin et celle de début.

if month(strt_dt) = month(end_dt) and
   day(strt_dt) = day(end_dt)
   then age_m1 = year(end_dt)-year(strt_dt);
else age_m1 = int(yrdif(strt_dt,end_dt,‘ACTUAL’));

2. Une seule instruction : calculer la date en une seule instruction, c’est possible. Le calcul a été répertorié sur le forum SAS-L. Je vous propose de la détailler ici.

2.1 La fonction INTCK : la fonction INTCK avec pour premier paramètre ‘month’ a pour valeur minimale 0.  On rencontre ce cas lorsque les mois et année des deux dates coïncident. Pour le même mois un an après, SAS retournera une valeur de 12.

cnt_mois = intck(‘month’,strt_dt,end_dt);

2.2 Comparer les jours : si le jour de début est supérieur au jour de fin, le mois entier ne s’est pas écoulé. On enlève donc un mois au calcul précédent. Le résultat de la parenthèse (day(strt_dt) > day(end_dt) est soit 0, soit 1.

comp_jr = day(strt_dt) > day(end_dt);

2.3 S’exprimer en années : comme on veut le résultat en années et non en mois, le tout est divisé par 12.

2.4 Avoir un nombre entier : l’individu prenant un an de plus seulement quand l’âge est révolu, seule la partie entière nous intéresse. Une fonction INT ou FLOOR fera l’affaire.

age_m2 = int((intck(‘month’,strt_dt,end_dt)-(day(strt_dt)>day(end_dt)))/12);

3. Illustration avec des données : En plus des variables strt_dt (start date) et end_dt (end date), les observations sous regroupées en 4 catégories (variable flag).

  • Les dates anniversaires,
  • La veille et le lendemain de ces dates anniversaires.
  • Des dates de début et de fin identiques.

Des années bissextiles et des années de 365 jours sont incluses.

data strt_end;
  length flag $3;
  format strt_dt end_dt date9.;
  informat strt_dt end_dt date9.;
  input strt_dt end_dt flag $;
  datalines;
02APR1979 02APR1980 =1
02APR1980 02APR1981 =1
02APR1981 02APR1982 =1
02APR1979 01APR1980 <1
02APR1980 01APR1981 <1
02APR1981 01APR1982 <1
02APR1979 03APR1980 >1
02APR1980 03APR1981 >1
02APR1981 03APR1982 >1
02APR1979 02APR1979 =0
02APR1980 02APR1980 =0
02APR1981 02APR1981 =0
;
run;

Dans cette sortie, on trouve les dates de début et de fin. Puis, on distingue d’un côté les deux variables illustrant la méthode 1 et ensuite celles de la méthode 2.

                   __METHODE 1__ ____METHODE 2____
                   yrdiff_ age_ cnt_ comp par_ age
strt_dt    end_dt   val     m1  mois _jr annee  m2


02APR1979 02APR1980 1.00205  1  12   0  1.00000  1
02APR1980 02APR1981 0.99795  1  12   0  1.00000  1
02APR1981 02APR1982 1.00000  1  12   0  1.00000  1

02APR1979 01APR1980 0.99932  0  12   1  0.91667  0
02APR1980 01APR1981 0.99521  0  12   1  0.91667  0
02APR1981 01APR1982 0.99726  0  12   1  0.91667  0

02APR1979 03APR1980 1.00478  1  12   0  1.00000  1
02APR1980 03APR1981 1.00069  1  12   0  1.00000  1
02APR1981 03APR1982 1.00274  1  12   0  1.00000  1

02APR1979 02APR1979 0.00000  0   0   0  0.00000  0
02APR1980 02APR1980 0.00000  0   0   0  0.00000  0
02APR1981 02APR1981 0.00000  0   0   0  0.00000  0