Data Step

Comment extraire efficacement les dernières observations d'une table ?

Simon 12 vistas

Lors de l'exploration de données ou du débogage, il est fréquent de vouloir isoler uniquement la "fin" d'une table (dataset). Contrairement à l'option OBS=10 qui nous donne le début, récupérer les 10 dernières observations d'une table contenant $N$ lignes demande une approche plus réfléchie, surtout si la table est volumineuse.

Voici une compilation des meilleures méthodes issues de la communauté SAS©, classées par performance et cas d'usage.

Note :
L'approche naïve (Tri Décroissant)
La première idée qui vient souvent à l'esprit est de trier la table par ordre chronologique inverse et de prendre les premières lignes.
1PROC SORT DATA=MA_TABLE out=sorted_table;
2 BY descending date_variable;
3RUN;
4 
5DATA last_ten;
6 SET sorted_table (obs=10);
7RUN;
Verdict : À éviter sur les grosses tables.

Pourquoi ? Trier une table de millions de lignes consomme énormément de ressources CPU et I/O simplement pour lire 10 lignes. C'est inefficace.
Note :
L'approche arithmétique (NOBS et IF)
Une méthode beaucoup plus propre consiste à utiliser l'option NOBS dans l'instruction SET. Cette option stocke le nombre total d'observations dans une variable temporaire lors de la compilation, sans avoir à lire la table.
1DATA last_ten;
2 SET MA_TABLE nobs=total_obs;
3 /* On ne garde que si le numéro de ligne (_N_) est dans les 10 derniers */
4 IF _N_ > (total_obs - 10);
5RUN;
Verdict : Bon pour les tables de taille moyenne.

Pourquoi ? Bien que nous ne gardions que 10 lignes, SAS© doit quand même lire séquentiellement toute la table jusqu'à la fin pour tester la condition IF. Sur une table d'un milliard de lignes, cela sera lent.
Note :
L'approche haute performance (Accès Direct avec POINT=)
C'est la solution optimale recommandée par les experts. L'objectif est d'utiliser l'accès aléatoire (Direct Access) pour sauter directement à la fin du fichier sans lire le début.

On combine NOBS (pour connaître la fin) et POINT (pour aller à une ligne précise).
1DATA last_ten;
2 /* Boucle de la ligne N-9 jusqu'à la ligne N */
3 DO i = (total_obs - 9) to total_obs;
4 SET MA_TABLE nobs=total_obs point=i;
5 OUTPUT;
6 END;
7 stop; /* IMPORTANT : stop évite une boucle infinie avec l'instruction POINT */
8RUN;
Verdict : La meilleure performance.

Pourquoi ? SAS© ne lit que 10 lignes, même si la table en contient 100 millions. L'exécution est quasi-instantanée.

Note technique : L'instruction STOP est obligatoire car l'instruction SET avec POINT= ne rencontre jamais de marqueur de fin de fichier (End-of-File).
Note :
L'approche Macro (FIRSTOBS dynamique)
Une alternative intéressante consiste à calculer le point de départ dans une étape précédente, puis à utiliser l'option FIRSTOBS.
1/* Étape 1 : Calculer le point de départ */
2DATA _null_;
3 SET MA_TABLE nobs=n;
4 start_point = n - 9;
5 call symput('start_obs', start_point);
6RUN;
7 
8/* Étape 2 : Lire à partir de ce point */
9DATA last_ten;
10 SET MA_TABLE (firstobs=&start_obs);
11RUN;
Verdict : Fonctionnel mais verbeux. La méthode 3 reste supérieure car elle tient en une seule étape Data.

Points d'attention et Limitations

Pour conclure, voici quelques nuances techniques soulevées lors de la discussion :

  1. Vues et SGBD : Les méthodes utilisant NOBS et POINT= fonctionnent parfaitement sur les tables Base SAS© natives. Cependant, elles peuvent échouer sur des Vues (Views) ou des tables de bases de données externes (Oracle, SQL Server via SAS©/ACCESS) car ces moteurs ne connaissent pas toujours le nombre de lignes à l'avance ou ne supportent pas l'accès direct par numéro de ligne.

  2. La variable _N_ : Dans la méthode 3, vous pouvez utiliser la variable automatique _N_ comme compteur de boucle (au lieu de i).

    • Avantage : _N_ n'est pas écrite dans la table de sortie (pas besoin de DROP).

    • Inconvénient : Cela peut prêter à confusion pour les débutants, car _N_ désigne habituellement le nombre d'itérations de l'étape Data.

En résumé : Pour une table SAS© classique volumineuse, privilégiez toujours la Méthode 3 (POINT=).