Dynamische KEEP- oder DROP-Listen

Hallo,

folgende Frage scheint im Forum noch nicht diskutiert worden zu sein:

Ich habe ein Array x[500], wobei nur wenige Felder einen von 1000 abweichenden Wert haben. Am Schluss des DataSteps möchte ich nur diese Felder xi behalten, deren Inhalt < 1000 ist.
(Hintergrund ist übrigens, für den Export nach Excel nur solche Spalten zu behalten, die wirklich relevante Informationen enthalten.)

Es ist nun nicht schwierig, einen String mit der Liste aller Felder zu erzeugen, deren Inhalt

Hat das dataset eine oder

Hat das dataset eine oder mehrere Sätze?

So müsste es gehen:

So müsste es gehen:

options nosource mprint;
%let obs = 5;
%let len = 10;
%let value = 10;
%macro bla;
    data test; %
* hier wird das dataset generiert;
        
array d (&len);
        drop i j r;
        do J =
1 to &obs;
            do i =
1 to &len;
                r = ranuni(
1);

                if r <
0.95 then
                    d(I) = &value;
                else
                    d(I) = &value - i;
            end;
            output;
        end;

    proc print;

    data test; %
* hier wird die verarbeitung vorbereitet;
        
array d (&len) ;
        array f (&len) _temporary_ (
%do I = 1 %to &len; 0 %end;) ;
        set test end = End;
        do i =
1 to &len;
            f(i) = f(i) or d(i) < &value;
        end;
        do i =
1 to &len;
            f(i) = f(i) or d(i) < &value;
        end;
        if End then do i =
1 to &len;
            call symput(
'f' !! trim(left(put (i, best.))), compress(put(f(i), best.)));
        end;
    run;

    
%do I = 1 %to &len;
        
%put f&i = &&f&i;
    
%end;

    proc print;

    data test; %
* hier wird die verarbeitung durchgeführt;
        
set test (keep = %do I = 1 %to &len;
                                  
%if &&F&I %then D&I;
                              
%end;);
    run;

    proc print;
    run;
%mend;
%bla
options source ;

Vielen Dank, MWendel!

Vielen Dank, MWendel!

Das funktionierende Testbeispiel werde ich auf den Fall anwenden.
Eine Frage habe ich noch:
Ich verstehe nicht, was der zweite, völlig identische Aufruf der drei Zeilen

do i = 1 to &len;
    f(i) = f(i) or d(i) < &value;
end;

bewirken soll, da f(i) bei erfüllter Bedingung bereits nach dem ersten Durchlauf 1 ist.

Gruß
MM

Das war ein copy und

Das war ein copy und paste-Fehler.
Gruß,
M. Wendel

Mehrere Sätze

Das Dataset hat mehrere (9) Sätze.
Was ich zur Vereinfachung weggelassen hatte:
Ich habe vor, alle Beobachtungen durchzugehen und je Spalte ein Flag zu setzen, wenn irgendwo ein Wert

x[i] LT 1000
auftritt.

MM

Pardon! Fortsetzung

Leider ist mir beim Speichern der Rest des Beitrages abhanden gekommen. Also:

"Es ist nun nicht schwierig, einen String mit der Liste aller Felder zu erzeugen, deren Inhalt LT 1000 ist.

list = '';
DO i=1 TO 500;
    IF (x[i] LT
1000) THEN DO;
        list = catt(list,
' x',i);
    
END;
END;

Aber wie kann ich mit dieser Liste KEEP oder DROP steuern?
Verwende ich einen Makro, bereitet mir die Konkatenierung der Liste Schwierigkeiten (Einbringen des Laufindizes i).

Für einen Hinweis wäre ich dankbar.
Gruß

Meinhard Mende

Kein Problem mit call symput

Hallo,
unabhängig davon, dass weiter oben das eigentliche Problem schon gelöst ist, will ich trotzdem hier noch die Lösung (?) zu dem "kleinen" Problem "Verwende ich einen Makro, bereitet mir die Konkatenierung der Liste Schwierigkeiten (Einbringen des Laufindizes i)" aus dem Beitrag von MM Genepi, 14. August 2007, 16:51 beisteuern:
Einfach nach der DO-Schleife einen call SYMPUT machen und schon ist die Variablen-Liste 'da' um sie in einer keep-Liste einzusetzen:

DATA blalbla_out;
  
set blabla_in;
  
/* ..... */
  
list = '';
  
DO i=1 TO 500;
    
IF (x[i] LT 1000) THEN DO;
      list = catt(list,
' x',i);
    
END;
  
END;
  
call symput(KeepVars, compress(list)); /* compress eigenlich unnötig */
run;
%put INFO: KeepVars=&KeepVars.;  /* Kontroll-Ausgabe im log */
Die Lösung erscheint mir soooo einfach, dass ich befürchte ich habe irgendetwas falsch verstanden ....
Gruß
Hans Kneilmann, Schäfer Shop GmbH (SSI)

Den Wald vor Bäumen nicht gesehen ...

Vielen Dank, Hans Kneilmann!

Der Zusammenhang ist tatsächlich noch komplexer als im Beitrag dargestellt, da x hier doppelt indiziert ist.
(Das erschwert aber kaum die Listenerstellung, indem man den Index k aus i und j berechnet.)
Außerdem habe ich mich wohl davon "schocken" lassen, dass die Variablenliste erst im nächsten DataStep zur Verfügung steht, was aber auch kein Problem ist.
Ich danke nochmals, da solche Hinweise helfen, cleverer mit den gegebenen Mitteln umzugehen.

Gruß
Meinhard Mende

Macro-Var mit keep-Liste

Hallo,
statt in meinem Beispiel oben die Daten einzulesen und wieder auszugeben um die Macro-Variable zu erzeugen, also statt

DATA blalbla_out;
  
set blabla_in;
  
/* ..... */
run;
kann man auch die Macro-Variable mit den Namen für die keep-Liste in einem data _null_-Schritt erzeugen:
DATA _null_;
  
set blabla_in;
  
/* ..... */
  
list = '';
  
DO i=1 TO 500;
    
IF (x[i] LT 1000) THEN DO;
      list = catt(list,
' x',i);
    
END;
  
END;
  
call symput(KeepVars, compress(list)); /* compress eigentlich unnötig */
run;
%put INFO: KeepVars=&KeepVars.;  /* Kontroll-Ausgabe im log */
DATA blalbla_out;
  
set blabla_in(keep=&KeepVars.);
run;
Vorteil: Man bewegt nicht unnötig viele Daten.
Gruß
Hans Kneilmann, Schäfer Shop GmbH (SSI)

Einige Anregungen

Der Herr Kneilmann weiß natürlich, wie das geht, und hat diese kurze und knackige Lösung einfach hingeschrieben, ohne sie auszuprobieren.

Für diejenigen, die es selbst probieren wollen:

Die Variable list muss deklariert werden (z.B. LENGTH list $200;) bevor ihr ein Wert zugewiesen wird.

In Call symput muss man den Namen der Makrovariablen in Gänsefüßchen schreiben und das compress weglassen, denn es wirft die Leerzeichen zwischen den Variablennamen wieder raus. Also:
call symput ("KeepVars", list);

Aber interessant die Verwendung von catt. Die cat-Funktionen wären mal einen Artikel wert.

Vielen Dank für die Anregungen

Allen Teilnehmern herzlichen Dank für die Beiträge.
Es gibt immer wieder Tipps, die "das Leben mit SAS" leichter gestalten.

Freundliche Grüße und einen guten Tag
Meinhard Mende

Mea Culpa

Guten Morgen,
na klar!!
Macro-Namen im call symput immer in Gänsefüßchen und die compress-Funktion ist an der Stelle super-ober-hyper-falsch!!! :-\
Mea Culpa
Gruß
Hans Kneilmann, Schäfer Shop GmbH (SSI)

Hat das dataset einen oder

Hat das dataset einen oder mehrere Sätze?