SAS 哈希对象总和

SAS Hash object sum

我想了解 SAS Hash 对象的 sum() 函数。据我了解,suminc: 定义了变量 SAS 哈希对象跟踪而 sum() 将对该变量的值求和。

假设我有数据集

data sample;
    input id x;
    datalines;
1 350
1 220
1 300
2 300
2 500
;
run;

我希望聚合为

id x_sum
2  800
1  870

然而,我的哈希码:

data _null_;
    set sample end= done;

    length x_sum 8;

    if _N_ = 1 then 
    do;
        declare hash T(suminc:"x");
        T.definekey("id");
        T.definedata("id");
        T.definedata("x_sum");
        T.definedone();
    end;


    T.ref();

    T.sum(sum:x_sum);

    put _all_;


    T.replace();

    if done then T.output(dataset: "my_set");

run;

输出:

id x_sum
2  800
1  520

作为数据集并写入日志:

done=0 id=1 x=350 x_sum=350 _ERROR_=0 _N_=1
done=0 id=1 x=220 x_sum=570 _ERROR_=0 _N_=2
**done=0 id=1 x=300 x_sum=520 _ERROR_=0 _N_=3**
done=0 id=2 x=300 x_sum=300 _ERROR_=0 _N_=4
done=1 id=2 x=500 x_sum=800 _ERROR_=0 _N_=5

谁能给我解释一下这是怎么回事?

所有评论后更新

大家好,我是 Stack Overflow 的新手,所以我仍在研究这个 "Tick off answer" 系统...我觉得每个人都做出了贡献。

总之,经过大量的实验,我弄明白了是怎么回事-

基本上,每当调用 .sum() .replace() 时,求和计数器将重置为零。 这, 而不是真正的 replace() 等等 ,这就是为什么结果是这样的原因——sum() 重置了我的计数,所以 ref() 只是对前 2 个观察结果求和。

希望这是对大家有用的信息。如果其他人有任何见解,请分享。

我认为 T.REPLACE() 是您问题的一部分。我不知道这样做有什么好处,只有坏处。如果您将其注释掉,则 PUT _ ALL _ 会显示您想要的内容。令我惊讶的是(对 SAS 散列仍然是新手),我无法让 T.Output() 将 x_sum 变量写入输出数据集。希望其他人会插话。也许这些 suminc 蓄能器的处理方式不同?在下面,由于 PDV 有正确的数据,我切换到以正常的数据步骤方式写入输出数据集,而不是使用 output()

data my_set(keep=id x_sum);
  set sample;
  by id;

  if _N_ = 1 then 
  do;
    declare hash T(suminc:"x");
    T.definekey("id");
    T.definedata("x");
    T.definedone();
  end;

  T.ref();

  T.sum(sum:x_sum);

  put _all_;

  if last.id;
run;
Maybe you can try these codes:
data _null_;

length x_sum 8;

if _N_ = 1 then 
do;
    declare hash T(suminc:"x");
    T.definekey("id");
    T.definedata("id");
    T.definedata("x_ct","x_sum");
    T.definedone();
end;

do until(done);
  set sample end = done;
  if t.find() ^= 0 then do;
     x_ct = 0;
     x_sum = 0;
  end;
  x_ct ++ 1;
  x_sum ++ x;
  t.replace();
 end;
 t.output(dataset:'want');
 stop;
run;

您的问题是当您声明您的散列 table 时,您的密钥 ID 对于每条记录来说都不是唯一的。您可以通过包含多数据方法来修复它:multidata:"yes":

if _N_ = 1 then 
do;
    declare hash T(suminc:"x", multidata:"yes");
    T.definekey("id");
    T.definedata("id");
    T.definedata("x_sum");
    T.definedone();
end;

这给出:

done=0 id=1 x=350 x_sum=350 _ERROR_=0 _N_=1
done=0 id=1 x=220 x_sum=570 _ERROR_=0 _N_=2
**done=0 id=1 x=300 x_sum=870 _ERROR_=0 _N_=3**
done=0 id=2 x=300 x_sum=300 _ERROR_=0 _N_=4
done=1 id=2 x=500 x_sum=800 _ERROR_=0 _N_=5

问题在于您对 Replace() 的使用。来自文档(9.3 语言参考概念,使用散列对象):

This SUMINC tag instructs the hash object to allocate internal storage for maintaining a summary value for each key. The summary value of a hash key is initialized to the value of the SUMINC variable whenever the ADD or REPLACE method is used. The summary value of a hash key is incremented by the value of the SUMINC variable whenever the FIND, CHECK, or REF method is used.

我认为重要的一点是 "summary value" 不是 DATA 步变量 x_sum,或者 x_sum 作为数据变量存储在散列 table 中。它存储在散列 table 定义的数据之外。辅助信息实际上是密钥的一个属性。 (在我脑海中...)

如果你注释掉 replace(),你的代码可以工作(你在 PDV 中得到 x_sum 的正确值),但问题是 x_sum 永远不会写入哈希table。因此,您调用 replace() 将 x_sum 写入散列 table,导致不幸的副作用,即汇总值被初始化为 x 的值。我认为解决方法是在调用 replace() 之前分配 x=x_sum。这样当 replace() 将汇总值重新初始化为 x 的值时,x 保存当前汇总值。我很难用语言表达,但看到下面只添加了一个声明。

data _null_;
  set sample end= done;

  length x_sum 8;

  if _N_ = 1 then 
  do;
    declare hash T(suminc:"x");
    T.definekey("id");
    T.definedata("id");
    T.definedata("x_sum");
    T.definedone();
  end;
  T.ref();
  T.sum(sum:x_sum);
  put _all_;

  x=x_sum;  *Replace method will initialize the summary value to x! ;

  T.replace();
  if done then T.output(dataset: "my_set");
run;