在SAS中生成非连续时间段的潜在负载和滞后

时间:2015-03-23 13:45:18

标签: sql sas

使用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_F1是年x
  • t+1的值
  • x_L1是年t-1
  • 中x的值

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

我尝试使用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;

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

3 个答案:

答案 0 :(得分:3)

您可以坚持使用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;

答案 1 :(得分: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对只有一个观察值,如果不是这样,则需要修改。

答案 2 :(得分:1)

  1. 按组和每年对数据进行排序。
  2. 在数据步骤中计算x_F1,其滞后和条件如下:if (year and lag(year) are consecutive) then x_F1=lag(x)
  3. 以相反的方式对日期进行排序
  4. 同样地计算x_L1。
  5. 我现在正试着给你写一个正常工作的代码。 如果您向我提供数据样本(例如,带有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;