SAS 创建节日标志矩阵

SAS Create a matrix of holiday flags

我想要一个二进制标志矩阵,指示给定日期是否有假期,类似这样(但对于每个 SAS 认可的假期):

date        flag_BOXING   flag_CHRISTMAS   flag_...   flag_...
14DEC2014      0                0             0           0
15DEC2014      0                0             0           0
16DEC2014      0                0             0           0
17DEC2014      0                0             0           0
18DEC2014      0                0             0           0
19DEC2014      0                0             0           0
20DEC2014      0                0             0           0
21DEC2014      0                0             0           0
22DEC2014      0                0             0           0
23DEC2014      0                0             0           0
24DEC2014      0                0             0           0
25DEC2014      0                1             0           0
26DEC2014      1                0             0           0
27DEC2014      0                0             0           0
28DEC2014      0                0             0           0

我知道可能有一种更简单的方法可以做到这一点,但我想在继续我目前的尝试之前确认一下(这实际上不起作用......)。我正在考虑创建一个单独的列来引入实际假期的日期,然后如果该日期与特定行上的日期匹配,则标志变量变为 1。这样做的缺点是我必须这样做每个假期。此外,假日函数需要指定年份,因此我必须使用一些 if-elseif 逻辑来说明不同的年份(我的列表是几年的日期)。有没有一种简单的方法可以生成我想要的矩阵,或者这是最好的方法吗?

data test;
    length day ;
    input day $;
cards;
23DEC2014
24DEC2014
25DEC2014
26DEC2014
27DEC2014
28DEC2014
;
run;

data test(drop=BOXING CHRISTMAS);
    set test;
    BOXING=holiday('boxing', 2014);
    CHRISTMAS=holiday('christmas', 2014);
    format BOXING CHRISTMAS date9.;
    flag_BOXING=0;
    flag_CHRISTMAS=0;
    if upcase(day)=upcase(BOXING) then flag_BOXING=1;
    if upcase(day)=upcase(CHRISTMAS) then flag_CHRISTMAS=1;
run;

谢谢。

这是一个蛮力方法。如果您只需要特定日期,我会这样做,然后 merge/filter 以某种方式得到结果。请注意,数组需要对齐,假期名称和标志变量才能正常工作。 h_list 是感兴趣的假期列表,存储为临时数组,不会输出到最终数据集。

data want;
format date date9.;
array h_list(6) . _temporary_ ("newyear" "thanksgiving", "christmas", "easter", "mlk", "memorial");
array h_flag(6) flag_newyear flag_thanksgiving flag_christmas flag_easter flag_mlk flag_memorial;

date_start="01Jan2013"d;
date_end="31Dec2015"d;

do date=date_start to date_end;
year=year(date);

do i=1 to dim(h_list);
    h_flag(i)=0;
    if date=holiday(h_list(i), year) then h_flag(i)=1;
end;

output;
end;
run;

我们有一个宏可以做到这一点。只需指定要为其计算假期的日期范围,它就会显示 table,每个假期 1 行。

%holidays(iStartDt=%sysfunc(mdy(1,1,2007)), iEndDt=%sysfunc(today())+100);

您可以获取它创建的数据集并加入您现有的数据以获取您需要的字段。

这是宏:

/*****************************************************************************
**  PROGRAM: MACROS.HOLIDAYS.SAS
**
**  CREATES A DATASET CONTAINING A LIST OF PUBLIC HOLIDAYS
**  
**  PARAMETERS: 
**
******************************************************************************
**  HISTORY:
**  1.0 MODIFIED: 30-JUN-2010  BY:RP
**  - CREATED. 
*****************************************************************************/

%macro holidays(iStartDt=, iEndDt=);

  data holidays;
    attrib holiday_date format=date9.
           holiday_desc length=
           rule         length=
           ;

    yr_start = year(&iStartDt);
    yr_end   = year(&iEndDt);

    do yr_tmp=yr_start to yr_end;
      holiday_date = mdy(1,1,yr_tmp);
      holiday_desc = "New Years Day";
      rule         = "";
      output;
      holiday_date = mdy(7,4,yr_tmp);
      holiday_desc = "July 4th";
      rule         = "";
      output;
      holiday_date = mdy(11,11,yr_tmp);
      holiday_desc = "Veterans Day";
      rule         = "November 11";
      output;
      holiday_date = mdy(12,25,yr_tmp);
      holiday_desc = "Christmas Day";
      rule         = "";
      output;    

      **
      ** Martin Luther King Day    [3rd monday in Jan]
      *;
      cnt = 0;
      do tmp_date = mdy(1,1,yr_tmp) to mdy(2,1,yr_tmp);
        if weekday(tmp_date) eq 2 then do;
          cnt = cnt + 1;
          if cnt = 3 then do;
            leave;
          end;
        end;
      end;
      holiday_date = tmp_date;
      holiday_desc = "MLK Day";
      rule         = "3rd Monday in Jan";
      output;

      **
      ** Presidents Day [3rd monday in Feb]  
      *;
      cnt = 0;
      do tmp_date = mdy(2,1,yr_tmp) to mdy(3,1,yr_tmp);
        if weekday(tmp_date) eq 2 then do;
          cnt = cnt + 1;
          if cnt = 3 then do;
            leave;
          end;
        end;
      end;
      holiday_date = tmp_date;
      holiday_desc = "Presidents Day";
      rule         = "3rd Monday in Feb";
      output;

      **     
      ** Memorial Day [last monday in May]  
      *;
      cnt = 0;
      do tmp_date = mdy(6,1,yr_tmp)-1 to mdy(5,1,yr_tmp) by -1;
        if weekday(tmp_date) eq 2 then do;
          cnt = cnt + 1;
          if cnt = 1 then do;
            leave;
          end;
        end;
      end;
      holiday_date = tmp_date;
      holiday_desc = "Memorial Day";
      rule         = "Last monday in May";
      output;

      **
      ** Labor Day [1st monday in Sept]  
      *;
      cnt = 0;
      do tmp_date = mdy(9,1,yr_tmp) to mdy(10,1,yr_tmp);
        if weekday(tmp_date) eq 2 then do;
          cnt = cnt + 1;
          if cnt = 1 then do;
            leave;
          end;
        end;
      end;
      holiday_date = tmp_date;
      holiday_desc = "Labor Day";
      rule         = "1st monday in Sept";
      output;

      **
      ** Columbus Day [2nd monday in Oct]
      *;
      cnt = 0;
      do tmp_date = mdy(10,1,yr_tmp) to mdy(11,1,yr_tmp);
        if weekday(tmp_date) eq 2 then do;
          cnt = cnt + 1;
          if cnt = 2 then do;
            leave;
          end;
        end;
      end;
      holiday_date = tmp_date;
      holiday_desc = "Columbus Day";
      rule         = "2nd monday in Oct";
      output;

      ** 
      ** Thanksgiving Day  [4th thursday in Nov]
      *;
      cnt = 0;
      do tmp_date = mdy(11,1,yr_tmp) to mdy(12,1,yr_tmp);
        if weekday(tmp_date) eq 5 then do;
          cnt = cnt + 1;
          if cnt = 4 then do;
            leave;
          end;
        end;
      end;
      holiday_date = tmp_date;
      holiday_desc = "Thanksgiving Day";
      rule         = "4th thursday in Nov";
      output;

    end;

    keep holiday_date holiday_desc rule;

  run;

  proc sort data=holidays(where=(holiday_date between &iStartDt and &iEndDt));
    by holiday_date;
  run;

  **
  ** WHEN A HOLIDAY FALLS ON A NONWORKDAY -- SATURDAY OR SUNDAY -- THE HOLIDAY USUALLY IS OBSERVED 
  ** ON MONDAY (IF THE HOLIDAY FALLS ON SUNDAY) OR FRIDAY (IF THE HOLIDAY FALLS ON SATURDAY).
  *;
  data holidays;
    format adjusted_date date9.;
    length adjusted_downame downame ;
    set holidays;

    downame = upcase(cats(put(holiday_date, downame.)));
    if downame eq ("SATURDAY") then do;
      adjusted_date = holiday_date - 1;
    end;
    else if downame eq ("SUNDAY") then do;
      adjusted_date = holiday_date + 1;
    end;
    else do;
      adjusted_date = holiday_date;
    end;
    adjusted_downame = upcase(cats(put(adjusted_date, downame.)));

  run;
%mend;