LesezeichenAbonnierenRSS-Feed abonnieren
Katrin11
Calcite | Level 5

Hallo zusammen,

ich habe eine csv-Datei in SAS importiert, die in der ersten Spalte eine ID enthält und in den restlichen Spalten 4-stellige Zahlen-Codes.

Ich möchte die Datensätze angezeigt bekommen, in denen 4-stellige Zahlen-Codes mehrfach vorkommen.

Beispiel:

1;0002;1235;3468;4587;3952;6795;

2;0136;5976;3290;0554;4281;3942;

3;3594;4381;4753;3954;0002;4753;

Hier sollte mir im Ergebnis nur noch die 3. Zeile angezeigt werden, da diese den zahlen-Code "4753" mehrfach enthält.

Ich habe schon probiert, die Daten erst mit proc transpose zu transponieren. Allerdings komme ich nicht wirklich weiter, weil die Datei über eine Million Datensätze hat.

 

Vielen Dank vorab und viele Grüße

Katrin

 

5 ANTWORTEN 5
Kurt_Bremser
Super User

Bitte probier mal das:

data have;
infile datalines dlm=";";
input (id c1-c6) ($);
datalines4;
1;0002;1235;3468;4587;3952;6795;
2;0136;5976;3290;0554;4281;3942;
3;3594;4381;4753;3954;0002;4753;
;;;;

proc transpose data=have out=long (rename=(col1=code));
by id;
var c:;
run;

data want;
set long;
by id;
retain ind list;
length list $50.;
if first.id
then call missing(ind,list);
if index(list,strip(code)) then ind = 1;
list = catx(";",list,code);
if last.id and ind;
keep id;
run;

Ein transpose wide to long sollte eigentlich kein Problem darstellen.

Katrin11
Calcite | Level 5
Vielen Dank, das hat geklappt! Ich musste nur noch einen Zwischenschritt einfügen, weil in meinem Datensatz auch leere Spalten vorkommen können.
andreas_lds
Jade | Level 19

Ausnahmsweise mal eine Lösung ohne tranpose:

data have;
   length id $ 10 var1-var6 $ 4;
   infile datalines4 delimiter=';';
   input ID var1-var6;
   datalines4;
1;0002;1235;3468;4587;3952;6795
2;0136;5976;3290;0554;4281;3942
3;3594;4381;4753;3954;0002;4753
;;;;


data want;
   set have;

   length alle $ 40;

   array werte var:;

   alle = catx('|', of var:);

   do i = 1 to dim(werte)-1;
      if count(alle, trim(werte[i])) > 1 then do;
         output;
         leave;
      end;
   end;

   drop i alle;
run;
Spinner_Bernd
Calcite | Level 5

Hallo Katrin,

 

folgender Code sollte funktionieren, geht sicherlich noch eleganter.

 

data in;
infile datalines;
input id $ a $ b $ c $ d $ e $ f $;
datalines;
1 0002 1235 3468 4587 3952 6795
2 0136 5976 3290 0554 4281 3942
3 3594 4381 4753 3954 0002 4753
;
run;

data in2 ;
set in;
if 
a = b or 
a = c or
a = d or
a = e or
a = f or

b = a or 
b = c or
b = d or
b = e or
b = f or 

c = a or 
c = b or
c = d or
c = e or
c = f or 

d = a or 
d = b or
d = c or
d = e or
d = f or 

e = a or 
e = b or
e = c or
e = d or
e = f or 

f = a or 
f = b or
f = c or
f = d or
f = e ;
run; 

Viele Grüße

Bernd

FreelanceReinh
Jade | Level 19

Hallo @Katrin11,

 

mit einer Perl Regular Expression geht es auch:

data have;
infile cards dlm=';';
input ID (code1-code6)(:$4.);
cards4;
1;0002;1235;3468;4587;3952;6795;
2;0136;5976;3290;0554;4281;3942;
3;3594;4381;4753;3954;0002;4753;
;;;;

data want;
set have;
if prxmatch('/(\d{4}).+\1/',catx('#',of code:));
run;

Edit:

Erläuterung: Die CATX-Funktion verkettet die sechs Codes mit einem beliebig gewählten Trennzeichen, z. B. zu 3594#4381#4753#3954#0002#4753. Dann sucht die PRXMATCH-Funktion in diesem String nach vier aufeinanderfolgenden Ziffern (dafür steht "\d{4}"), nach denen mindestens ein weiteres Zeichen (".+") sowie erneut die zuvor gefundenen vier Ziffern ("\1") folgen. Da die Codes alle vierstellig sind, muss es sich bei dem zweiten "Treffer" ggf. um einen wiederholten Code handeln. Der Rückgabewert der PRXMATCH-Funktion ist dann die Zeichenposition des ersten der doppelten Codes, im Beispiel also 11 (allgemein: eine Zahl >0), und der betreffende Satz wird ausgegeben. Tritt kein Code doppelt auf, ist der Rückgabewert 0 und die IF-Bedingung damit nicht erfüllt, so dass der Satz nicht ausgegeben wird.