首页 > 解决方案 > 如何在sas中转置多次出现的数据

问题描述

我有一个 2 列数据集 - 帐户和属性,其中有 6 种类型的属性。我正在尝试使用 PROC TRANSPOSE 将 6 个不同的属性设置为 6 个新列,并在该列具有该属性的位置设置 1,在没有该属性的位置设置 0

标签: sastransposeproc

解决方案


这个答案显示了两种方法:

  • Proc TRANSPOSE, 和
  • 使用通过哈希的索引查找的基于数组的转置。

对于所有帐户都缺少相同属性的情况,数据本身将无法展示所有属性 - 理想情况下,允许或预期的属性应作为数据重塑的一部分列在单独的表中。

转置

当使用only account表时,attribute您需要构建一个视图,添加一个可以转置的数字变量。TRANSPOSE必须对结果数据进行进一步处理后,将缺失值 ( .)替换为0.

例子:

data have;
  call streaminit(123);
  do account = 1 to 10;
    do attribute = 'a','b','c','d','e','f';
      if rand('uniform') < 0.75 then output;
    end;
  end;
run;

data stage / view=stage;
  set have;
  num = 1;
run;

proc transpose data=stage out=want;
  by account;
  id attribute;
  var num;
run;

data want;
  set want;
  array attrs _numeric_;
  do index = 1 to dim(attrs);
    if missing(attrs(index)) then attrs(index) = 0;
  end;
  drop index;
run;

proc sql;
  drop view stage;

在此处输入图像描述

在此处输入图像描述

高级技术 - 数组和哈希映射

在某些情况下Proc TRANSPOSE,编码员或操作员认为它无法使用,可能很多按组和很多属性。将属性值转换为类似命名的标志变量的另一种方法是编码:

  • 两次扫描
    • 扫描 1 确定将遇到并用作列名的属性值
      • 将值列表存储在宏变量中
    • 扫描 2
      • 将属性值排列为变量名
      • 使用散列(或@Joe 的自定义信息)将值映射到数组索引
      • 处理每个组。将对应于每个遇到的属性值的数组变量设置为1。通过哈希映射查找得到的数组索引。

例子:

* pass #1, determine attribute values present in data, the values will become column names;
proc sql noprint; 
  select distinct attribute into :attrs separated by ' ' from have;

* or make list of attributes from table of attributes (if such a table exists outside of 'have');
*  select distinct attribute into :attrs separated by ' ' from attributes;

%put NOTE: &=attrs;

* pass #2, perform array based tranposformation;

data want2(drop=attribute);
  * prep pdv, promulgate by group variable attributes;
  if 0 then set have(keep=account);

  array attrs &attrs.;
  format &attrs. 4.;

  if _n_=1 then do;
    declare hash attrmap();
    attrmap.defineKey('attribute');
    attrmap.defineData('_n_');
    attrmap.defineDone();
    do _n_ = 1 to dim(attrs);
      attrmap.add(key:vname(attrs(_n_)), data: _n_);
    end;
  end;

  * preset all flags to zero;

  do _n_ = 1 to dim(attrs);
    attrs(_n_) = 0;
  end;

  * DOW loop over by group;

  do until (last.account);
    set have;
    by account;

    attrmap.find();     * lookup array index for attribute as column;
    attrs(_n_) = 1;     * set flag for attribute (as column);
  end;

  * implicit output one row per by group;
run;

推荐阅读