2012-08-16 80 views
0

我有一個數據集,其中包含有關一系列食品的消耗量的信息,基本上是消耗的頻率,消耗的數量以及它是否爲食品你是否使用sazonally。此外,一些食物也有一種類型(例如,你正在消耗普通蘇打水或減肥蘇打水,例如)。每種食物都被命名爲「DIEA#」加上一個字母(F表示頻率,Q表示數量,S表示sazonality,T表示類型(如果需要))。數據集看起來像這樣。優化SAS中的代碼,重新計算基於其他變量的變量

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 respondants,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.*&parameter.*&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.*&parameter.*&RootItem.Q/&gramsref.); 
     RUN; 
    %END; 
%END; 

%MEND WithType; 

然後我套用apropriate宏的每一種食品(例如%WithType(食品= 1))

我其實是相當新的SAS語言,這是我的第二個月使用它,所以我想我可能會做我的代碼中冗餘或不最佳的東西。任何提示將非常感謝。提前致謝。

+0

我認爲你可能需要打破這個問題。很難找到時間篩選您提供的所有信息。分段運行代碼並找到需要很長時間的部分...然後發佈示例數據和緩慢的代碼......一旦我們可以運行代碼,效率低下將更容易診斷。這個問題實際上可能會變成多個問題......然後,在我發表評論之前,有人可能會有答案 – 2012-08-16 15:47:52

回答

1

這是部分anwswer我會嘗試和更新它,當我有更多的時間......

我認爲最好的辦法是使用hash tables的查找表,然後再處理所有的數據在通過數據集進行單個解析。這可能會將時間減少到1分鐘<。這意味着你可以避免使用宏變量。

或者......

1)考慮將索引添加到表中。

2)在我看來,這似乎也可能是使用SASFILE聲明的候選人。它將允許您將經常查詢的數據集加載到內存中,以便更快地訪問它們。

3)下面的代碼塊

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; 

可改爲:

PROC SQL NOPRINT; 

    SELECT Gramature, Grams_Ref INTO :gramature, :gramsref FROM dadosdie 
    WHERE VARF = "&RootItem.F" ; 

QUIT; 

這就要求1名中的數據的解析少。代碼中有幾個地方可以從中受益。

最後 - 如果您可以發佈日誌以運行1個食物項目,這可能有助於我們識別可能從優化中受益最多的部分。

+0

哇,非常感謝。我會嘗試這些併發布一些結果。 – Rub 2012-08-16 16:57:11

+0

+1善念......,希望是讓您能在1.5K代表羅布;) – sasfrog 2012-08-17 22:10:53

+0

大聲笑它確實這樣做了感謝=) – 2012-08-17 23:06:34