SAS:表列子集的总和(多次)

时间:2018-06-29 08:32:23

标签: sas

(我是SAS的新手,我很难理解按列进行操作的复杂程度,这在“正常”语言中是很容易的。如果这是非常基本的内容,请多多包涵。)

我有一个表,其中包含值 type a1-a10 b1-b10 ,我想查找(对于每个< em> N ) aN 为正的行的 bN 之和。我可以一次完成一个变量,例如像这样:

proc sql;
create table work.test1 as
    select type, b1
    from work.table
    where (a1 >0);
run;

,然后对所有这些表求和,然后合并它们,但这将是很多代码和一些麻烦。有没有一种不错且紧凑的方法来做到这一点?

编辑:我想要的输出是一个值为 type sum1-sum10 的表,其中 sumN 是上述总和

样本数据:

type | a1 | a2 | ... | b1 | b2 | ...
------------------------------------
 cat   10   14   ...   1     2   ...
 cat   -5    3   ...   1     1   ...
 dog   35   -1   ...   9     3   ...
 dog    9    2   ...  0.5    1   ...

所需的输出:

type | sum1 | sum2 | ...
------------------------
 cat    1      3     ...
 dog   9.5     1     ...

因此,对于每种 type N ,求和那些 bN ,其中同一行的 aN 为正。

4 个答案:

答案 0 :(得分:3)

这是一种proc summary的方法。这并不像数组方法那样直接,但是将其归纳为您可能感兴趣的其他统计数据要容易得多。

data have; 
input type $ a1   a2   b1  b2  ; 
datalines;
cat    10   14   1    2
cat    -5    3   1    1
dog    35   -1   9    3
dog     9    2   0.5  1
;
run;

/*Create a view of the dataset with suitable weight columns*/
data t_have / view = t_have;
  set have;
  array a[*] a1-a2;
  do i = 1 to dim(a);
    a[i] = a[i] > 0;
  end;
run;

/*Use proc summary to sum across rows*/
proc summary nway data = t_have;
  class type;
  var b1 /weight=a1; /*You could macro-ise this bit to avoid excessive repetition*/
  var b2 /weight=a2;
  output out= want(drop=_:) sum= mean= /autoname;
run;

答案 1 :(得分:2)

您可以使用数组在单个步骤中以单个输出执行此任务。数组将值跨列存储在内存中,然后可以循环遍历以进行计算。

在此代码中,我创建了3个数组,一个数组用于A1-A2,一个数组用于B1-B2,一个数组用于新变量SUM1-Sum2。显然,在实际数据中,您可以将范围更改为A10,B10,SUM10。

我添加了很多注释来描述代码的作用,但是我还建议阅读数组以更好地理解。

/* create input data */
data have;
input type $ a1 a2 b1 b2;
datalines;
cat . 14 1 2
cat -5 3 1 1
dog 35 -1 9 3
dog 9 2 0.5 1
;
run;

/* sort data by type (needed for next step) */
proc sort data=have;
by type;
run;

data want;
set have;
by type; /* data neds to be sorted by this */
array var_a{2} a1-a2; /* store the values of a in an array */
array var_b{2} b1-b2; /* store the values of b in an array */
array sumvar{2} sum1-sum2; /* set up an array of sum variables (will also create physical variables) */
if first.type then do; /* set sum variables to zero when type changes */
    do i = 1 to dim(sumvar);
        sumvar{i} = 0;
    end;
end;
do j=1 to dim(var_a); /* loop through each var_a value and add var_b to sum_N if var_a>0 */
    if var_a{j}>0 then sumvar{j}+var_b{j}; /* syntax var1 + var2 retains value across rows */
end;
keep type sum: ; /* only keep required variables */
if last.type then output; /* only output last record for each type, with the total sum */
run;

答案 2 :(得分:2)

您可以在单个SQL select中为每个变量使用一个case子句来完成此操作。

数据

data have; input 
type $ a1   a2   b1  b2  ; datalines;
cat    10   14   1    2
cat    -5    3   1    1
dog    35   -1   9    3
dog     9    2   0.5  1
run;

SQL示例

proc sql;
  create table want_way1
  as select 
    type
  , sum (case when a1 > 0 then b1 else 0 end) as sum1
  , sum (case when a2 > 0 then b2 else 0 end) as sum2
  from have
  group by type
  ;

SQL没有数组,因此将为每个 N ab变量编写一个宏以生成整个SQL或仅生成所需的子句对。如果您希望宏发现 N 本身,则宏可以检查数据的元数据。

数据步骤示例

使用DOW循环进行组处理,并使用数组进行项目处理。如果删除注释,则非常紧凑。

data want_way2 (keep=type sum:);
  do until (last.type);
    set have;
    by type;

    * array statement is non-executable, but associates PDV variables with the array reference;
    * array statement will create new variables in PDV if needed;

    array a a1-a2;      /* connects existing variables with array */
    array b b1-b2;      /* connects existing variables with array */
    array s sum1-sum2;  /* creates new variables and connects them with array */

    * repurpose _n_ as simply an automatic variable that does not need to be dropped;
    do _n_ = 1 to dim(a);
      s(_n_) = sum ( s(_n_) , ifn ( a(_n_) > 0, b(_n_), 0 ) );
    end;
  end;
run;

答案 3 :(得分:1)

如果我了解您想要的内容,那么我认为将代码放在宏中可以解决问题。例如,在下面的示例中,我使用一个%do循环来生成10个不同的数据集,每个N一个。我所做的只是将您的代码包装在一个宏中,因此我希望您的代码能够满足您的要求。然后我用run替换了您的quit,否则proc sql不会停止。

编辑:

options symbolgen mprint mlogic;

%macro Y(N=);

  %macro compute;
  %do i = 1 %to &N.;
    proc sql;
      create table work.test&i. as
        select type, sum(b&i.) as sum&i.
        from work.table
        where (a&i. >0)
        group by type
        order by type;
      quit;
   %end;
  %mend;

   %compute;

      data want;
      %do i = 1 %to &N.;
        merge test&i.;
      %end;
      run;
 %mend;

%Y(N=10);