LesezeichenAbonnierenRSS-Feed abonnieren
Katrin11
Calcite | Level 5

Hallo zusammen,

 

mein Datensatz sieht folgendermaßen aus:

 

Kennnummer

2541212354
215454865
1356898
35415sto54545
35415sto54545
35415sto54545
52s4121s21

 

Diese Variable ist alphanumerisch und kann bis zu 25 Stellen lang sein.

Die Kennnummer soll nun in ein 8-stelliges numerisches Feld umgewandelt werden. Dazu möchte ich die Datensätze von 1 an durchnummerieren. Da die gleiche Kennnummer mehrfach vorkommen kann, sollten diese natürlich die gleiche anonymisierte Kennnummer bekommen.

Das Ergebnis des Beispiels sollte so aussehen:

Kennnummer          AnonymeKennnnummer

2541212354                              1
215454865                                2
1356898                                    3
35415sto54545                         4
35415sto54545                         4
35415sto54545                         4
52s4121s21                              5

 

Vielen Dank für Eure Mühen im Voraus.

Viele Grüße

Katrin

15 ANTWORTEN 15
Patrick
Opal | Level 21

Sortiere den Datensatz nach Kennnummer.

Dann in einem data step benutze syntax wie:

.....
by kennnummer;
retain anonyme_kennnummer;
if first kennnummer then anonyme_kennnummer+1;
....

 

andreas_lds
Jade | Level 19

+1 Weil ich den Reply-Button verfehlt habe 😉

 

Wenn du die Daten nicht sortieren kannst/willst könnte auch dieses Problem mit einem Hash-Objekt oder einem Format gelöst werden.

 

data annonym;
   set basis;

   length AnonymeKennnnummer naechsteNr 8;
   retain naechsteNr 1;
   drop naechsteNr;

   if _n_ = 1 then do;
      declare hash h();
      h.defineKey('Kennnummer');
      h.defineData('AnonymeKennnnummer');
      h.defineDone();
   end;

   if h.find() ^= 0 then do;
      AnonymeKennnnummer = naechsteNr;
      naechsteNr = naechsteNr + 1;
      h.Add();
   end;
run;

Und, ja, ich würde eher den Vorschlag von @Patrick umsetzen.

Patrick
Opal | Level 21

@andreas_lds 

Und hier als eine Variante:

data annonym;
  set basis;
  length AnonymeKennnnummer 8;

  if _n_ = 1 then
    do;
      declare hash h();
      h.defineKey('Kennnummer');
      h.defineData('AnonymeKennnnummer');
      h.defineDone();
    end;

  if h.find() ^= 0 then
    do;
      AnonymeKennnnummer= h.num_items + 1;
      h.Add();
    end;
run;
Kurt_Bremser
Super User

Oder man baut ein Informat:

data have;
input kennnummer $25.;
datalines;
2541212354
215454865
1356898
35415sto54545
35415sto54545
35415sto54545
52s4121s21
;

proc sort
  data=have
  out=sorted (rename=(kennnummer=start))
  nodupkey
;
by kennnummer;
run;

data cntlin;
set sorted;
retain
  type 'I'
  fmtname 'kennnummer'
;
label = _N_;
run;

proc format cntlin=cntlin;
run;

data want;
set have;
anonym = input(kennnummer,kennnummer.);
run;

proc print data=want noobs;
run;

Ergebnis:

kennnummer       anonym

2541212354          3  
215454865           2  
1356898             1  
35415sto54545       4  
35415sto54545       4  
35415sto54545       4  
52s4121s21          5  
Christine2
Fluorite | Level 6

Hallo Katrin,

 

musst Du die anonyme Kennnummer nur einmalig vergeben oder öfter?

 

Wenn Du z.B. heute einen Satz mit Kennnummern bekommst und morgen einen neuen Satz mit Kennnummern bekommst, sollen dann die anonymisierten Kennnummern auch eindeutig sein?

 

Falls ja bietet es sich an, dass Du Dir die Übersetzungstabelle abspeicherst. Mit deiner Kennnummer kannst Du dann nachschauen, ob Du schon eine Übersetzung kennst und die liefern. Ansonsten zählst Du das Maximum um 1 hoch, trägst es in die Tabelle ein und lieferst das Ergebnis.

 

Sobald ich meinen Gedanken mal gecoded habe poste ich Dir auch das Beispiel hier.

 

Schönen Gruß

 

Christine

Christine2
Fluorite | Level 6

Beim Versuch das zu implementieren ist mir aufgefallen, dass es doch ein wenig komplizierter wird als im ersten Anlauf gedacht.

Von daher ignorier meinen Einwand falls Du nicht bei jedem Lauf das Gleiche Ergebnis brauchst.

Patrick
Opal | Level 21

@Christine2  schrieb:

Beim Versuch das zu implementieren ist mir aufgefallen, dass es doch ein wenig komplizierter wird als im ersten Anlauf gedacht.

Von daher ignorier meinen Einwand falls Du nicht bei jedem Lauf das Gleiche Ergebnis brauchst.


 

Nicht getestet sollte aber funktionieren fuer mehrfache Laeufe.

%macro uebersetzung(tabelle);
  %if (%eval(%sysfunc(exist(&tabelle, DATA)) eq 0) %then
    %do;
      /* if table does not exist  */
      data &tabelle;
        stop;
        set basis(keep=Kennnummer);
        length AnonymeKennnnummer 8;
        format AnonymeKennnnummer 32.;
      run;

    %end;
%mend;
%uebersetzung(work.AnonymeKennnnummern);

data annonym;

  set basis end=last;

  if _n_ = 1 then
    do;
      if 0 then set work.AnonymeKennnnummern;
      declare hash h(dataset:'work.AnonymeKennnnummern');
      h.defineKey('Kennnummer');
      h.defineData('AnonymeKennnnummer');
      h.defineDone();
    end;

  if h.find() ^= 0 then
    do;
      AnonymeKennnnummer= h.num_items + 1;
      h.Add();
    end;

  if last then
    h.output(dataset:'work.AnonymeKennnnummern');
run;
Christine2
Fluorite | Level 6

Ich merke immer wieder, dass ich Hashs noch mehr einsetzen sollte als bislang.

Danke

Christine

Patrick
Opal | Level 21

Mein klarer Favorit ist Maxim 52  Smiley (fröhlich)

Christine2
Fluorite | Level 6

Zur Vollständigkeit aber doch noch der Code, leider quick und dirty:

 

data have;
input kennnummer $25.;
datalines;
2541212354
215454865
1356898
35415sto54545
35415sto54545
35415sto54545
52s4121s21
;

data bekannt;
	length kennnummer $25 anonyme_id 8;
	stop;
run;

proc sort data=have out=have_tmp nodupkey;
	by kennnummer;
run;


proc sql;
	create table fehlen as 
	select a.kennnummer 
	from have_tmp a left join 
		   bekannt b
	on a.kennnummer = b.kennnummer and b.kennnummer = ' ';
quit;

data bekannt(drop= id_max);
	set bekannt (in=a)
			fehlen (in=b);
	retain id_max 0;
	if a then do;
		id_max = anonyme_id;
	end;
	if b then do;
		id_max +1;
		anonyme_id = id_max;
	end;
run;

data Daten_mit_Kennung(drop= rc);
	set have;

	if _N_ = 0 then 
		set bekannt;
	if _N_ = 1 then do;
		declare hash h(dataset:'bekannt');
		rc = h.defineKey('Kennnummer');
		rc = h.defineData('anonyme_id');
		rc = h.defineDone();
	end;

	rc = h.find();
run;
mfab
Quartz | Level 8

Hier stellt sich mir die Frage, inwieweit wirklich "anonymisiert" wird, bzw. werden soll.

Meiner Ansicht nach wird durch die Vergabe einer neuen Nummer lediglich pseudonymisiert.

Interessant wäre auch, wie der neue Wert weiter verwendet werden soll; also ob Lesbarkeit, Plattenplatz beim Speichern, Performance bei weiteren Joins, etc. eine Rolle spielt.

 

Ggf. reicht ansonsten einfach ein Hash (MD5, SHA256, ...)?!

 

 

data want;
set have;
pseudo_kennnummer = sha256(kennnummer);
/* format pseudo_kennnummer $hex64.; */
run;

😉

 

 

Kurt_Bremser
Super User

Die momentan beste und "deppensicherste" Methode ist es (IMO), eine UUID zu verwenden. Das braucht 16 Bytes Speicherplatz und sorgt mit ziemlicher Sicherheit (weil Kennzeichen des generierenden Computers eingearbeitet werden) für weltweite Eindeutigkeit.

Man kann aber auch in einer Zahl mit 8 Byte Timestamps mit Genauigkeit auf Mikrosekunden-Ebene speichern, das haben die Datenbanken vor der Einführung der UUID als Keys verwendet.

 

Wenn es um Platz geht, kann man aber einfach eine laufende Nummer verwenden, und die Länge der Variablen nach der erwarteten maximalen Anzahl wählen, das ist dann wohl am effizientesten.

mfab
Quartz | Level 8

Guter Hinweis mit der UUID!

So wie ich verstanden hatte, kommen die Kennnummern auch mehrfach im Dataset vor. Daher war mein Gedankengang, dass man mit einer Hash-Funktion ohne Sortierung in einem Dataset immer die gleiche Ergebnisvariable erhält. Da würde normalerweise auch ein Hash-Objekt ausreichen, allerdings liefert die Hash-Funktion auch bei weiteren Datasets mit der gleichen Kennnummer das gleiche Ergebnis ohne zusätzliche Verarbeitungsschritte.

Wie gesagt, kommt es aus meiner Sicht auf die weitere Verwendung an, welche Methode idealerweise gewählt wird.

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

Diskussionsstatistiken
  • 15 Antworten
  • 2895 Aufrufe
  • 4 Kudos
  • 7 in Unterhaltung