可以使用PROC FORMAT对许多列中的组进行求和吗?

时间:2018-10-10 16:53:37

标签: sas bigdata

我有一个约9亿行的数据集,每行代表3年内给定患者的索赔,每个索赔具有多达25个按变量排列的诊断代码,以及一个可转换代码的某些子集变成“慢性状况”。

像这样:

data claims;
   infile cards;
   input id $ type dg1 $ dg2 $ dg3 $ dg4 $ [...] dg25 $; 
   cards; 
A 40 A123 A234 B345 . [...] .
A 10 A234 . . . . [...] . 
B 40 C567 1234 Z4657 [...] . 
B 40 C567 1233 X4787 [...] . 
; 
run; 

data chrons;
infile cards; 
input chron nm $ code $ ;
cards; 
1 ckd A234
1 ckd C567
1 ckd 1233
2 copd B345
2 copd C233
3 diab A234
3 diab 1234
[...]
55 foo Z4657
55 foo X4787
;
run; 

为了确定条件是否为“慢性”,我必须计算出现条件的索赔(在任何DG中)的数量,不同条件下的最小索赔数量不同。

目前,我已经使用了一个非常笨拙的数据步骤来完成此操作,该步骤看起来或多或少像这样:

/* first a SQL loop that puts the codes into macros: */

%macro chron(start,end); 

    proc sql noprint; 
        %do k=&start. %to &end.; 
            select strip(catt("'",code,"'")) 
                into :chron&k. separated by ',' 
            where chron=&k. 
           from chrons; 
        %end;
    quit; 
 %mend; 
 %chron(1,55); 


/* then a double loop array for each of the 55 conditions in any of the 25 vars */

data claims_1yr;
 set claims;
    array dgc(25) dg1-dg25;
    array cond(55) cond1-cond55; 
do i=1 to 55; 
    do j=1 to 25; 
if cond(i) < 1 then do; 
    if dgc(j) in (&&chron&i.) then cond&i.=1; else cond&i.=0;
end;
end; 
run; 

后跟一些SQL总和,包括索偿数和基于索偿类型的其他条件等。其中某些条件具有特殊情况,例如具有代码列表,如果这些代码出现在任何dg {n}变量中,则构成索偿不计数,或者要求代码在前2个dg {n}空格内。

我想知道的是,是否存在一种更简单的方法来使用PROC FORMAT(我不太熟悉)和PROC MEANS或PROC Summary来获取摘要数据集,其中每个ID都有数量为针对每个条件提出索赔(无论代码位于哪个dg中)。就计算而言,循环数是残酷的。我上次运行它需要近48个小时才能完成。

一位同事建议:

%macro sl(st,end); 
proc sql; 
%do l=&st. %to &end.; 
    create table claims_&l as
     select distinct id, 
     sum(case when (dg1 in (&&chron&l.) or 
    dg2 in (&&chron&l.) or 
    dg3 in (&&chron&l.) or 
    dg4 in (&&chron&l.) [...] or 
    dg25 in (&&chron&l.) then 1 else 0 end) as  chron&l. 
    from claims group by id; 
 %end;
quit;    
 %mend; 
%sl(1,55); 

但这通常会在大约一个小时后导致段错误。

数据步并不是世界上最糟糕的事情,但是我想知道这个难题是否对任何人都熟悉,或者是否有一个明显的答案让我忽略了(可悲的是,使用SAS 9.3以外的其他方法是不可行的) 。

最后的目标是拥有一个看起来像这样的数据集:

ID   Cond   Claims
A    diab    2
A    copd    1  
A    ckd     2
B    diab    1
B    ckd     2
B    foo     2

ID  cond1   cond2  cond3  [...] cond55
A   2        1       2    [...]   0
B   2        0       1    [...]   2 

n.b。 档案中平均有70例患者索赔(有1300万例患者)。先前的研究表明,其中约40%患有至少一种慢性病,而其中一半(占总数的20%)患有一种以上慢性病。实际上,“具有”该条件是基于给定时间段内具有关联代码的最小数量的索赔(针对不同条件的最小最小值)。

谢谢!

3 个答案:

答案 0 :(得分:2)

这会在数组中使用“值”,并创建CONDn变量并按ID进行计数。

data claims;
   infile cards missover;
   input id $ type (dg1-dg5)($); 
   cards; 
A 40 A123 A234 B345
A 10 A234
B 40 C567 1234 Z4657
B 40 C567 1233 X4787
;;;; 
   run; 

data chrons;
   infile cards; 
   input chron nm $ code $;
   cards; 
1 ckd A234
1 ckd C567
1 ckd 1233
2 copd B345
2 copd C233
3 diab A234
3 diab 1234
;;;;
   run; 
filename FT77F001 temp;
data _null_;
   file FT77F001;
   set chrons;
   by chron nm;
   if first.chron then put +3 'Cond' chron '=' @;
   put code :$quote. 'in DG' @;
   if not last.chron then put ' or ' @;
   if last.chron then do;
      put ';' +3 'label Cond' chron '=' nm:$quote. ';';
      end;
   run;

data want1(keep=id cond:) / view=want1;
   set claims;
   array DG[*] dg:;
   %inc FT77F001 / source2;
   run;
proc summary data=want1 nway;
   class id;
   output out=want2(drop=_type_) sum(cond:)=;
   run;
proc print;
   run;

enter image description here

From SAS Log

答案 1 :(得分:0)

我将采用的方法是使用一个数据步骤将每个诊断代码的数据集转置为一行,并将“慢性病”格式应用于该列。然后,PROC TABULATE可能是您最好的选择,以获取每个ID的每个条件的诊断计数。最初的转置不会很快,但是它将使用数据步骤,因此即使它是一个大文件,它也可以工作,并且除非磁盘速度太慢,否则不会花费数小时。只需确保将输出数据集过滤为仅需要的三个变量即可-ID,diag。代码,我想输入吗?

您可以使用PROC FORMAT上的CNTLIN功能来导入您的慢性病。您至少需要:

  • START =输入格式(即诊断代码)
  • LABEL =格式(即慢性病)的输出
  • FMTNAME =任何您想命名的名称,用$表示字符
  • TYPE ='c'(字符)
  • 具有HLO ='o'和空标签或任何不匹配项的单行应折叠为(格式不匹配的“其他”)

然后proc format cntlin=[formatdataset]; run;将其导入。

答案 2 :(得分:0)

将所需的诊断频率表的内存需求视为哈希表。

900M索赔,平均每位患者70索赔,意味着约有1300万不同的患者

假设每位患者的10种慢性病的平均可怕程度。因此,您的目标(ID,条件,频率)的垂直数据布局形式中将有1.3亿行。

进一步假设内存中的哈希对象键+数据每行需要75个字节。因此,包含完整的所需垂直格式结果的哈希可能需要> =〜9G RAM。

因此您可以单次传递数据,进行诊断->条件映射计算频率。

通过基于IN的评估来映射(如从慢性病控制表生成的代码(按@数据 null ))可能是最快的解决方案之一。生成的代码可能会进一步优化-我的理解是,SAS数据步骤代码中的 OR 评估是完整路径评估,这意味着每个子句都已完成。例如

<condition-1> = (clause-1) OR (clause-2) … OR … (clause-k);
<condition-2> = (clause-1) OR (clause-m) … OR … (clause-n);

此外,子句1是一个映射器(或分类标准),被多个条件使用。您的实际控制数据可能具有不同的映射,这意味着单个诊断代码始终仅映射到一个条件。

无论如何,代码生成器都可以生成单个测试映射select语句

select 
  when (clause-1) do; condition1=1; end;
  when (clause-2) do; condition2=1; condition14=1; end; /* a non-distinct mapping in the control data */
  …
  when (clause-k) do; condition<p> = 1; end;
  otherwise condition_healthy = 1;
end;

根据data _null_的答案,(子句-k)应为("<some-code>" in DG)