Retain als Ersatz für die LAG-Funktion im Data Step

Aus BI-Snippets - Business Intelligence Code und Module
Wechseln zu: Navigation, Suche

Für große Datensätze kann es sich im Data Step lohnen, auf die Verwendung der LAG1-Funktion zu verzichten und stattdessen mit dem Retain-Statement zu arbeiten. Dazu folgendes Beispiel:

/* Erstellen eines Testdatensatzes mit einer zufällig gefüllten numerischen Variablen  */

data testsatz (drop=it);
        length Var 8;
        format Var 8.2;
 
        do it = 1 to 10000000;
 
                Var = ranuni(0);
                output;
 
        end;
 
run;

/* Berechnung der Differenz zwischen dem Wert in einer Zeile und dem Wert in der vorigen Zeile ohne
   Verwendung der LAG-Funktion */

data test_ohne_lag (drop=_Var);
        retain _Var .;
        format Differenz 8.2;
        set testsatz;
 
        Differenz = Var-_Var;
 
        _Var = Var;
run;

/* Berechnung der Differenz zwischen dem Wert in einer Zeile und dem Wert in der vorigen Zeile unter
   Verwendung der LAG-Funktion */
 
data test_mit_lag;
        format Differenz 8.2;
        set testsatz;
 
        Differenz = Var-lag(Var);
run;

Die Verwendung des Data Steps ohne die LAG-Funktion ist hier schneller. Dies gilt aber offenbar lediglich, wenn man die LAG1-Funktion betrachtet.
Für LAGn mit n>1 ist die Verwendung von Retain-Statements langsamer. Das kann bei Interesse mit folgendem Makro überprüft werden, welches
die LAGn-Funktion für beliebiges n ersetzen kann. Allerdings ist die Ausführung des Makros erst für n>2 richtig sinnvoll.

/*********************************************************/
/*               ########### MAKRO ############          */
/*              ######### LAG_ERSATZ #########           */
/*                                                       */
/* n:   Das 'n' in LAGn. Also Angabe, auf wie            */
/*              viele Felder im Voraus zugegriffen       */
/*              werden soll. Funktioniert grundsätzlich  */
/*              für alle n > 0. Ist aber nur sinnvoll    */
/*              für n > 2.                               */
/*                                                       */
/* input_data: Angabe des Data Sets, in dem das          */
/*              numerische Feld enthalten ist, auf das   */
/*              die Funktion angewendet werden soll.     */
/*                                                       */
/* feld: Numerisches Feld, auf das die Funktion          */
/*              angewendet werden soll                   */
/*                                                       */
/* format: Numerisces Format, das das berechnete         */
/*              Differenzfeld haben soll.                */
/*********************************************************/
 
%macro lag_ersatz(n, input_data, feld, format);
 
data ohnelag&n. (drop =
            %do it = 1 %to &n.;
               _&feld.&it.
                                %end;
                 );
        retain
                %do it = 1 %to &n.;
                        _&feld.&it.
                                           %end;
                .;
        format Differenz &format.;
        set &input_data.;
 
        if mod(_N_,&n.) = 1 then do;
                Differenz = &feld.-_&feld.1;
                _&feld.1 = &feld.;
        end;
        %do it = 2 %to %eval(&n.-1);
 
                else if mod(_N_,&n.) = &it. then do;
                        Differenz = &feld.-_&feld.&it.;
                        _&feld.&it. = &feld.;
                end;
 
        %end;
        else do;
                Differenz = &feld.-_&feld.&n.;
                _&feld.&n. = &feld.;
        end;
run;
 
%mend lag_ersatz;