【问题标题】:Generating Leads and lags for non-consecutive time periods in SAS在 SAS 中为非连续时间段生成领先和滞后
【发布时间】:2015-03-24 01:17:55
【问题描述】:

使用SAS 类似的数据集

Ob     x    year   pid  grp 
1    3.88   2001    1    a
2    2.88   2002    1    a 
3    0.13   2004    1    a 
4    3.70   2005    1    a 
5    1.30   2007    1    a 
6    0.95   2001    2    b 
7    1.79   2002    2    b 
8    1.59   2004    2    b 
9    1.29   2005    2    b 
10   0.96   2007    2    b 

我想买

Ob   x      year    pid grp grp   X_F1      XL1
1   3.88    2001    1   a    a   2.88        .
2   2.88    2002    1   a    a     .        3.88
3   0.13    2004    1   a    a    3.7        .
4   3.7     2005    1   a    a     .        0.13
5   1.3     2007    1   a    a     .         .
6   0.95    2001    2   b    b    1.79       .
7   1.79    2002    2   b    b     .        0.95
8   1.59    2004    2   b    b    1.29       .
9   1.29    2005    2   b    b     .        1.59
10  0.96    2007    2   b    b     .         .

在哪里用相同的pid 和每年t 观察,

  • x_F1x 在年份 t+1
  • 中的值
  • x_L1 是 x 在年份 t-1 中的值

在我的数据集中,并非所有pids 都有连续几年的观察结果。

我尝试使用expand proc

proc expand data=have out=want method=none;
    by pid; id year;
    convert x = x_F1 / transformout=(lead 1);
    convert x = x_F2 / transformout=(lead 2);
    convert x = x_F3 / transformout=(lead 3);
    convert x = x_L1 / transformout=(lag 1);
    convert x = x_L2 / transformout=(lag 2);
    convert x = x_L3 / transformout=(lag 3);
run;

没有考虑到年份不连续的事实。

【问题讨论】:

  • 如果您在调用 PROC EXPAND 之前扩展 have 数据集,以使其具有每个 pid-year 的记录(在适当的情况下缺少 x 值),会有帮助吗?
  • 我的数据集有超过 800 万个观察值,如果我想不出更好的方法,我会考虑。

标签: sql sas


【解决方案1】:

您可以坚持使用proc expand 将缺失的年份插入到您的数据中(使用extrapolate 语句)。我已将from 值设置为day,因为这是对天数的连续整数检查,它适用于您的数据,因为 YEAR 存储为整数而不是日期。

与其他答案一样,它需要 2 次数据传递,但我认为没有其他选择。

data have;
input x year pid grp $;
datalines;
3.88   2001    1    a
2.88   2002    1    a 
0.13   2004    1    a 
3.70   2005    1    a 
1.30   2007    1    a 
0.95   2001    2    b 
1.79   2002    2    b 
1.59   2004    2    b 
1.29   2005    2    b 
0.96   2007    2    b 
;
run;

proc expand data = have out = have1
    method=none extrapolate
    from=day to=day;
by pid;
id year;
run;

proc expand data=have1 out=want method=none;
    by pid; id year;
    convert x = x_F1 / transformout=(lead 1);
    convert x = x_F2 / transformout=(lead 2);
    convert x = x_F3 / transformout=(lead 3);
    convert x = x_L1 / transformout=(lag 1);
    convert x = x_L2 / transformout=(lag 2);
    convert x = x_L3 / transformout=(lag 3);
run;

或者这可以一次性完成,取决于 x 的值在最终数据集中是否重要(请参阅下面的评论)。

proc expand data=have1 out=want1 method=none extrapolate from=day to=day;
    by pid; id year;
    convert x = x_F1 / transformout=(lead 1);
    convert x = x_F2 / transformout=(lead 2);
    convert x = x_F3 / transformout=(lead 3);
    convert x = x_L1 / transformout=(lag 1);
    convert x = x_L2 / transformout=(lag 2);
    convert x = x_L3 / transformout=(lag 3);
run;

【讨论】:

  • 可以通过将to=day 添加到最后一个proc expand 来替换早期步骤,还是在缺失观测值的插补之前执行转换?我会测试但没有 SAS/ETS。
  • @Keith 它正在工作;我应该关注警告信息吗?
  • 回答@SRSwift,我没有尝试,因为我认为它不起作用。运行它后,您确实得到了 x_F1 - x_L3 的相同答案,但是 x 值存在差异。使用 2 步法,它在插入缺失年份时将 x 值设置为缺失,但是使用 1 步法,它将其设置为下一年的值!假设结果不需要 x 值,则 1 步方法有效。当然,SAS 可能仍在后台对数据进行 2 次读取!我会更新我的答案
  • @Duna,不,警告消息在这里无需担心,尽管它们是日志中不受欢迎的补充!
【解决方案2】:

这是使用proc sql 的简单方法。它将数据与自身连接两次;一次用于向前,一次用于向后滞后,然后在它们存在的地方取所需的值。

proc sql;
    create table want as
    select
        a.*,
        b.x as x_f1,
        c.x as x_l1
    from have as a
    left join have as b
        on a.pid = b.pid and a.year = b.year - 1
    left join have as c
        on a.pid = c.pid and a.year = c.year + 1
    order by 
        a.pid, 
        a.year;
run;

注意事项:

  • 如果滞后量较大,它不会很好地扩展。
  • 这可能不是最快的方法。
  • 它要求每个 pid year 对只有一个观察值,如果不是这种情况,则需要修改。

【讨论】:

  • ObSAS 中的行号我如何在代码中引用它
  • 数据已经按pid year 排序,每个pid year 对只有一个观察值。我是SAS的新手
  • proc sql 可以在处理过程中更改观察的顺序,因此您不能依赖它来维护输入顺序。它不能以简单的方式引用输入排序。但是,您可以使用order by a.pid, a.year 获得相同的结果,因为这将要求输出数据按这两个变量排序。我会更新答案以反映这一点。
【解决方案3】:
  1. 按组和每年对数据进行排序。
  2. 在数据步中计算 x_F1,具有滞后和如下条件:if (year and lag(year) are consecutive) then x_F1=lag(x)
  3. 以相反的方式对日期进行排序
  4. 类似地计算 x_L1。

我现在正在尝试为您编写一个有效的代码。 如果您向我提供数据样本(例如带有 infile 的数据步骤),我可以更好地尝试和测试它。

这似乎适用于我的数据:

/*1*/
proc sort data=WORK.QUERY_FOR_EPILABO_CLEAN_NODUP out=test1(where=(year<>1996)) nodupkey;
    by grp year;
run;

quit;

/*2*/
data test2;
    *retain x;
    set test1;
    by grp;
    x_L1=lag(x);
    if first.grp then
        x_L1=.;
    yeardif=dif(year);
    if (yeardif ne 1) then
        x_L1=.;
run;

/*3*/
proc sort data=test2(drop=yeardif) out=test3;
    by grp descending year;
run;

quit;

/*4*/
data test4;
    *retain x;
    set test3;
    by grp;
    x_F1=lag(x);
    if first.grp then
        x_F1=.;
    yeardif=dif(year);
    if (yeardif ne -1) then
        x_F1=.;
run;

【讨论】:

  • 在步骤 2 中 yeardif 未在组 grp 内执行。我在定义yeardif 之后添加了if first.grp then yeardif=. ;。它似乎正在工作。对吗?
  • 我看不出这个广告的价值。因为如果first.grp 那么x_L1=. 已经。添加这将使yeardif=. 至极使(yeardif ne 1) 为真,因此x_L1=. 再次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 2019-09-24
  • 1970-01-01
  • 1970-01-01
  • 2020-12-29
相关资源
最近更新 更多