2

我有一个 3 列的 SAS 数据集。A FirmIndex、 aProducIndex和第三列称为PrChange。在每个FirmIndex&ProductIndex组中,我想计算有多少与和PrChange不同,并将其添加到名为 的列中。然后我想将该列除以每组中不是的观察数。.0NumberNumber.

下面是数据集和所需输出的示例。

data prod;
input firmindex productindex PrChange Number Fract;
cards;

1   1   .   1   0.250
1   1   0.00    1   0.250
1   1   0.00    1   0.250
1   1   -0.40   1   0.250
1   1   0.00    1   0.250
1   2   .   2   1.000
1   2   1.00    2   1.000
1   2   0.30    2   1.000
1   3   .   4   0.800
1   3   0.70    4   0.800
1   3   1.00    4   0.800
1   3   0.70    4   0.800
1   3   0.00    4   0.800
1   3   -0.30   4   0.800
1   4   .   5   1.000
1   4   0.20    5   1.000
1   4   -1.00   5   1.000
1   4   -0.90   5   1.000
1   4   -0.50   5   1.000
1   4   1.00    5   1.000
2   1   .   2   1.000
2   1   0.30    2   1.000
2   1   -0.50   2   1.000
2   2   .   5   0.714
2   2   0.30    5   0.714
2   2   0.10    5   0.714
2   2   0.00    5   0.714
2   2   0.00    5   0.714
2   2   0.80    5   0.714
2   2   -0.20   5   0.714
2   2   0.40    5   0.714
2   3   .   1   1.000
2   3   0.60    1   1.000
2   4   .   5   0.714
2   4   -1.00   5   0.714
2   4   0.80    5   0.714
2   4   -0.20   5   0.714
2   4   0.00    5   0.714
2   4   0.00    5   0.714
2   4   -0.70   5   0.714
2   4   0.90    5   0.714
2   5   .   3   1.000
2   5   0.90    3   1.000
2   5   -0.70   3   1.000
2   5   -0.50   3   1.000
;
run;

这是我尝试生成的 column number,但它不起作用:

data work.prod;
    set work.prod;
    by firmindex productindex;
    if first.productindex  or first.firmindex then sum = 0;
        else if PrChange ne 0 and PrChange ne .;
        sum = sum + 1;
run;
4

4 回答 4

1

我将给出我能够给出的 IML 答案。Rick 或其他更精通 IML 的人可能比这做得更好。在 R 或其他矩阵语言中,我认为这会容易得多,但我没有 IML 印章来做到这一点而无需循环;也许这是可能的。

proc iml;
  use have;
  read all var _all_ into h;
  u =  h[uniqueby(h,1:2), 1:2];   *generate the "unique" categories for the first two columns;

  v = j(nrow(h),5);               *generate a matrix to save this into;
  v[,1:3] = h;                    *start it out with the first three columns of the dataset;
  do i  = 1 to nrow(u);           *iterate over the unique category matrix;
    number = ncol(loc(h[loc((h[,1:2] = u[i,1:2])[,#]),3]));
                                  *the inner LOC produces a two column 1/0 matrix with match 1 / nomatch 0 for each col
                                   then reduce to 1 column via subscript reduction product, to get correct 1/0 match vector
                                   the outer LOC takes the rows of h from that (so rows of h matching u), then returns nonzero/nonmissing
                                   which then ncol summarizes into a count;
    fract_denom = ncol(loc(h[loc((h[,1:2] = u[i,1:2])[,#]),3] ^= .));
                                  *similar, but here we have to verify they are not missing explicitly, considering 0 valid;

   v[loc((v[,1:2] = u[i,1:2])[,#]),4] = number;             *assign to col4 of V;
   v[loc((v[,1:2] = u[i,1:2])[,#]),5] = number/fract_denom; *assign to col5 of V;

  end;
  print v;

quit;

这或多或少地使用了 unique-loc 方法,并进行了一些修改;可能是获得比赛的更简单方法。

于 2017-05-05T20:31:22.917 回答
1

您的问题是您需要在运行数据行之前除以数字。这就是 SAS 与 Excel 不同的地方;SAS 是基于行的,这意味着它会获取您的代码并一次针对每一行数据(或多或少)运行它,而不是从每个其他单元格(如 Excel)动态查看每个单元格。对于这样的事情,速度更快,效率更高,但灵活性更低。

您的特定问题需要 DoW 循环。这接管了正常的数据步进循环并执行它自己的循环 - 两次。一次计算数字/分数值,然后一次将它们复制到 BY 组。注意我只检查last.productIndex; 当第一个 by 变量为 true 时,last/first 转换总是设置在第二个 by 变量上。

在这里,我们对第一组值(前 5 条记录)执行第一次循环,然后我们重新循环遍历相同的 5 条记录。然后是下一个 3. 等等。每次这两个循环采用相同数量的行,因此它们始终保持同步。

data want;
  do _n_ = 1 by 1 until (last.productIndex);
    set have;
    by firmindex productindex;
    number_denom = sum(number_Denom,not missing(PrChange));
    number       = sum(number, not (PrChange in (.,0)));
  end;
  fract = number/number_denom;
  do _n_ = 1 by 1 until (last.productIndex);
    set have;
    by firmindex productindex;
    output;
  end;
run;
于 2017-05-05T19:08:59.853 回答
0

SAS 解决方案中的 SQL - Parfait 可能总体上更好,但 SAS 愿意重新合并使 SASsy 解决方案更简单一些。

proc sql;
  create table want as
    select firmindex, productindex, prchange, 
           sum (not (prchange in (0,.))) as number,
           calculated number / (sum ( not missing(prchange))) as fract
       from have
       group by firmindex, productindex;
quit;

SAS将进行分组/计数/等。然后毫无问题地合并回原始数据集,跳过相关子查询的需要。不是标准的 SQL,但在 SAS 中很常见。

于 2017-05-05T19:13:21.770 回答
-1

Consider proc sql using conditional CASE WHEN correlated subqueries:

proc sql;
    create table ProdChangeCount as
    SELECT p.firmindex, p.productindex,
           (SELECT SUM(CASE WHEN sub.PrChange ^= . AND sub.PrChange ^= 0 THEN 1 ELSE 0 END)
            FROM Prod sub
            WHERE sub.firmindex = p.firmindex 
            AND sub.productindex = p.productindex) AS Number,

           CALCULATED Number / 
           (SELECT Count(*)
            FROM Prod sub
            WHERE sub.PrChange ^= . 
            AND sub.firmindex = p.firmindex 
            AND sub.productindex = p.productindex) AS Frac
    FROM Prod p;

quit;
于 2017-05-05T19:06:58.700 回答