我是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? 感谢您的想法和帮助!
祝你好运
答案 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)
如果您确保对数据进行了排序,则可以使用first
和last
命名变量来初始化您的新成员时的运行总计。这些和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;