sas - 使用BY语句计算分组数据的移动平均值

时间:2013-12-02 19:56:14

标签: sql sas datastep

我是SAS初学者,我很好奇以下任务是否可以更加简单,因为它目前在我脑海中。

我在名为user_date_money的表中有以下(简化的)元数据:

用户 - 日期 - 金钱

每个日历日(过去4年)的各种用户和日期。数据按用户ASC和日期ASC排序,样本数据如下所示:

User  | Date     | Money
Anna   23.10.2013   5
Anna   24.10.2013   1
Anna   25.10.2013   12
      ....       
Aron   23.10.2013   5
Aron   24.10.2013   12
Aron   25.10.2013   4 
     ....
Zoe    23.10.2013   1
Zoe    24.10.2013   1
Zoe    25.10.2013   0

我现在想要计算Money的五天移动平均线。我开始使用非常受欢迎的apprach和lag()函数,如下所示:

data cma; 
set user_date_money;
if missing(money) then
do;
OBS = 0;
money = 0.0;
end;
else OBS = 1;
money5 = lag5(money);
OBS5= lag5(obs);
if missing(money5) then money5= 0.0;
if missing(obs5) then obs5= 0;

if _N_ = 1 then
do;
SUM = 0.0;
N = 0;
end;
else;
sum = sum + money-money5;
n = n + obs-obs5;
MEAN = sum / n ;
retain sum n;
run;

如您所见,如果数据步骤运行到新用户,则会出现此方法的问题。 Aron会从Anna获得一些滞后值,当然不应该发生。

现在我的问题:我很确定你可以通过添加一些额外的字段来处理用户切换,例如laggeduser,如果你注意到这样的开关,可以重置N,Sum和Mean变量,但是:

这可以通过更简单的方式完成吗?也许以任何方式使用BY Clause? 感谢您的想法和帮助!

祝你好运

4 个答案:

答案 0 :(得分:4)

我认为最简单的方法是使用PROC EXPAND:

PROC EXPAND data=user_date_money out=cma;
  ID date;
  BY user;
  CONVERT money=MEAN / transformin=(setmiss 0) transformout=(movave 5);
RUN;

正如John的评论中所提到的,记住缺失值(以及关于开始和结束观察)也很重要。我已经在代码中添加了SETMISS选项,因为您明确表示要“删除”缺失值,而不是忽略它们(默认的MOVAVE行为)。 如果你想为每个用户排除前4个观测值(因为它们没有足够的前期历史来计算移动平均值5),你可以在TRANSFORMOUT =()中使用选项'TRIMLEFT 4'。

答案 1 :(得分:1)

如果您确保对数据进行了排序,则可以使用firstlast命名变量来初始化您的新成员时的运行总计。这些和retain应该可以满足您的需求;我不认为lag()在这里真的需要。

答案 2 :(得分:1)

如果您的特殊需求足够简单,您可以使用PROC MEANS和多标签格式进行计算。

data mydata;
do id = 1 to 5;
  datevar = '01JAN2010'd-1;
  do month = 0 to 4;
    datevar=intnx('MONTH',datevar,1,'b');
    sales = floor(500*rand('normal',7))+1500;
    output;
  end;
end;
run;

proc format;
value movingavg (multilabel notsorted)
'01JAN2010'd-'31MAR2010'd = 'JAN-MAR 2010'
'01FEB2010'd-'30APR2010'd = 'FEB-APR 2010'
'01MAR2010'd-'31MAY2010'd = 'MAR-MAY 2010'
/* ... more of these ... */
;
quit;

proc means data=mydata;
class id datevar/mlf order=data;
types id*datevar;
format datevar movingavg.;
var sales;
run;

PROC FORMAT可以使用CNTLIN数据集以编程方式完成,有关详细信息,请参阅PROC FORMAT的SAS文档。

答案 3 :(得分:1)

是的,您可以按分组使用。首先,您将按用户和日期排序(如您所知)。

proc sort data=user_date_money;
    by user date;
run;

然后,使用by变量和计数器重做数据步骤。

data cma;
    set user_date_money;
    by user;

    length User_Recs 3
            Average 8;

    retain User_Recs;

    if First.User=1 then User_Recs=0;

    User_Recs=User_Recs+1;

    if User_Recs>4 then do;
        Average=(lag4(money)+lag3(money)+lag2(money)+lag1(money)+money)/5;
    end;

    drop User_Recs;
run;