对数据集SAS中的连续观测值求和

时间:2020-07-20 16:02:51

标签: sas retain

我有一个类似的数据集:

  Hour    Flag
    1       1
    2       1
    3       .
    4       1
    5       1
    6       .
    7       1
    8       1 
    9       1
    10      . 
    11      1
    12      1
    13      1
    14      1

我想要一个输出数据集,例如:

   Total_Hours   Count
        2          2
        3          1
        4          1

如您所见,我想计算每个周期中包含连续“ 1”的小时数。缺少值将终止连续序列。

我应该如何去做?谢谢!

4 个答案:

答案 0 :(得分:3)

您需要分两步执行此操作。第一步是确保数据正确排序并确定连续时间的小时数:

PROC SORT DATA = <your dataset>;
  BY hour;
RUN;

DATA work.consecutive_hours;
  SET <your dataset> END = lastrec;

  RETAIN
    total_hours 0
  ;

  IF flag = 1 THEN total_hours = total_hours + 1;
  ELSE
    DO;
      IF total_hours > 0 THEN output;
      total_hours = 0;
    END;
  /* Need to output last record */
  IF lastrec AND total_hours > 0 THEN output;

  KEEP 
    total_hours
  ;
RUN;

现在有一个简单的SQL语句:

PROC SQL;
  CREATE TABLE work.hour_summary AS
  SELECT
    total_hours
   ,COUNT(*) AS count
  FROM
    work.consecutive_hours
  GROUP BY
    total_hours
  ;
QUIT;

答案 1 :(得分:2)

您将必须做两件事:

  • 计算行程长度
  • 计算行程长度的频率

对于使用隐式循环的情况

  • 可以计算每个游程长度出现次数,并将其保留在一个保留的跟踪变量中,测试output的丢失值或数据结尾以及游程长度重置或增量的不丢失值。
  • 过程FREQ

另一种方法是对频率计数使用显式循环和哈希。

示例:

data have; input
Hour    Flag; datalines;
  1       1
  2       1
  3       .
  4       1
  5       1
  6       .
  7       1
  8       1
  9       1
  10      .
  11      1
  12      1
  13      1
  14      1
;

data _null_;
  declare hash counts(ordered:'a');
  counts.defineKey('length');
  counts.defineData('length', 'count');
  counts.defineDone();

  do until (end);
    set have end=end;

    if not missing(flag) then 
      length + 1;

    if missing(flag) or end then do;
      if length > 0 then do;
        if counts.find() eq 0 
          then count+1;
          else count=1;
        counts.replace();
        length = 0;
      end;
    end;
  end;

  counts.output(dataset:'want');
run;

答案 2 :(得分:1)

替代

data _null_;
   if _N_ = 1 then do;
      dcl hash h(ordered : "a");
      h.definekey("Total_Hours");
      h.definedata("Total_Hours", "Count");
      h.definedone();
   end;

   do Total_Hours = 1 by 1 until (last.Flag);
      set have end=lr;
      by Flag notsorted;
   end;

   Count = 1;

   if Flag then do;
      if h.find() = 0 then Count+1;
      h.replace();
   end;

   if lr then h.output(dataset : "want");
run;

答案 3 :(得分:1)

几个星期前,@ Richard教我如何使用DOW循环和直接寻址数组。今天,我给你。

data want(keep=Total_Hours Count);

  array bin[99]_temporary_;
  do until(eof1);
    set have end=eof1;
    if Flag then count + 1;
    if ^Flag or eof1 then do;
      bin[count] + 1;
      count = .;
    end;
  end;

  do i = 1 to dim(bin);
    Total_Hours = i;
    Count = bin[i];
    if Count then output;
  end;
run;

再次感谢理查德,他也建议我this article