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

Ste*_*aus 1 sql sas datastep

我是 SAS 初学者,我很好奇以下任务是否可以像目前在我脑海中那样更简单地完成。

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

用户 - 日期 - 金钱

每个日历日(过去 4 年)的各种用户和日期。数据按 User ASC 和 Date 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
Run Code Online (Sandbox Code Playgroud)

我现在想计算货币的五天移动平均线。我从非常流行的 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;
Run Code Online (Sandbox Code Playgroud)

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

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

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

此致

Dmi*_*pin 5

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

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

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