SAS9

Appariement de données sur une fenêtre temporelle glissante

Simon 5 views

L'un des défis classiques en manipulation de données (Data Management) est de croiser deux tables non pas sur une égalité stricte, mais sur une fenêtre temporelle relative.

Le scénario typique est le suivant : vous avez une table de référence contenant des dates d'événements clés (ex: date de bilan, date de campagne marketing) et une seconde table contenant un historique de transactions. L'objectif est de récupérer, pour chaque événement clé, toutes les transactions ayant eu lieu dans les 12 mois précédents.

Contrairement à une fusion classique (MERGE) qui exige des clés identiques, ce problème nécessite une jointure d'inégalité.

Le Scénario

Prenons deux jeux de données pour illustrer la problématique :

  1. Table de Référence (HAVE_BASE) : Contient les entreprises et leurs dates pivots. Notez que l'entreprise 'A' apparaît deux fois avec deux dates différentes.

  2. Table d'Événements (HAVE_EVENT) : Contient l'historique des résultats financiers (EPS) par entreprise à diverses dates.

L'objectif est d'extraire les lignes de la table EVENT où la date est comprise entre [Date de Référence - 12 mois] et [Date de Référence].

Préparation des données

Les dates étant souvent importées sous forme de chaînes de caractères (ex: "199701"), la première étape critique est de les convertir en véritables dates SAS© numériques pour permettre les calculs arithmétiques.

1DATA have_base;
2 INPUT company $ _date :$6. profit;
3 /* Conversion de 'YYYYMM' en date SAS (1er du mois) */
4 date = INPUT(_date !! '01', yymmdd8.);
5 FORMAT date monyy6.;
6 drop _date;
7 DATALINES;
8a 199701 5
9a 199606 9
10b 201404 6
11f 200004 78
12;
13RUN;
14 
15/* Même traitement pour la table historique */
16DATA have_event;
17 INPUT company $ _date :$6. EPS;
18 date = INPUT(_date !! '01', yymmdd8.);
19 FORMAT date monyy6.;
20 drop _date;
21 /* ... données ... */
22RUN;

Pourquoi l'étape DATA (Merge) n'est pas adaptée ?

Une tentative intuitive serait d'utiliser l'étape DATA avec une instruction MERGE. Cependant, MERGE apparie les lignes séquentiellement basées sur une égalité stricte des variables BY.

Si vous tentez de filtrer avec des conditions comme if date >= intnx('month', date_b, -12), cela échouera souvent dans les cas "Many-to-Many" (plusieurs dates de référence pour une même entreprise) car le pointeur de lecture SAS© ne peut pas "revenir en arrière" pour re-tester les lignes historiques pour la deuxième date de référence.

La Solution Optimale : PROC SQL

Le langage SQL est parfait pour ce cas car il génère un produit cartésien sur la clé de jointure (company), puis filtre les résultats selon la fenêtre temporelle. Cela permet à une même ligne d'événement d'être associée à plusieurs dates de référence si les fenêtres se chevauchent.

Le Code

La fonction clé ici est INTNX, qui permet de décaler une date d'un nombre précis d'intervalles (ici, -12 mois).

1PROC SQL;
2 create TABLE want as
3 select
4 base.company,
5 base.profit,
6 base.date as Date_Reference,
7 evt.EPS,
8 evt.date as Date_Evenement
9 from
10 have_base as base,
11 have_event as evt
12 where
13 /* 1. Jointure sur l'identifiant */
14 base.company = evt.company
15 AND
16 /* 2. Jointure sur la fenêtre temporelle :
17 La date de l'événement doit être entre (Date Ref - 12 mois) et (Date Ref) */
18 intnx('month', base.date, -12) <= evt.date <= base.date;
19QUIT;

Analyse de la clause WHERE

  1. base.company = evt.company : Indispensable. Sans cela, vous compareriez les dates de l'entreprise A avec celles de l'entreprise B.

  2. intnx('month', base.date, -12) : Calcule la borne inférieure de la fenêtre (la date située exactement 12 mois avant la date de référence).

  3. L'opérateur <= : L'encadrement Borne_Inf <= Date_Evt <= Borne_Sup est la méthode la plus efficace et lisible pour définir l'intervalle.

Résultat et Interprétation

Si l'entreprise 'A' a une date de référence en Janvier 1997 et une autre en Juin 1996 :

  • Le SQL traitera d'abord Janvier 1997 : Il cherchera tous les événements de 'A' entre Jan 96 et Jan 97.

  • Il traitera ensuite Juin 1996 : Il cherchera tous les événements de 'A' entre Juin 95 et Juin 96.

  • Si un événement a lieu en Mai 1996, il apparaîtra deux fois dans le résultat final (une fois associé à la référence de 97, une fois à celle de 96), ce qui est le comportement correct attendu pour une analyse de ce type.

Pour croiser des données sur des intervalles de temps (fenêtres glissantes) :

  • Privilégiez PROC SQL à l'étape DATA.

  • Assurez-vous que vos dates sont au format numérique.

  • Utilisez INTNX pour calculer dynamiquement les bornes de votre fenêtre temporelle dans la clause WHERE.