首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >SAS:最有效的跨多列输出的方法

SAS:最有效的跨多列输出的方法
EN

Stack Overflow用户
提问于 2017-07-25 19:02:25
回答 1查看 1.7K关注 0票数 0

我拥有的数据是数以百万计的行,并且非常稀疏,需要处理的变量在3到10个之间。我的最终结果需要是一个一行,其中包含每个列的第一个不缺少的值。获取以下测试数据:

代码语言:javascript
运行
复制
** test data **;
data test;
    length ID $5 AID 8 TYPE $5;
    input ID $ AID TYPE $;
    datalines;
    A   .   .
    .   123 .
    C   .   XYZ
    ;
run;

最终的结果应该是这样的:

代码语言:javascript
运行
复制
ID  AID TYPE
A   123 XYZ

使用宏列表和循环,我可以使用多个合并语句强制执行这个结果,在这些语句中变量是不缺少的,并且是obs=1,但是当数据非常大时(下面我会循环这些变量而不是编写多个merge语句):

代码语言:javascript
运行
复制
** works but takes too long on big data **;
data one_row;
    merge 
        test(keep=ID where=(ID ne "") obs=1) /* character */
        test(keep=AID where=(AID ne .) obs=1) /* numeric */
        test(keep=TYPE where=(TYPE ne "") obs=1); /* character */
run;

coalesce函数看起来很有希望,但是我相信我需要它与arrayoutput结合来构建这个单行结果。函数也不同(coalescecoalescec取决于变量类型),但是使用proc sql并不重要。使用array时出错,因为数组列表中的所有变量都不是相同的类型。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-07-25 19:56:37

确切地说,什么是最有效的将在很大程度上取决于您的数据特征。特别是,最后一个变量的第一个不缺少的值在数据集中通常是相对“早期”的,或者如果您通常需要遍历整个数据集才能到达它。

我假设您的数据集没有索引(因为这将大大简化事情)。

一个选项是标准数据步骤。这不一定是快速的,但它可能不会比大多数其他选项慢得多,因为无论您做什么,都必须读取大部分/所有行。这有一个很好的优点,当每一行都完成时,它可以停止。

代码语言:javascript
运行
复制
data want;
  if 0 then set test; *defines characteristics;
  set test(rename=(id=_id aid=_aid type=_type)) end=eof;  
  id=coalescec(id,_id);
  aid=coalesce(aid,_aid);
  type=coalescec(type,_type);
  if cmiss(of id aid type)=0 then do;
    output;
    stop;
  end;
  else if eof then output;
  drop _:;
run;

您可以从dictionary.columns的宏变量中填充所有这些,甚至可以使用临时数组,尽管我认为这太麻烦了。

另一个选项是自我更新,但它需要两个更改。第一,您需要加入一些东西(与合并相反,合并不能有by变量)。第二,它将给出最后一个不丢失的值,而不是第一个,因此您必须对数据集进行反向排序。

但是,假设您将x添加到第一个数据集中,具有任何值(不重要,但对每一行都是常量),则如下所示:

代码语言:javascript
运行
复制
data want;
  update test(obs=0) test;
  by x;
run;

因此,这具有代码简单的巨大优点,并以一定的时间代价交换(反向排序和添加一个新变量)。

如果数据集非常稀疏,转置可能是一个很好的折衷方案。不需要知道变量名,因为可以使用数组处理它们。

代码语言:javascript
运行
复制
data test_t;
  set test;
  array numvars _numeric_;
  array charvars _character_;
  do _i = 1 to dim(numvars);
    if not missing(numvars[_i]) then do;
      varname = vname(numvars[_i]);
      numvalue= numvars[_i];
      output;
    end;
  end;
  do _i = 1 to dim(charvars);
    if not missing(charvars[_i]) then do;
      varname = vname(charvars[_i]);
      charvalue= charvars[_i];
      output;
    end;
  end;
  keep numvalue charvalue varname;
run;


proc sort data=test_t;
  by varname;
run;

data want;
  set test_t;
  by varname;
  if first.varname;
run;

然后,您可以将其转到所需的位置,以获得所需的希望(或者这对您来说是有效的)。它确实丢失了值上的格式/等等,因此要考虑到这一点,您的字符值长度可能需要设置为适当长的值--然后重新设置(您可以使用if 0 then set来修复它)。

类似的散列方法将以大致相同的方式工作;它的优点是可以更快地停止,并且不需要诉诸。

代码语言:javascript
运行
复制
data test_h;
  set test end=eof;

  array numvars _numeric_;
  array charvars _character_;
  length varname $32 numvalue 8 charvalue $1024; *or longest charvalue length;
  if _n_=1 then do;
    declare hash h(ordered:'a');
    h.defineKey('varname');
    h.defineData('varname','numvalue','charvalue');
    h.defineDone();
  end;

  do _i = 1 to dim(numvars);
    if not missing(numvars[_i]) then do;
      varname = vname(numvars[_i]);
      rc = h.find();
      if rc ne 0 then do;
        numvalue= numvars[_i];
        rc=h.add();
      end;    
    end;
  end;
  do _i = 1 to dim(charvars);
    if not missing(charvars[_i]) then do;
      varname = vname(charvars[_i]);
      rc = h.find();
      if rc ne 0 then do;
        charvalue= charvars[_i];
        rc=h.add();
      end;    
    end;
  end;

  if eof or h.num_items = dim(numvars) + dim(charvars) then do;
     rc = h.output(dataset:'want');
  end;
run;

还有很多其他的解决方案,只是取决于您的数据,这将是最有效的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45311579

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档