从变量

时间:2015-11-17 14:56:23

标签: loops date sas

我正在尝试循环一系列日期,以便在中间创建日期。这将以月为单位进行,始终显示相应月份的最后一天。给出了开始和结束日期(first_date和last_date),而last_date应始终指向上个月的结尾。

原始数据集如下所示:

customer id   first_date  last_date 
xy       135  01.01.2000  25.03.2005 
xy       247  19.03.2003  25.03.2005 
ab       387  01.06.2010  30.12.2012 
ab       128  01.05.2010  28.02.2011 
...

我的目标是建立一个如下所示的数据集:

customer id   date
xy       135  31.01.2000
xy       135  28.02.2000
...
xy       135  28.02.2005
xy       247  31.03.2003
xy       247  30.04.2003
...
xy       247  28.02.2005

我发现解决方案迭代几天非常简单(见下文),但我正在努力实施月度步骤和月末日期。

data want;
set have;
by customer id;
do day = first_date to last_date;
output;
end;
format day date9.;
run;

感谢您的帮助!!

4 个答案:

答案 0 :(得分:1)

首先,让我们获取一些数据:

data have;
  attrib customer length=$10 informat=$10.
        id         informat=best.
        first_date informat=ddmmyy10. format=ddmmyy10.
        last_date  informat=ddmmyy10. format=ddmmyy10.
        ;

  input customer $
        id
        first_date
        last_date 
        ;

datalines;
xy       135  01.01.2000  25.03.2005 
xy       247  19.03.2003  25.03.2005 
ab       387  01.06.2010  30.12.2012 
ab       128  01.05.2010  28.02.2011 
;
run;

intnx()功能将在这里得到拯救。我们将创建一个名为date的新变量,然后使用intnx函数返回该日期的月末。只要该日期小于结束日期,我们将继续将其输出到数据集,然后递增到下个月的末尾。

data want;
  format date ddmmyy10.;

  set have;

  date = intnx('month',first_date,0,'end');
  do while (date le last_date);
    output;
    date = intnx('month',date,1,'end');
  end;

  drop first_date last_date;
run;

答案 1 :(得分:1)

虽然我认为罗布的回答是正确的做法,但看看如何以你想要的方式做到这一点可能会有所帮助。

从这开始:

data want;
 set have;
 by customer id;
 do day = first_date to last_date;
  output;
 end;
 format day date9.;
run;

这会给你太多行,对吗?所以你需要做的是确定你在哪个月的哪个位置。有很多方法可以做到这一点。可以使用几个日期函数(如INTNX和INTCK)来告诉您您的位置;但最简单的方法是将month(date)month(date+1)进行比较。当它们不同时,你就是在一个月的最后一天!

data want;
  set have;
  by customer id notsorted;
  do day = first_date to last_date;
    if month(day) ne month(day+1) then output;
  end;
  format day date9.;
run;

(我添加了notsorted,因为Rob的示例数据没有排序,而且我很懒。在您的实际案例中可能不需要。)

我会注意到这可能不是你理想的解决方案 - 就速度而言,就数据步骤而言,Rob可能就是这样。这当然会每天迭代,而不是每月一次。

答案 2 :(得分:1)

如果您拥有上面创建的数据集(每天一行),则另一个选项是使用PROC EXPAND,如果您有ETS模块。这样的事情非常方便。

data intermediate;
  set have;
  by customer id notsorted;
  do day = first_date to last_date;
    output;
  end;
  format day date9.;
run;;;

这是您的日级数据。然后下面是PROC EXPAND语句,询问每月数据,最后对齐。 id day;标识时间序列变量,by customer id notsorted;是常规语句(哪些变量标识观察结果),notsorted因此它们不必相对于彼此有序

proc expand data=intermediate out=want from=day to=month align=end;
  id day;
  by customer id notsorted;
run;

这提供了一个与Rob和我的其他解决方案略有不同的解决方案,因为如果它不是在一个月末(并且确实将最后一行设置为),它确实为您提供了最后一行月底)。如果这是理想的,那很好,我们的解决方案可以很容易地适应这一点;如果不需要,你将不得不在之后删除它。

答案 3 :(得分:0)

您可以使用日期间隔函数通过简单的迭代DO循环执行此操作。从间隔数中减去一个,使其在上个月的最后一天结束。

data want ;
  set have ;
  do offset=0 to intck('month',first_date,last_date)-1;
    date=intnx('month',first_date,offset,'e');
    output;
  end;
  format date yymmdd10.;
run;