【问题标题】:How to count the maximum number of consecutive values in SAS如何计算SAS中连续值的最大数量
【发布时间】:2021-02-14 20:00:24
【问题描述】:

我有一个数据集,每个患者有一行,它包含有关患者服用 11 剂药物的日期(格式为 SAS 日期)的信息。在数据集中,每天最多服用一剂药物。患者可以填充 1 到 11 剂之间的任何日期,并且没有缺少信息的中间剂量(例如,如果填充了 Dose5,则根据定义填充了 Dose1-Dose4)。我有兴趣获得患者服用一剂药物的最大连续天数。 这里有 5 行示例数据。

data have;
    input PATIENT_ID Dose1 :ddmmyy10. Dose2 :ddmmyy10. Dose3 :ddmmyy10. Dose4 :ddmmyy10. Dose5 :ddmmyy10. Dose6 :ddmmyy10. Dose7 :ddmmyy10. Dose8 :ddmmyy10. Dose9 :ddmmyy10. Dose10 :ddmmyy10. Dose11;
    format Dose1 Dose2 Dose3 Dose4 Dose5 Dose6 Dose7 Dose8 Dose9 Dose10 Dose11 ddmmyy10.;
    cards;
          1          01/01/2020 01/02/2020 01/03/2020 01/04/2020 01/05/2020 01/06/2020 01/07/20  1/08/2020 01/09/2020 01/10/2020 01/11/2020
          2          01/01/2020 01/02/2020 01/03/2020 01/05/2020 01/06/2020
          3          01/02/2020 01/04/2020 01/06/2020 01/08/2020 01/10/2020 01/12/2020 01/14/2020 01/16/2020 01/18/2020
          4          01/03/2020 01/04/2020 01/05/2020 01/06/2020 01/07/2020 01/08/2020 01/09/2020  1/10/2020 01/12/2020 01/13/2020
          5          01/01/2020 01/07/2020 01/08/2020 01/10/2020
;
run;

我想获取变量 MAX_CONSECUTIVE_DAYS:

data want;
    input PATIENT_ID MAX_CONSECUTIVE_DAYS Dose1 :ddmmyy10. Dose2 :ddmmyy10. Dose3 :ddmmyy10. Dose4 :ddmmyy10. Dose5 :ddmmyy10. Dose6 :ddmmyy10. Dose7 :ddmmyy10. Dose8 :ddmmyy10. Dose9 :ddmmyy10. Dose10 :ddmmyy10. Dose11;
    format Dose1 Dose2 Dose3 Dose4 Dose5 Dose6 Dose7 Dose8 Dose9 Dose10 Dose11 ddmmyy10.;
    cards;
          1          11                  01/01/2020 01/02/2020 01/03/2020 01/04/2020 01/05/2020 01/06/2020 01/07/20  1/08/2020 01/09/2020 01/10/2020 01/11/2020
          2          3                   01/01/2020 01/02/2020 01/03/2020 01/05/2020 01/06/2020              
          3          1                   01/02/2020 01/04/2020 01/06/2020 01/08/2020 01/10/2020 01/12/2020 01/14/2020 01/16/2020 01/18/2020
          4          8                   01/03/2020 01/04/2020 01/05/2020 01/06/2020 01/07/2020 01/08/2020 01/09/2020  1/10/2020 01/12/2020 01/13/2020
          5          2                   01/01/2020 01/07/2020 01/08/2020 01/10/2020
run;

到目前为止,我只能通过蛮力零碎地弄清楚如何做到这一点。

data bruteforce;
    set have;
    if Dose2 =. then MAX_CONSECUTIVE_DAYS=1;
      else if Dose3=. then
      do;
        if Dose2-Dose1=1 then MAX_CONSECUTIVE_DAYS=2;
          else MAX_CONSECUTIVE_DAYS=1;
      end;
      else if Dose4=. then
      do;
        if Dose3-Dose1=2 then MAX_CONSECUTIVE_DAYS=3;
          else if (Dose2-Dose1=1) or (Dose3-Dose2=1) then MAX_CONSECUTIVE_DAYS=2;
          else MAX_CONSECUTIVE_DAYS=1;
      end;
      else if Dose5=. then
      do;
        if Dose4-Dose1=3 then MAX_CONSECUTIVE_DAYS=4;
          else if (Dose3-Dose1=2) or (Dose4-Dose2=2) then MAX_CONSECUTIVE_DAYS=3;
          else if (Dose2-Dose1=1) or (Dose3-Dose2=1) or (Dose4-Dose3=1) then MAX_CONSECUTIVE_DAYS=2;
          else MAX_CONSECUTIVE_DAYS=1;
      end;
     /*And so on and so forth until accounting for rows where Dose10 is populated*/
 run;

但是,在我的实际工作中,有超过 200 剂的药物,因此使用 if-then-else 语句进行一系列 do 循环是没有意义的。如果我不得不猜测,解决方案可能与数组有关,但我不确定从哪里或如何开始。

【问题讨论】:

    标签: arrays count sas


    【解决方案1】:

    首先,感谢您清楚地解释您的问题以及您到目前为止所做的尝试:-)

    只是一个注释。我将您的输入数据更改为具有 mmddyy10 信息/格式的日期。我想你想要的是连续计算几天而不是几个月。

    不管怎样,试试这个。欢迎询问

    data have;
    infile datalines missover;
    input PATIENT_ID (Dose1 - Dose11)(:mmddyy10.);
    format Dose: mmddyy10.;
    cards;
    1 01/01/2020 01/02/2020 01/03/2020 01/04/2020 01/05/2020 01/06/2020 01/07/2020 1/08/2020 01/09/2020 01/10/2020 01/11/2020
    2 01/01/2020 01/02/2020 01/03/2020 01/05/2020 01/06/2020
    3 01/02/2020 01/04/2020 01/06/2020 01/08/2020 01/10/2020 01/12/2020 01/14/2020 01/16/2020 01/18/2020
    4 01/03/2020 01/04/2020 01/05/2020 01/06/2020 01/07/2020 01/08/2020 01/09/2020 1/10/2020 01/12/2020 01/13/2020
    5 01/01/2020 01/07/2020 01/08/2020 01/10/2020
    ;
    
    data want(drop=c i);
       set have;
       array dose {*} Dose:;
       c = 1;
       do i = 2 to dim(dose);
          if dose[i] - dose[i-1] = 1 then c + 1;
          else do;
             if c > mc then mc = c;
             c = 1;
          end;
       end;
       if mc = . then mc = c;
    run;
    

    结果:

    PATIENT_ID Dose1...Dose11 mc 
    1 ... 11 
    2 ... 3 
    3 ... 1 
    4 ... 8 
    5 ... 2 
    

    【讨论】:

    • 这太好了,谢谢!你能解释一下数组是如何与这些代码行一起工作的吗(对于格式不佳的道歉,我无法弄清楚如何在评论中获得换行符):@ 987654323@ SAS 用来迭代以获取值的逻辑是什么MC>1?
    • 逻辑是这样的:1)测试两个日期之间是否正好有1天。 2) 如果有,将 c 加 1。如果没有,我们有一个“休息”。因此,我们将 c 设置回 1。此外,测试 c 是否大于当前的“最长连续”(mc)。
    【解决方案2】:

    正确,基于变量 array 将允许您迭代日期并计算最长的运行时间。

    提示:尽可能使用变量名作为值内容的指示。 dose<n> 比 dose_date<n> 提供的信息更少 meta

    稳健的计算将检查或考虑边缘情况,例如没有剂量。

    示例代码:

    从数组中提取值的 CPU 开销很小(也许可以忽略不计)。假设数组被命名为x。循环内的计算 x[index]-x[index-1] 重复了这样的成本。
    例如:x[5]−[x4] 和 x[6]−x[5]。将提取的值存储在变量中将减少重复成本。

    数据集选项keep= 是要输出的变量的显式列表。或者,drop=_: 可用于排除名称以 _ 开头的工作变量(在此示例中)。

    data have;
    infile datalines missover; input 
    ID X1-X11; format _numeric_ 4.; datalines;
    1 01 02 03 04 05 06 07 08 09 10 11
    2 01 02 03 05 06
    3 02 04 06 08 10 12 14 16 18
    4 03 04 05 06 07 08 09 10 12 13
    5 01 07 08 10
    6 01
    7
    8 01 03 05 07 09 11 13 15 17 19 21
    ;
    
    data want(keep=id x: rl_max);
      set have;
      array X X:;
    
      if not missing(x1) then _rl = 1;  /* preset if not an edge case */
      _p = x1;
    
      rl_max = _rl;
    
      do _index = 2 to dim(X);
        _q = X[_index]; /* store extracted value in worker variable */
        if missing(_q) then leave; /* iterate as little as needed */
         
        if _q - _p = 1 then /* consecutive */
          _rl = sum (_rl, 1);
        else do; /* gap, check and reset */
          if _rl > rl_max then rl_max = _rl;
          _rl = 1;
        end;
    
        _p = _q;  /* current to previous */
      end;
    
      if _rl > rl_max then rl_max = _rl;   /* no gaps */
    run;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-11
      • 2020-03-05
      • 2021-02-21
      • 2018-12-18
      • 2019-04-30
      • 2022-11-24
      • 2013-09-17
      相关资源
      最近更新 更多