LesezeichenAbonnierenRSS-Feed abonnieren
hs_do
Calcite | Level 5

Hallo zusammen!

 

Ich möchte ein Produkt bilden über mehrere Zeilen im Datensatz hinweg.

Sobald eine Zeile mit einer neuen id auftritt, soll neu gerechnet werden.

 

Eine Summe schaffe ich zu berechnen, aber wenn ich das + gegen ein * tausche, erhalte ich eine Fehlermeldung.

 

Hier ein kurzes Beispielprogramm (die fehlerhafte Produktberechnung ist auskommentiert):

 

data test;
input id wert;
cards;
1 3
1 5
1 7
2 1
2 2
2 3
2 4
3 5
3 5
3 5
run;

Proc sort data=test;
by id wert;
run;


data test2;
 set test;
 by id;
 if first.id then do;
 summe = 0;
 summe = summe + wert;
 *produkt = 1;
 *produkt = produkt * wert;
 end;
 else do;
 summe + wert;
 *produkt * wert;
 end;
run;

 

 

Habt ihr eine Idee für mich, wie ich das hinkriege?
Vielen Dank vorab für Eure Hilfe!

Harald

8 ANTWORTEN 8
AndreasMenrath
Pyrite | Level 9

Hallo Harald,

 

da du für die Multiplikation kein SUM Statement verwenden kannst, musst du die Variable produkt explizit per RETAIN Statement so deklarieren, dass ihr Wert über die Datensatziterationen erhalten bleibt.

 

Hier ein lauffähiges Beispiel:

 

data test2;
 set test;
 by id;
 retain produkt 0;
 if first.id then do;
   summe = 0;
   summe = summe + wert;
   produkt = 1; 
 end;
 else do;
   summe + wert;
 end;
 produkt = produkt * wert;
run;

Gruß,

Andreas

hs_do
Calcite | Level 5

Hallo Andreas,

 

vielen Dank für Deine schnelle Hilfe!

 

Gruß,

Harald

WolfgangHornung
Obsidian | Level 7

Hallo Harald,

 

summe+wert;

ist eine sogenannte SUM-Anweisung, die die Variable summe automatisch retained. Eine Entsprechende MAL-Anweisung gibt es leider nicht. Folgendermaßen funktioniert es:

 

 

data test2;
 set test;
 by id;
 retain produkt 1;
 if first.id then do;
  produkt = 1;
 end;
 produkt=produkt * wert;
run;

Wichtig dabei ist es die Variable produkt auf retain zu setzen, das bedeutet, dass der errechnete Wert beibehalten wird, bis er bei einem Gruppenwechsel (first.id) neu initialisiert wird.

 

 

Viele GRüße

Wolfgang

hs_do
Calcite | Level 5

Hallo Wolfgang,

 

vielen Dank für Deine schnelle Hilfe!

 

Gruß,

Harald

mariusg
Obsidian | Level 7

und zur Abwechslung mal etwas proc sql 😉

Marius

 

data test;
	input id wert;
	cards;
1 3
1 5
1 7
2 1
2 2
2 3
2 4
3 5
3 5
3 5
run;

proc sql;
	SELECT
		id,
		round
	(CASE
		WHEN MinVal = 0 THEN 0
		WHEN mod(Neg, 2) = 1 THEN -1 * EXP(ABSMult)
		ELSE EXP(ABSMult)
	END)
as Mult_Wert
	from(
		SELECT
			id, 
			SUM(log(ABS(ifn(wert=0, 0,wert)))) AS ABSMult,
			SUM(SIGN
		(CASE 
			WHEN wert < 0 THEN 1 
			ELSE 0 
		END)
			) AS Neg,
			MIN(ABS(wert)) AS MinVal
		FROM
			test
		GROUP BY
			id
			) test
	;
quit;
Dennis_V
Calcite | Level 5

Mit PROC SQL

 

DATA TEST;
  INPUT ID WERT;
  CARDS;
1 3
1 5
1 7
2 1
2 2
2 3
2 4
3 5
3 5
3 5
RUN;

PROC SQL;
  SELECT ID, 
         EXP(SUM(LOG(WERT))) AS PRODUKT
  FROM TEST
  GROUP BY ID;
QUIT;
mariusg
Obsidian | Level 7
Hi Dennis_V,

mal mit einem Wert von 0 getestet? 😉

Viele Grüße
Marius
FreelanceReinh
Jade | Level 19

Auch wenn man nur positive Eingangswerte zulässt, sollte m. E. ein ROUND um das Formelergebnis nicht fehlen. Es könnte ja sein, dass mit der Variable PRODUKT weitergearbeitet wird (z. B. if produkt<125 then ...). Dann stellen die möglichen Rundungsfehler ein Risiko dar. Schon im vorliegenden Zahlenbeispiel weichen 2 der 3 Ergebnisse vom erwarteten ganzzahligen Produkt ab (jedenfalls auf meinem Rechner).

 

Werden prinzipiell auch nicht ganzzahlige Eingangswerte zugelassen, ist bei der Wahl der Rundungseinheit auf die Größenordnung der erwarteten Ergebnisse zu achten. In vielen Fällen ähnlich dem vorliegenden Beispiel dürfte sich 10^-8 als Rundungseinheit eignen, also

ROUND(EXP(SUM(LOG(WERT))), 1E-8) AS PRODUKT

 

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
  • 8 Antworten
  • 4424 Aufrufe
  • 2 Kudos
  • 6 in Unterhaltung