SAS:如何过滤最接近月份最后一天的(多个)条目(每个月)

SAS: How can I filter for (multiple) entries which are closest to the last day of month (for each month)

我有一个很大的数据集,我想对每个月的日期条目最接近该月最后一天的所有行进行过滤。因此,最接近一个月最后一天的那一天可能有多个条目。

例如: 原始数据集

date          price       name
05-01-1995    1,2         abc
06-01-1995    1,5         def
07-01-1995    1,8         ghi
07-01-1995    1,7         mmm
04-02-1995    1,9         jkl
27-02-1995    2,1         mno

目标:

date          price       name
07-01-1995    1,8         ghi
07-01-1995    1,7         mmm
27-02-1995    2,1         mno

我有 2 个想法,但我无法在 SAS 的循环(用于遍历月份)中实现它。 1.idea:创建新列,指示当前月份的最后一天(intnx() 函数);然后筛选出最接近该月最后一天的所有条目:

date          price       name   last_day_of_month
05-01-1995    1,2         abc    31-01-1995
06-01-1995    1,5         def    31-01-1995
07-01-1995    1,8         ghi    31-01-1995
04-02-1995    1,9         jkl    28-02-1995
27-02-1995    2,1         mno    28-02-1995

2.idea:简单地过滤每个月具有最高日期的条目(可能使用 max 函数?!)

如果你能帮助我,我会很高兴,因为我习惯了普通的编程语言,刚开始使用 SAS 进行研究。

1) 创建一个新变量 periode = put(date,yymmn6.) /* 给你 yyyymm*/ 2) 按周期和日期对 table 进行排序 3) 现在 periode.last 逻辑将 select 您需要的每个周期的记录。

类似...

    data tab2;
      set your_table;
      periode = put(date,yymmn6.);
   run;

   proc sort data= tab2;
     by  periode date;
   run;

   data tab3;
    set tab2;
     by periode;
     if last.periode then output;
   run;

您可以使用两个名为 intnxintck 的 SAS 函数来实现 proc sql:

proc sql ;
create table want as
  select *, put(date,yymmn6.) as month, intck('days',date,intnx('month',date,0,'end')) as DaysToEnd 
  from have
  group by month
  having (DaysToEnd=min(DaysToEnd))
;quit ;

Intnx() 按时间间隔调整日期。在上面的例子中,使用的四个参数是:

  1. 你想要 add/subrate 间隔的大小 'step'。
  2. 被引用的日期
  3. 要进行多少间隔步骤
  4. 如何 'round' 步骤(例如将其四舍五入到结果 day/week/year 的 start/end/middle)

Intck() 简单计算两个日期之间的间隔步数

这将为您提供最接近月底的那一天的所有记录

proc sql 是解决这种情况的一种方法。我将分解您的原始要求,并在 sql.

中解释如何解释它们

由于您想 group 您的观察日期,您可以使用 having 子句过滤每个月的 max 日期。

data work.have;
input date DDMMYY10. price name $;
format date date9.;
datalines;
05-01-1995    1.2         abc
07-01-1995    1.8         ghi
06-01-1995    1.5         def
07-01-1995    1.7         mmm
04-02-1995    1.9         jkl
27-02-1995    2.1         mno
;

data work.want;
input date DDMMYY10. price name $;
format date date9.;
datalines;
07-01-1995    1.8         ghi
07-01-1995    1.7         mmm
27-02-1995    2.1         mno
;

proc sql ;
create table work.want as
  select *
    /*, max(date) as max_date format=date9.*/
    /*, intnx('month',date,0,'end') as monthend format=date9.*/
  from work.have
  group by intnx('month',date,0,'end')
  having max(date) = date
  order by date, name
;

如果取消注释,实际使用的过滤器会显示在输出中 table。

将需求与解决方案进行比较:

proc compare base=work.want compare=work.solution;

结果

NOTE: No unequal values were found. All values compared are exactly equal.

Another approach is by using proc rank;

data mid;
  retain yrmth date;
  set have;
  format date yymmddn8.;
  yrmth = put(date,yymmn6.);
run;

proc sort data = mid;
  by yrmth descending date;
run;

proc rank data = mid out = want descending  ties=low;
by yrmth;
var date;
ranks rankdt;
run;

data want1;
  set want;
  where rankdt = 1;
run;

HTH