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

Sum consecutive observations in a dataset SAS

我的数据集如下所示:

  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”的小时数。缺失值结束连续序列。

我应该怎么做?谢谢!

你必须做两件事:

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

对于使用隐式循环的情况

  • 每个 运行 长度的出现都可以计算并保存在保留的跟踪变量中,测试 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;

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

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;

另一种选择

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;

几周前,@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