使用 UPDATE 折叠观察时如何保留不在 BY 组中的变量的原始值

How to retain original value of variable not in BY group when using UPDATE to collapse observations

我有一份在特定日期进行医疗访问的人员名单,并且我已经将他们标记为进行特定诊断。现在我试图折叠这些标志以创建一个文件,每行有一个 person/one 日期。我找到了一个部分有效的解决方案,使用 UPDATE(在此处找到:SAS collapse dates)。然而,这会用某个人在特定日期的最后诊断代码覆盖标记的诊断代码。这是我的数据的简化版本:

data have;
input id id_date diag_code $ flag;
datalines;
1 1 a .
1 1 b 1
1 1 c .
1 2 d 1
1 2 e .
1 2 f 1
2 1 g .
2 1 h .
2 1 i 1
2 2 j 1
3 1 k . 
;
run;

data want;
    update have (obs=0) have;
    by id id_date;
run;

输出:

                        diag_
Obs    id    id_date    code     flag

 1      1       1         c        1  
 2      1       2         f        1  
 3      2       1         i        1  
 4      2       2         j        1 
 5      3       1         k        . 

我想得到的是:

                        diag_
Obs    id    id_date    code     flag

 1      1       1         b        1  
 2      1       2         d        1  
 3      2       1         i        1  
 4      2       2         j        1 
 5      3       1         k        . 

所以基本上,我想保留 diag_code 来自具有标志 = 1 的第一个观察结果。我已经尝试使用 RENAME 选项来防止覆盖变量,但是由于 UPDATE 首先读取具有 0 个观察值的数据集,(新的)原始变量出现但为空:

data want;
    update have (obs=0 rename=(diag_code=orig_diag_code)) have;
    by id id_date;
run;

                        orig_
                        diag_              diag_
Obs    id    id_date    code     flag      code

 1      1       1                  1       c  
 2      1       2                  1       f  
 3      2       1                  1       i  
 4      2       2                  1       j
 5      3       1                  .       k   

有什么想法吗?

编辑: 添加 where flag = 1 仍然错误地显示出现多个标志时的最后诊断,并且不会在标志丢失时产生日期观察:

data want;
    update have (obs=0) have;
    by id id_date;
    where flag=1;
run;

                        diag_
Obs    id    id_date    code     flag

 1      1       1         b        1  
 2      1       2         f        1  
 3      2       1         i        1  
 4      2       2         j        1  

您需要将 DIAG_CODE 变量移开,这样它就不会被 UPDATE 语句更新。您需要创建一个新变量来保留在第一个 FLAG=1 记录中找到的值。然后re-assign右值返回DIAG_CODE.

data want;
  update have (obs=0) have(rename=(diag_code=diag_code_orig));
  by id id_date;
  if 0 then keep_diag=diag_code ;
  retain keep_diag ;
  if first.id_date then call missing(keep_diag);
  if flag=1 then keep_diag=coalescec(keep_diag,diag_code_orig);
  diag_code=coalescec(keep_diag,diag_code_orig);
  drop keep_diag diag_code_orig;
run;

您可以改为 re-merge 第二步中第一个 FLAG=1 记录的 DIAG_CODE 值。

data want ;
  update have(obs=0) have;
  by id id_date;
run;

data want ;
  merge want
        have(keep=id id_date diag_code flag rename=(flag=xflag)
             where=(xflag=1 and not missing(diag_code)))
  ;
  by id id_date;
  if first.id_date;
  drop xflag;
run;

可以使用标志(或状态维护)变量选择满足某些条件的组中的第一行。

这里有两种方法:

  • DOW 遍历组,不需要retainfirst.
  • 只有 retainfirst.last.
  • 的隐式循环

代码:

* DOW over group with last., no retain or first.;
data want;
  do _n_ = 1 by 1 until (last.id_date);
    set have;
    by id id_date;
    if flag and not flagged then do;
      output;
      flagged = _n_;
    end;
  end;
  if not flagged then output;

  drop flagged;
run;

* Only implicit loop with retain, first. and last.;
data want;
  retain flagged;
  drop flagged;

  set have;
  by id id_date;

  if first.id_date then flagged = .;

  if flag and not flagged then do;
    flagged = 1;
    output;
  end;

  if last.id_date and not flagged then
    output;
run;