不同变量行之间的差异,避免宏方法

时间:2017-12-05 21:09:53

标签: sql sas

我试图找到两个进程之间的平均时间。每条记录都是一个修复过程,包括零件ID,开始日期和结束日期。对于给定的ID,一次只能进行一个修复过程。请参阅以下示例数据:

ID  START_DATE  END_DATE
123  1/2/2006   2/3/2006
124  1/3/2006   4/2/2006
123  3/5/2006   3/7/2006
123  6/2/2006   6/4/2006
123  6/8/2006   6/9/2006
124  6/2/2006   6/4/2006
124  6/5/2006   6/9/2006
124  6/10/2006   6/12/2006

我需要的信息是给定ID的END_DATE和START_DATE之间的差异。例如,对于ID 123,其第一个过程和第二个过程之间的时间是3/5/2006 - 2/3/2006。如果列表更长,我会采取所有这些差异并取其平均值。

输出将是这样的:

ID  AverageTime
123   4.3
124   2.3

我的方法是根据以下步骤创建一个宏:

  1. 创建唯一ID列表。
  2. 对于列表中的每个ID,创建表 只是那个ID。
  3. 计算START_DATE和之间的差异 END_DATE使用LAG函数获取该ID。
  4. 平均值 差异并附加到唯一ID列表。
  5. 我认为这样可行,但可能需要很长时间,因为有400k行。有没有办法在没有宏的情况下做到这一点?这个过程如何优化,因为我运行它的服务器非常慢?

4 个答案:

答案 0 :(得分:2)

您可以在数据步骤和PROC方式中执行此操作。 使用LAG()查找以前的值。你不能在这里使用DIF(),因为你正在查看不同的变量。

data middle_step;
set have;
by id;

lag_end = lag(end_date);
duration = start_date-lag_end;

if first.id then duration=.;

run;

proc means data=middle_step mean;
class id;
var duration;
run;

答案 1 :(得分:1)

以下是“SAS-y”的做法。

首先是您的数据:

data have;
input ID  START_DATE  END_DATE;
informat start_date end_date mmddyy10.;
format start_date end_date mmddyy10.;
datalines;
123  1/2/2006   2/3/2006
124  1/3/2006   4/2/2006
123  3/5/2006   3/7/2006
123  6/2/2006   6/4/2006
123  6/8/2006   6/9/2006
124  6/2/2006   6/4/2006
124  6/5/2006   6/9/2006
124  6/10/2006   6/12/2006
;

按ID和Start_Date排序:

proc sort data=have;
by id start_date;
run;

接下来为每个id添加一个记录计数,并为前一个id添加一个链接。

data tmp;
set have;
by id;
if first.id then 
    id_cnt = 0;

id_cnt + 1;
id_last = id_cnt-1;
run;

然后将数据连接到自身,取第一个结束和下一个开始之间的差异的平均值:

proc sql noprint;
create table want as
select a.id
     , mean(b.start_date - a.end_date) as ave
    from tmp as a,
         tmp as b
    where a.id=b.id and 
          a.id_cnt=b.id_last
    group by a.id;
quit;

答案 2 :(得分:1)

使用Dom的输入和排序,这个DOW循环将在一次通过中计算每个id的平均间隙:

... input ...
... sort ...

data want(keep=id gap_mean);
  do _n_ = 1 by 1 until (last.id);
    set have;
    by id;

    if prior_end then gap_sum = sum ( gap_sum, end_date - prior_end );
    prior_end = end_date;
  end;

  gap_mean = gap_sum / (_n_ - 1);  * number of gaps is the number of iterations less 1;
run;

注释的代码项目:

  • setby语句在圈内
  • 使用_n_跟踪循环迭代(方便 - 重用自动变量)
  • until (last.id)循环测试有效,因为每个组至少有一行,而标志设置在组的最后一行
  • gap_sum使用sum()计算,因此第一个差距可以干净地累积。
    • 备用... then gap_sum = gap_sum + end_date-prior_end有效,但会导致LOG显示NOTE: Missing values were generated as a result of performing an operation on missing values.
    • 备选... then gap_sum + (end_date - prior_date)无需使用NOTE,但+运算符会导致gap_sum被隐式保留,这意味着gap_sum必须在do之前显式重置{1}}
  • prior_end是下一个的手动延迟
  • 当一个组完成时,计算平均值并隐式输出
  • 当隐式循环返回顶部时,它将是下一组的开始。非保留变量将重置为缺失(。)重要性为gap_sumprior_end

答案 3 :(得分:0)

计算也可以在单个SQL查询中完成:

proc sql;
  create table want as
    select id,mean(dif) as mean_dif from(
       select a.id,min(b.start_date-a.end_date) as dif
       from have a,have b
       where a.id=b.id
         and a.end_date<b.start_date
       group by a.id,a.start_date)
    group by id;
run;

但是,如果重要的话,datastep解决方案可能会运行得更快。