Analyser ses données écologiques en SAS

Dernière modification : 27/11/04

Les fonctions utilisables dans l'étape Data :

Les fonctions sont des actions déja préprogrammées que l'utilisateur peut appeler dans l'étape DATA pour effectuer des calculs sur des variables. Elles sont généralement définie par nom (à ne pas utiliser pour définir des noms de variables) et un ou plusieurs arguments séparés par une virgule "," (en Excel = ";").

Par exemple, le code lognind = log(nind); calcule le logarithme népérien du contenu de la variable nind et le stocke dans la variable lognind. On aurait pu le stocker dans la variable nind en écrivant nind = log(nind); mais on perdait alors l'abondance originale. On peut aussi écrire directement des chiffres ou du texte à la place d'un nom de variable. On peut emboîter les fonctions les unes dans les autres en les utilisant comme argument d'autres fonctions ou utiliser comme argument des calculs entre différentes variables. Par exemple, nom=compress(upcase(nom)); transforme d'abord le contenu de la variable nom en majuscule, puis élimine tous les caractères blancs qu'elle contient. Les fonctions sont sensibles au type numérique ou alphanumérique des variables.

Les fonctions peuvent être rassemblées en différentes familles et on présente ci-dessous une liste des plus fréquement utilisées. On indiquera le type de l'argument par le code num pour une variable ou un contenu numérique, le code anum pour une variable ou un contenu alphanumérique et le code variable pour indiquer un nom de variable.

Les fonctions sont rassemblées par différents types :

Les fonctions arithmétiques

ABS(num) donne la valeur absolue (= la valeur positive) d'un nombre
ABS(5.8) => 5.8 ou ABS(-58) => 58

DIM(variable) donne le nombre d'éléments qu'il y a dans un ARRAY

si on a défini ARRAY temp (*) x1-x5, alors DIM(temp) => 5

MAX(num1, ..., numn) calcule la valeur maximale de la liste de chiffres ou de variables (voir aussi l'introduction des variables statistiques où d'autres modes d'expression de listes de variables sont proposés)

MAX(1.5, 1.8, 1.79999) => 1.8

MIN(num1, ..., numn) calcule la valeur minimale de la liste de chiffres ou de variables (voir aussi l'introduction des variables statistiques où d'autres modes d'expression de listes de variables sont proposés)

MIN(1.5, 1.8, 1.79999) => 1.5

MOD(num1, num2) calcule le reste de la division de num1 par num2

MOD(10, 3) => 1

SQRT(num) calcule la racine carré d'un nombre. Pour d'autres racines, on procèdera avec un exposant fractionnaire comme x = y ** (1/3) pour obtenir une racine cubique.

SQRT(9) => 3

Les fonctions de troncation de nombre

CEIL(num) arrondi à l'entier supérieur
CEIL(5.8) => 6

FLOOR(num) arrondi à l'entier inférieur

FLOOR(5.8) => 5

INT(num) tronque à l'entier

INT(5.8) => 5

ROUND(num, nombre) arrondi le nombre num en fonction du nombre d'unités d'arrondi

ROUND(5.8, 1) => 6
ROUND(5.8) => 6
ROUND(5.7999, 0.1) => 5.8
ROUND(57899.1,10) => 57900

Les fonctions mathématiques

EXP(num) calcule l'exposant de num
EXP(1) => 2.7182818285
EXP(0) => 1
EXP(3.123) => 22.714420793

LOG(num) calcul le logarithme népérien de num

LOG(1) => 0
LOG(0) => .
et cela génére un message d'erreur
LOG (0.5) => -0.693147181
LOG(12) => 2.4849066498
LOG(EXP(1)) => 1

Pour effectuer une transformation logarithmique d'abondances d'espèces dont les valeurs peuvent être nulles, on ne peut appliquer directement la formule logabond => LOG(abond). Il faut donc ne le calculer pour pour les abondances >= à 1 ou effectuer systématiquement la transformation suivante : logabond = LOG(abond +1).

LOG2(num) calcul le logarithme en base 2 de num

LOG2(1) => 0
LOG2(0) => .
et cela génére un message d'erreur
LOG2 (0.5) => -1
LOG2(12) => 3.5849625007
LOG2(2) => 1

LOG10(num) calcul le logarithme en base 10 de num

LOG10(1) => 0
LOG10(0) => .
et cela génére un message d'erreur
LOG10(0.5) =>-0.301029996
LOG10(12) => 1.079181246
LOG10(2) => 1

Formules pour les autres bases = ?

Les fonctions trigonométriques

Les arguments des fonctions trigonométriques utilisant des degrés sont spécifiés en radians. 180 degrés = 1 pi radian. Donc, à partir d'un angle en degré, l'angle en radian se calcule comme suit :

Angle en radian = pi * (angle en degré) / 180
avec pi = 3.14159265358979

COS(num) calcule le cosinus de num

si pi = 3.14159265358979
COS(  0 / 180 * pi) =>  1.000 pour 0 degré
COS( 45 / 180 * pi) => 0.707 pour 45 degrés
COS( 90 / 180 * pi) => 0.000 pour 90 degrés
COS(180 / 180 * pi) => -1.000 pour 180 degrés
COS(270 / 180 * pi) => 0.000 pour 270 degrés
COS(360 / 180 * pi) => 1.000 pour 360 degrés
SIN(num) calcule le sinus de num
si pi = 3.14159265358979
SIN(  0 / 180 * pi) =>  0.000 pour 0 degré
SIN( 45 / 180 * pi) => 0.707 pour 45 degrés
SIN( 90 / 180 * pi) => 1.000 pour 90 degrés
SIN(180 / 180 * pi) => 0.000 pour 180 degrés
SIN(270 / 180 * pi) => -1.000 pour 270 degrés
SIN(360 / 180 * pi) => 0.000 pour 360 degrés

TAN(num) calcule la tangente de num

Pour les fonctions ARC qui permettent d'obtenir l'inverse d'un cosinus, d'un sinus ou d'une tangente, num est un chiffre compris entre 0 et 1 et le résultat est exprimé en radian. Pour l'obtenir en degré, il faut effectué la transformation suivante :

Angle en degré = 180 * (angle en radian) / pi
avec pi = 3.14159265358979

ARCOS(num) calcule l'arcosinus de num (qui est un nombre entre 0 et 1). C

ARSIN(num) calcule l'arcsinus de num

ARTAN(num) calcule l'arctangente de num

Pour les fonctions hyperboliques, l'argument num est simplement numérique.

COSH(num) calcule le cosinus hyperbolique de num [c'est en fait le résultat de (exp(num) + exp(-num))/2]

SINH(num) calcule le sinus hyperbolique de num [c'est en fait le résultat de (exp(num) - exp(-num))/2]

TANH(num) calcule la tangente hyperbolique de num [c'est en fait le résultat de [SINH/COSH]

Les fonctions statistiques

Ces différentes fonctions calculent des paramètres statistiques sur la distribution des valeurs ou de la liste des variables. Les arguments peuvent donc être une liste de chiffres ou de variables séparées par des virgules mais aussi être exprimés sous la forme d'une liste décrite par OF var1-varn. Par exemple, écrire somme = SUM(x1, x2, x3, ...à compléter...,x120) peut aussi bien s'écrire somme = SUM (OF x1-x120). L'expression "OF" est indispensable pour SAS n'interprète pas le signe "-" comme une soustraction de deux variables.

Si un ARRAY est défini (ARRAY y(*) x1-X120), on peut aussi l'utiliser somme= SUM(OF y(*)). Si on ne dispose pas d'ARRAY ou de listes de noms de variables du style x1-x1120, on peut aussi donner la liste des variables selon la forme premierevar--dernierevar qui utiliser, selon leur ordre de création, toutes les variables comprises entre la premierevar et la dernierevar, celles-ci incluses. Pratique quand les noms des varaibles sont des noms de stations ou des abréviations de taxons.

N(num1, ..., numn) calcule la fréquence de valeurs non-manquantes

N(1, 2, 4, 8, 10, 8, 4, 2, 1) => 9

NMISS(num1, ..., numn) calcule la fréquence des valeurs manquantes

NMISS(1, 2, 4, 8, 10, 8, 4, 2, 1) => 0

SUM(num1, ..., numn) calcule la somme de la liste des arguments non-manquants

SUM(1, 2, 4, 8, 10, 8, 4, 2, 1) => 40

MEAN(num1, ..., numn) calcule la moyenne de la liste des arguments non-manquants

MEAN(1, 2, 4, 8, 10, 8, 4, 2, 1) => 4.44

RANGE(num1, ..., numn) calcule l'écart entre les valeurs minimale et maximale de la liste des arguments non-manquants

RANGE(1, 2, 4, 8, 10, 8, 4, 2, 1) => 9

STD(num1, ..., numn) calcule l'écart-type de la liste des arguments non-manquants

STD(1, 2, 4, 8, 10, 8, 4, 2, 1) => 3.40

STDERR(num1, ..., numn) calcule l'erreur-standard à la moyenne de la liste des arguments non-manquants

STDERR(1, 2, 4, 8, 10, 8, 4, 2, 1) => 1.13

VAR(num1, ..., numn) calcule la variance de la liste des arguments non-manquants

VAR(1, 2, 4, 8, 10, 8, 4, 2, 1) => 11.53

CV(num1, ..., numn) calcule le coefficient de variation de la liste des arguments non-manquants

CV(1, 2, 4, 8, 10, 8, 4, 2, 1) => 76.39

CSS(num1, ..., numn) calcule la somme corrigée des carrés de la liste des arguments non-manquants

CSS(1, 2, 4, 8, 10, 8, 4, 2, 1) => 92.22

Les fonctions probabilistiques

Ces fonctions permettent de calculer des probabilités d'occurrences d'évenements en fonction de différents types de distribution de valeur. 

PROBNORM(x) calcule la probabilité qu'une observation d'une distribution normale standardisée (avec une moyenne = 0 et écart-type = 1) soit plus petite ou égale à x.

PROBNORM(0) => 0.500 soit à la moyenne, la probabilité est de 50%
PROBNORM(1.96) => 0.9750 soit à la valeur de 1.96, à pratiquement 2 écart-types, la probabilité est de 97,5%

PROBT(x, dld) calcule la probabilité qu'une observation d'une distribution de t de Student, avec ddl degré de liberté soit plus petite ou égale à x. Si on veut obtenir le niveau de signification d'un test de t bilateral, on doit faire p = (1 - PROBT(ABS(x),ddl))*2. Dans le cas d'un test unilatéral, on fera p = 1 - PROBT(ABS(x),ddl). On peut ainsi reconstruire un tableau de probabilité complet pour la v.a. de Student.

PROBT(1.45, 10) => 0.9112. La probabilité unilatérale est égale à 8,88 %; si le test est bilatéral, la probabilité est égale à 17,72 %
PROBT(1.96, 1000) => 0.9748.
La probabilité unilatérale est égale à 2,52 %; si le test est bilatéral, la probabilité est égale à 5,04 %

PROBF(x, ddln, ddld) calcule la probabilité qu'une observation d'une distribution de Fisher, avec ddln degré de liberté au numérateur (effet factoriel) et ddld degré de liberté au dénominateur (effet résiduel) soit plus petite ou égale à x. Si on veut obtenir le niveau de signification d'un test de F, on doit faire p = 1 - PROBF(x, ddln, ddld).

PROBF(3.32, 2, 3) => 0.8264. La probabilité est égale à 17,36 %

PROBCHI(x, ddl) calcule la probabilité qu'une observation d'une distribution de Chicarré, avec ddl degré de liberté soit plus petite ou égale à x. Si on veut obtenir le niveau de signification d'un test de Chicarré, on doit faire p = 1 - PROBCHI(x, ddl).

PROBCHI(11.264, 11) => 0.5786. La probabilité est égale à 42,14 %

Si on souhaite mesurer la fidelité d'une espèce de papillon à une plante, on peut utiliser le test de Chicarré avec par exemple le tableau suivant :

Fréquence observée

Papillon présent
Papillon absent

Plante présente

24
15

Plante absente

10
34

Fréquence attendue

Papillon présent
Papillon absent

Plante présente

15.98
23.02

Plante absente

18.02
25.98

Le Chicarré(r-1)*(c-1) = Chicarré(2-1)*(2-1) = Chicarré(1) = 12.88

PROBCHI(12.88, 1) => 0.99967. La probabilité unilatérale est égale à 0.0003, la relation est donc largement significative puisqu'on a 3 chances sur 10.000 de se tromper en disant qu'elle est vraie.

POISSON(x, n) calcule la probabilité qu'une observation d'une distribution de Poisson de moyenne x, soit plus petite ou égale à n.

POISSON(1, 2) => 0.9197

PROBBNML(p, n, m) calcule la probabilité qu'une observation d'une distribution binomiale, avec une probabilité de succès p, un nombre d'essais n et un nombre de succès m, est plus petite ou égale à m.

PROBBNML(0.5, 10, 4) => 0.3770

Les 3 fonctions suivantes font l'inverse des précédentes. Elles donnent les valeurs des tables qui correspondent à une probabilité et un certain nombre de degré de liberté.

TINV (p, ddl) calcule une valeur d'une table de t de Student correspondante à une probabilité p et ddl degré de liberté.

TINV(0.95, 2) => 2.9199

FINV (p, ddln, ddld) calcule une valeur d'une table de F correspondante à une probabilité p et ddln degré de liberté au numérateur et ddld degré de liberté au dénominateur.

FINV(0.95, 2, 10) => 4.1028

CINV (p, ddl) calcule une valeur d'une table de Chicarré correspondante à une probabilité p et ddl degré de liberté.

CINV(0.95, 3) => 7.81

Les fonctions de génération de nombres "aléatoires"

Ces fonctions permettent de générer des nombres qui suivent différentes distributions qui peuvent être ensuite utilisées pour tester le comportement de différents modèles. Ces nombres ne sont pas à strictement parler purement aléatoires mais le nombre d'itérations nécessaires pour retrouver les mêmes séries est très très grand.

Ces fonctions ont besoin d'un nombre de départ (n) qui permet de regénérer la même distribution de valeurs à condition qu'il soit plus grand que zéro. Si on utilise toujours le même nombre 5, la série de valeurs aléatoires générées sera la même à chaque exécution du programme. Si on utilise le chiffre zéro comme nombre de départ, c'est un nombre généré par l'horloge interne de l'ordinateur qui sert de point de départ et il est impossible d'obtenir les mêmes séries de nombres aléatoires. Les résultats peuvent alors varier d'une exécution à l'autre.

UNIFORM(n) génére un nombre pseudo-aléatoire compris entre 0 et 1 [ UNIFORM (n) est synonyme de RANUNI (n)]

NORMAL(n) génére un nombre dont la fréquence suit une distribution normale standardisée (avec une moyenne = 0 et écart-type = 1) [ NORMAL (n) est synonyme de RANNOR (n)].

Pour générer une série de valeurs x correspondant à une variable aléatoire normale de moyenne mean et un écart-type std, on utilisera la formule x = mean + std * NORMAL(0)

RANPOI(n, lambda) génére un nombre dont la fréquence suit une distribution de Poisson de moyenne lambda.

RANBIN(n, nbr, p) génére un nombre dont la fréquence suit une distribution binomiale(nbr, p).

Les fonctions alphabétiques

COMPRESS(anum) enlève les blancs dans la chaîne de caractères anum. Si elle est utilisée avec deux arguments comme COMPRESS(anum, "%"), elle enlève les "%" dans la chaîne de caractères anum.
COMPRESS("C'est la vie") => "c'estlavie"
COMPRESS("C'est la vie", "e") => "c'st la vi"

LEFT(anum) aligne à gauche dans la chaîne de caractères anum.

LEFT("    C'est la vie    ") => "c'est la vie         "

RIGHT(anum) aligne à droite dans la chaîne de caractères anum.

LEFT("    C'est la vie    ") => "         c'est la vie"

TRIM(anum) enlève les blancs à droite (à la fin) dans la chaîne de caractères anum.

TRIM("    C'est la vie    ") => "    c'est la vie"

Exemple comparatif de l'utilisation de ces 4 fonctions :

DATA;
fonction="normal            ";
chaine="     ABCDE   FGHIJ     ";
resultat='***'||chaine||'***';
   OUTPUT;
fonction="compress";
resultat='***'||COMPRESS(chaine)||'***';
   OUTPUT;
fonction="trim";
resultat='***'||TRIM(chaine)||'***';
   OUTPUT;
fonction="left";
resultat='***'||LEFT(chaine)||'***';
   OUTPUT;
fonction="right";
resultat='***'||RIGHT(chaine)||'***';
   OUTPUT;
fonction="trim(left)";
resultat='***'||TRIM(LEFT(chaine))||'***';
   OUTPUT;
RUN;
   
PROC PRINT;
   
   OBS    FONCTION         CHAINE                   RESULTAT
   
 1     normal        ABCDE   FGHIJ    ***     ABCDE   FGHIJ     ***
 2     compress      ABCDE   FGHIJ    ***ABCDEFGHIJ***             
 3     trim          ABCDE   FGHIJ    ***     ABCDE   FGHIJ***     
 4     left          ABCDE   FGHIJ    ***ABCDE   FGHIJ          ***
 5     right         ABCDE   FGHIJ    ***          ABCDE   FGHIJ***
 6     trim(left)    ABCDE   FGHIJ    ***ABCDE   FGHIJ***          

 

TRANSLATE(anum, t1, f1, ..., tn, fn) traduit dans la chaîne de caractère anum les caractères f par le caractère t correspondant. Attention, ordre inverse de ce qu'on ferait logiquement, d'abord le nouveau puis l'ancien !

TRANSLATE("     C'est la vie     ", "*", " ") => "****C'est la vie****"

UPCASE(anum) transforme tous les caractères de la chaîne de caractère anum en majuscules.

UPCASE("C'est la vie") => "C'EST LA VIE"

LOWCASE(anum) transforme tous les caractères de la chaîne de caractère anum en minuscules.

LOWCASE("C'est la vie") => "c'est la vie"

REVERSE(anum) renverse lo'rdre de tous les caractères de la chaîne de caractère anum.

REVERSE("C'est la vie") => "eiv al tse'C"

LENGTH(anum) donne la longueur de la chaîne de caractère anum en ignorant les caractères blancs à la fin de la chaîne.

LENGTH("C'est la vie    ") => 12

INDEX(anum, string) cherche dans la chaîne de caractère anum la position de la chaîne ou du caractère string.

INDEX("C'est la vie    ", "v") => 10
INDEX("C'est la vie    ", "z") => 0

INDEXC(anum, t1, ..., tn ) cherche dans la chaîne de caractère anum la position d'un des caractères t.

INDEXC("C'est la vie    ", "t", "l", "z") => 5

SUBSTR(anum, n, m) extrait dans la chaîne de caractère anum m caractères en commençant à la position n.

SUBSTR("C'est la vie", 7, 2) => "la"
SUBSTR("C'est la vie", 7) => "la vie" !

SCAN(anum, n) extrait dans la chaîne de caractère anum le nième mot séparé par des blancs.

SCAN("C'est la vie", 2) => "la"

SCAN(anum, n, car) extrait dans la chaîne de caractère anum le nième mot séparé par le délimiteur car.

SCAN("C'est_la_vie", 2, "_") => "la"

Les fonctions spéciales

LAG n (anum) restitue la valeur qu'avait l'argument à la n ième ligne précédente.

Si on dispose d'un data set avec une colonne de chiffres sur 5 lignes.

DATA; 
   INPUT x @@; 
   y = LAG1(x);
   z = LAG2(x);
   CARDS;
   1 2 3 4 5 6
;
PROC PRINT;
RUN;
OBS X Y Z
 1  1 . .
 2  2 1 .
 3  3 2 1
 4  4 3 2
 5  5 4 3
 6  6 5 4

DIF n (arg) fournit la valeur de la différence entre l'argument et la valeur qu'avait l'argument à la n ième ligne précédente.

y = DIF3(x) est égal à y = x - LAG3(x);

Les fonctions chronologiques

Les dates peuvent se gérer comme des chaînes de caractères mais on ne peut alors les classer dans un ordre chronologique. On peut répartir les jours, les mois et les années dans trois variables séparées mais se pose alors le problème du calcul des intervalles entre deux dates. SAS propose donc un format numérique spécial pour la gestion des dates. Ce format de type "date" est attribué lors de la lecture des variables avec un format de lecture spécial qui va traduire les informations "jour", "mois" et "année" sous la forme d'un nombre correspondant au nombre de jours écoulés depuis le 1er janvier 1960. La date est donc traduite en un nombre de jours qui peut alors être utilisé facilement pour calculer des intervalles, ordonner, ... Si on n'utilise pas de format de date particulier lors de l'impression, c'est d'ailleurs ce nombre de jours qui figurera sur les listings.

Il en existe de plusieurs sortes de format de lecture des dates :

DATEn. qui permet de lire une date représentée sous format alphanumérique

INPUT date1 DATE10.;
CARDS;
1JAN1982
01 JAN 82
1 JAN 82
1-JAN-82
;

est lu convenablement et traduit par la valeur 8036 pour les 4 lignes de la variable date1.

DDMMYYn. qui permet de lire une date représentée sous format numérique

INPUT date1 DDMMYY8.;
CARDS;
151082
15-10-82
15/10/82
;

est lu convenablement et traduit par la valeur 8323 pour les 3 lignes de la variable date1. Les formats MMDDYYn. et YYDDMMn. sont aussi disponibles.

Ces formats peuvent aussi être utilisé pour imprimer dans les listings ou dans les dates sauvées sous la forme d'un nombre de jours depuis le 1er janvier 1960. Par exemple,

 PUT date1 DATE5.   => 15OCT
 PUT date1 DATE6.   => 15OCT
 PUT date1 DATE7.   => 15OCT82
 PUT date1 DATE8.   => 15OCT82
 PUT date1 DATE9.   => 15OCT1982
 PUT date1 DDMMYY2. => 15
 PUT date1 DDMMYY8. => 15/10/82
 PUT date1 MMDDYY8. => 10/15/82 

Différentes fonctions chronologiques sont disponibles :

DATE() ou TODAY() donne la date du jour.

date1 = TODAY() => date1 =  15763 si on est le 27 février 2003.
TIME() donne l'heure du jour.
heure1 = time() => heure1 =  46024.94 si il est 12 h 47' 4.9410"

MDY(mois, jour, annee) transforme les informations d'une date stockée en trois variables en une nouvelle variable de type "date".

date1 = MDY( 8, 18, 1961) => date1 =   595.

DAY(date), MONTH (date) et YEAR(date) transforme les informations de date stockée en une variable de type "date" en trois nouvelles variables.

date1 = TODAY() => date1 =  15763 si on est le 27 février 2003.
jour = DAY(date1) => jour = 27
mois = MONTH(date1) => mois = 2
annee = YEAR (date1) => annee = 2003

HMS(heure, minute, seconde) transforme les informations d'une heure stockée en trois variables en une nouvelle variable de type "heure".

heure1 = HMS( 12, 18, 10.01) => heure1 =   44290.01

HOUR(heure), MINUTE (heure) et SECOND(heure) transforme les informations d'heure stockée en une variable de type "heure" en trois nouvelles variables.

heure1 = TIME() => heure1 =  46040.07 si il est 12 h 47' 20,07"
heure = HOUR(heure1) => heure = 12
jour = MINUTE(heure1) => minute = 47
seconde = SECOND(heure1) => seconde = 20.07

[Introduction] [Conventions SAS] [DATA step] [Fonctions] [Procédures de base]