我有一个数据集,其中包含有关一系列食品消费的信息,基本上是消费频率、消费数量以及它是否是您按时消费的食品。此外,一些食品也有一种类型(例如,您食用普通苏打水或无糖苏打水)。每个食品项目都被命名为“DIEA#”加上一个字母(F 表示频率,Q 表示数量,S 表示区域性,T 表示类型(如果需要))。数据集看起来像这样。
ID DIEA1F DIEA1Q DIEA1S DIEA1T DIEA2F DIEA2Q DIEA2S ...
1 3 20 0 1 1 10 0 ...
2 1 50 0 2 3 30 0 ...
3 5 10 1 2 1 15 0 ...
4 8 5 0 1 2 10 1 ...
... ... ... ... ... ... ... ... ...
在另一个数据集中,我有关于每种食物的营养信息,使用频率变量作为索引
VARF TYPE CALORIES FAT VIT.A VIT.B ...
DIEA1F 1 150 20 8 0 ...
DIEA1F 2 120 5 7 0 ...
DIEA2F . 50 0 3 25 ...
DIEA3F . 67 5 1 10 ...
... ... ... ... ... ...
所以,我有大约 15k 名受访者、114 种食品和每种食品的 160 个营养变量(如果该食品有不同的类型,则更多)。我需要的是根据食物消费数据计算每个人每种营养素的总消费量。我实际上解决了这个问题,但是,我认为我的解决方案太慢了。计算大约需要 5 个小时。
这是我的代码:
LIBNAME DIET "C:\Nutri\diet";
DATA diet.Test;
SET diet.qf2_die_100412;
/*here is a list of nutrition variables, and i set each one to zero (exemple CAL=0;)*/
RUN;
PROC IMPORT OUT= diet.dadosdie DATAFILE= "C:\Nutri\diet\nutrifacts.xls"
DBMS=xls REPLACE;
SHEET="plan1";
GETNAMES=YES;
RUN;
DATA dadosdie;
SET diet.Dadosdie;
RUN;
%MACRO cnt_list(list=);
%LET i = 1;
%DO %WHILE (%CMPRES(%SCAN(&list., &i.)) ne );
%LET item&i. = %CMPRES(%SCAN(&list., &i.));
%LET i = %EVAL((&i. + 1);
%END;
%*** STORE THE COUNT OF THE NUMBER OF ITEMS IN A MACRO VARIABLE: &CNTITEM;
%LET cntitem = %EVAL((&i. - 1);
&cntitem.
%MEND cnt_list;
%MACRO NoType(food=);
%LET RootItem=DIEA&food.;
DATA diet.test;
set diet.test;
if &RootItem.F = 1 then CONS_&RootItem.FPF = 3;
if &RootItem.F = 2 then CONS_&RootItem.FPF = 2.5;
if &RootItem.F = 3 then CONS_&RootItem.FPF = 1;
if &RootItem.F = 4 then CONS_&RootItem.FPF = 0.8;
if &RootItem.F = 5 then CONS_&RootItem.FPF = 0.4;
if &RootItem.F = 6 then CONS_&RootItem.FPF = 0.1;
if &RootItem.F = 7 then CONS_&RootItem.FPF = 0.07;
if &RootItem.F = 8 then CONS_&RootItem.FPF = 0;
RUN;
PROC SQL NOPRINT;
SELECT Gramature INTO :gramature FROM dadosdie
WHERE VARF = "&RootItem.F" ;
SELECT Grams_Ref INTO :gramsref FROM dadosdie
WHERE VARF = "&RootItem.F" ;
QUIT;
%LET listvarcomp= \* Here goes the same list of nutrition variables *\
%DO i=1 %TO %cnt_list(list=&listvarcomp.) ;
%LET measure=%scan(&listvarcomp.,&i.);
PROC SQL NOPRINT;
SELECT &measure. INTO :parameter FROM dadosdie
WHERE VARF = "&RootItem.F" ;
QUIT;
DATA diet.test;
set diet.test;
if &RootItem.Q ne . and &RootItem.Q ne .P and &RootItem.S ne 1
then &measure.= &measure. + (CONS_&RootItem.FPF*&gramature.*¶meter.*&RootItem.Q/&gramsref.);
RUN;
%END;
%MEND NoType;
%MACRO WithType(food=);
%LET RootItem=DIEA&food.;
DATA diet.test;
set diet.test;
if &RootItem.F = 1 then CONS_&RootItem.FPF = 3;
if &RootItem.F = 2 then CONS_&RootItem.FPF = 2.5;
if &RootItem.F = 3 then CONS_&RootItem.FPF = 1;
if &RootItem.F = 4 then CONS_&RootItem.FPF = 0.8;
if &RootItem.F = 5 then CONS_&RootItem.FPF = 0.4;
if &RootItem.F = 6 then CONS_&RootItem.FPF = 0.1;
if &RootItem.F = 7 then CONS_&RootItem.FPF = 0.07;
if &RootItem.F = 8 then CONS_&RootItem.FPF = 0;
RUN;
PROC SQL NOPRINT;
SELECT gramature INTO :gramature FROM dadosdie
WHERE VARF = "&RootItem.F" ;
SELECT Grams_Ref INTO :gramsref FROM dadosdie
WHERE VARF = "&RootItem.F" ;
SELECT COUNT(*) INTO :NOBStype FROM dadosdie
WHERE VARF = "&RootItem.F" ;
QUIT;
%LET listvarcomp= \* Here goes the same list of nutrition variables *\
%DO j=1 %TO &NOBStype. ;
%DO i=1 %TO %cnt_list(list=&listvarcomp.) ;
%LET measure=%scan(&listvarcomp.,&i.);
PROC SQL NOPRINT;
SELECT &measure. INTO :parameter FROM dadosdie
WHERE VARF = "&RootItem.F" AND TYPE = &j.;
QUIT;
DATA diet.test;
set diet.test;
if &RootItem.Q ne . and &RootItem.Q ne .P and &RootItem.S ne 1 and &RootItem.T = &j.
then &measure.= &measure. + (CONS_&RootItem.FPF*&gramature.*¶meter.*&RootItem.Q/&gramsref.);
RUN;
%END;
%END;
%MEND WithType;
然后我将适当的宏应用于每个食物项目(例如 %WithType(food=1))
我实际上对 SAS 语言相当陌生,这是我使用它的第二个月,所以我想我可能在我的代码中做了一些多余或不是最优的事情。任何提示将非常感谢。提前致谢。