我正在尝试循环一系列日期,以便在中间创建日期。这将以月为单位进行,始终显示相应月份的最后一天。给出了开始和结束日期(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;
感谢您的帮助!!
答案 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;