Vous n'êtes pas identifié.
Bienvenue sur le site support de mes ouvrages d'introduction à SAS
La 4ème édition de mon ouvrage est disponible depuis le 11 avril 2019 !
encore une histoire tirée de faits réels...
de deux faits réels en fait...
Caroline m'a envoyé un fichier Excel avec lequel j'ai eu quelques difficultés et Ibrahima m'a contacté pour un problème qu'il rencontrait et qui avait aussi pour origine un fichier Excel.
Je vais concentrer les deux problèmes dans ce petit exercice...
Je dispose d'un classeur Excel avec lequel j'ai bien des misères....
ce fichier peut être téléchargé en cliquant sur ce lien
Comme je souhaite manipuler avec SAS les données contenues dans ce classeur, j'ai exécuté cette instruction :
libname test xlsx "c:/intro_sas/fichiers/maudit.xlsx";
évidemment, dans mon journal, tout semble bien aller :
2895 libname test xlsx "C:\intro_sas\fichiers\maudit.xlsx"; NOTE: Libref TEST was successfully assigned as follows: Engine: XLSX Physical Name: C:\Users\leo_l\Documents\poubelle\maudit.xlsx
premier problème
Le premier onglet contient deux variables : email et type. Je souhaite afficher l'observation relative à l'email client_B@quinexistepas.com.
cette adresse email existe, aucun doute à ce sujet (vous pourrez vérifier en ouvrant le classeur Excel).
j'exécute donc le programme suivant :
proc print data=test.feuil1; where email="client_B@quinexistepas.com"; run;
et je n'obtiens aucun résultat.... dans mon journal, j'ai ce message :
NOTE: Access by observation number not available. Observation numbers will be counted by PROC PRINT. NOTE: The import data set has 12 observations and 2 variables. NOTE: No observations were selected from data set TEST.feuil1. NOTE: There were 0 observations read from the data set TEST.feuil1. WHERE email='client_B@quinexistepas.com'; NOTE: PROCEDURE PRINT a utilisé (Durée totale du traitement) : real time 0.00 seconds cpu time 0.01 seconds
les deux premières notes ne doivent pas vous inquiéter, elles ne sont pas la cause de cette première difficulté...
vous ne me croyez pas ?
data maudit; set test.feuil1; run; proc print data=maudit; where email="client_B@quinexistepas.com"; run;
et vous n'aurez pas non plus de résultat.... pourtant, si vous remplacez = dans l'instruction WHERE par CONTAINS, vous obtenez bien un résultat...
proc print data=maudit; where email contains "client_B@quinexistepas.com"; run;
le résultat :
j'ai donc deux questions :
1- pourquoi ?
2- et comment corrige t'on le problème pour que le programme suivant fonctionne et donne le résultat escompté :
proc print data=maudit; where email="client_B@quinexistepas.com"; run;
second problème
pour des raisons qui n'appartiennent qu'à moi, j'ai besoin de créer un fichier TXT contenant les observations de la table maudite. J'ai donc rédigé ce programme (classique...) :
data _null_; set test.feuil1; file "C:\intro_sas\fichiers\maudit.txt"; put email @30 type ; run;
(j'ai indiqué un @30 dans mon instruction PUT parce que je souhaite créer un fichier TXT formaté colonne)
Mon journal m'indique que les choses semblent s'être bien passées :
2904 data _null_; 2905 set test.feuil1; 2906 file "C:\intro_sas\fichiers\maudit.txt"; 2907 put email @30 type ; 2908 run; NOTE: The file "C:\intro_sas\fichiers\maudit.txt" is: Nom du fichier=C:\intro_sas\fichiers\maudit.txt, RECFM=V,LRECL=32767, Taille de fichier (octets)=0, Modifié(e) le=17 novembre 2020 10 h 06, Heure de création=17 novembre 2020 10 h 06 NOTE: The import data set has 12 observations and 2 variables. NOTE: 12 records were written to the file "C:\intro_sas\fichiers\maudit.txt". The minimum record length was 30. The maximum record length was 42. NOTE: There were 12 observations read from the data set TEST.feuil1. NOTE: DATA statement a utilisé (Durée totale du traitement) : real time 0.02 seconds cpu time 0.00 seconds
et j'ouvre mon fichier TXT pour vérifier qu'effectivement, tout va bien :
client_A@quinexistepas.com super client client_B@quinexistepas.com client moyen client_C@quinexistepas.com client bon client_D@quinexistepas.com super client client_E@quinexistepas.com client moyen client_F@quinexistepas.com client bon client_G@quinexistepas.com super client client_H@quinexistepas.com client moyen client_I@quinexistepas.com client bon client_J@quinexistepas.com super client client_K@quinexistepas.com client moyen
fatalitas !
et j'ai deux nouvelles questions (identiques en fait aux deux précédentes...):
1- pourquoi ?
2- et comment corrige t'on je problème pour que mon programme fonctionne et donne le résultat escompté : un fichier TXT dans lequel chaque observation n'est présentée que sur une ligne
amusez vous bien
Hors ligne
Attaquons nous aux deux premières questions posées liées à l'impossibilité d'avoir un résultat quand le programme suivant est exécuté :
proc print data=test.feuil1; where email="client_B@quinexistepas.com"; run;
pourquoi est ce que ça ne marche pas ?
réponse simple : parce que la modalité de EMAIL n'est jamais égale à client_B@quinexistepas.com
vous me direz :
"ah... pourtant, quand on regarde la modalité, on dirait bien qu'elle est égale à cette valeur pour la seconde observation !"
et je vous répondrai : "il ne faut JAMAIS croire ce que l'on voit quand on regarde une table SAS"
Ceux qui ont lu mes bouquins le savent...
"alors à quoi est égale cette modalité ?"
regardons cela au moyen du programme suivant :
libname lib xlsx "C:\intro_sas\fichiers\maudit.xlsx"; data maudit; set lib.feuil1; if _n_=2 then do ; do i=1 to length(email); lettre=substr(email,i,1); ascii=rank(lettre); put lettre= ascii=; end; end; drop lettre ascii; run;
ce programme permet de voir le code ASCII associées à chacun des caractères de la modalité d'EMAIL pour la seconde observation.
vous obtenez dans votre journal le résultat suivant :
lettre=c ascii=99 lettre=l ascii=108 lettre=i ascii=105 lettre=e ascii=101 lettre=n ascii=110 lettre=t ascii=116 lettre=_ ascii=95 lettre=B ascii=66 lettre=@ ascii=64 lettre=q ascii=113 lettre=u ascii=117 lettre=i ascii=105 lettre=n ascii=110 lettre=e ascii=101 lettre=x ascii=120 lettre=i ascii=105 lettre=s ascii=115 lettre=t ascii=116 lettre=e ascii=101 lettre=p ascii=112 lettre=a ascii=97 lettre=s ascii=115 lettre=. ascii=46 lettre=c ascii=99 lettre=o ascii=111 lettre=m ascii=109 lettre= ascii=160
tiens.... tout semble être correct sauf... le dernier caractère... on dirait un blanc mais c'est en fait le caractère ASCII 160.
on se renseigne un peu et on découvre qu'il s'agit en réalité d'un blanc insécable - la caractère ASCII pour le blanc, c'est 32.
Dans un classeur EXCEL, si votre modalité contient des blancs à droite, lorsque vous lisez votre classeur Excel au moyen de SAS, ces blancs sont éliminés. Ça n'est pas le cas des blancs insécables.
Le problème de ces blancs insécables n'est pas un problème que j'invente de toute pièce et qui est lié uniquement à SAS : c'est relativement courant et ça ne concerne pas que SAS (pour vous en convaincre faites une recherche "Excel Ascii 160").
que faire ? supprimer ces espaces insécables !
data maudit(drop=i j); set maudit; array all{*} _character_; do i=1 to dim(all); do j=1 to length(all{i}); all{i}=tranwrd(all{i},byte(160),''); all{i}=strip(all{i}); end; end; run;
la fonction BYTE(160), sorte "d'inverse" de RANK, permet de renvoyer à SAS, en second argument de TRANWRD, le caractère espace insécable que l'on souhaite remplacer par "rien".
J'ai utilisé ici TRANWRD mais on pouvait tout à fait utiliser COMPRESS :
all{i}=compress(all{i},byte(160));
et maintenant, pourquoi utiliser STRIP dans l'instruction qui suit notre TRANWRD ?
Si les blancs à droite sont supprimés lorsque vous lisez un classeur Excel au moyen de SAS, ça n'est pas le cas avec les blancs à gauche... au moyen de STRIP, nous les supprimons.
Si maintenant, vous exécutez le programme suivant :
proc print data=maudit; where email="client_B@quinexistepas.com"; run;
vous aurez bien un résultat.
Avons nous régler l'ensemble des problèmes liés à ce classeur Excel ?
et bien non... ce saut de ligne qui apparaît lorsqu'on veut créé un fichier TXT est toujours là... mais maintenant que vous avez la méthode, vous saurez sûrement le régler...
à suivre...
Hors ligne
Concluons ce petit exercice...
si vous ouvrez le fichier Excel, vous constaterez que dans la colonne TYPE, il a été introduit un saut de ligne à l'intérieur de chaque case.
Dans le fichier Excel ouvert par SAS au moyen de LIBNAME XLSX, ces sauts de ligne n'apparaissent pas lorsque vous faites un PROC PRINT et vous pourriez croire qu'ils ont été supprimés. Et bien non... ils sont toujours là et c'est ce que l'on constate lorsqu'on cherche à créer un fichier TXT.
Vous le constaterez aussi lorsque vous exécuterez le programme suivante :
proc print data=maudit; where type="super client"; run;
Vous n'obtiendrez aucun résultat...
il y a une nouvelle fois ici des caractères cachés dans les modalités de type et il suffit simplement de suivre la démarche vue dans le précédent post pour régler le problème.
C'est ce qu'à fait Mathieu dans la solution qu'il m'a transmise :
data _null_; set maudit; if _n_=2 then do; do i=1 to length(type); lettre=substr(type,i,1); ascii=rank(lettre); put lettre= ascii=; end; end; drop lettre ascii; run; /* On remarque la présence des caractères ASCII 13 (carriage return) et ASCII 10 (linefeed). */ data maudit; set maudit; do i=1 to length(type); type=tranwrd(type,byte(13),' '); type=tranwrd(type,byte(10),' '); type=strip(compbl(type)); end; drop i; run; /* Il y a maintenant deux espaces successifs donc on en supprime un. */ data _null_; set maudit; file "C:\Users\hukic\Desktop\maudit.txt"; put email @30 type; run;
et voilà !
à bientôt pour un nouveau sujet...
Hors ligne