我有一个数据集:
data have;
input group $ value;
datalines;
A 4
A 3
A 2
A 1
B 1
C 1
D 2
D 1
E 1
F 1
G 2
G 1
H 1
;
run;
第一个变量是组标识符,第二个变量是值。
对于每组,我想要一个新的变量"sum",其中包含列中所有值的总和,除了观察所在的组。
我的问题是必须在近3000万次观测中做到这一点,所以效率很重要。我发现使用数据步骤比使用procs更有效。
最终的数据库应该是这样的:
data want;
input group $ value $ sum;
datalines;
A 4 11
A 3 11
A 2 11
A 1 11
B 1 20
C 1 20
D 2 18
D 1 18
E 1 20
F 1 20
G 2 18
G 1 20
H 1 20
;
run;
你知道怎么表演吗?
编辑:我不知道这件事是不是,但我举的例子是我问题的简化版本。在实际情况下,我有另外两个群变量,因此取整列的和减去群中的和是不可行的。
要求
列中所有值的总和,除了观察在中的组
表示必须进行两次数据传递:
- 计算
all_sum
和每个组的group_sum
哈希可以存储每个组的和——通过指定的suminc:
变量和.ref()
方法调用计算。一个变量可以累加allsum
- 为一组中的每一行计算
allsum
-group_sum
从散列中检索group_sum
,并从allsum
中减去
示例:
data want;
if 0 then set have; * prep pdv;
declare hash sums (suminc:'value');
sums.defineKey('group');
sums.defineDone();
do while (not hash_loaded);
set have end=hash_loaded;
sums.ref(); * adds value to internal sum of hash data record;
allsum + value;
end;
do while (not last_have);
set have end=last_have;
sums.sum(sum:sum); * retrieve groups sum. Do you hear the Dragnet theme too?;
sum = allsum - sum; * subtract from allsum;
output;
end;
stop;
run;
直接方法有什么问题?无论你做什么,你都需要两次传球。
就像这样。我包含了额外的变量,这样你就可以看到这些值是如何导出的。
proc sql ;
create table want as
select a.*,b.grand,sum(value) as total, b.grand - sum(value) as sum
from have a
, (select sum(value) as grand from have) b
group by a.group
;
quit;
结果:
Obs group value grand total sum
1 A 3 21 10 11
2 A 1 21 10 11
3 A 2 21 10 11
4 A 4 21 10 11
5 B 1 21 1 20
6 C 1 21 1 20
7 D 2 21 3 18
8 D 1 21 3 18
9 E 1 21 1 20
10 F 1 21 1 20
11 G 1 21 3 18
12 G 2 21 3 18
13 H 1 21 1 20
请注意,GROUP BY子句中包含的内容并不重要。
你真的需要输出所有的原始观测结果吗?为什么不直接输出汇总表呢?
proc sql ;
create table want as
select a.group, b.grand - sum(value) as sum
from have a
, (select sum(value) as grand from have) b
group by a.group
;
quit;
结果
Obs group total sum
1 A 10 11
2 B 1 20
3 C 1 20
4 D 3 18
5 E 1 20
6 F 1 20
7 G 3 18
8 H 1 20
我将把它分成两个不同的部分:
1.(您可以从使用PROC SQL开始,按组获取总和
2.(然后使用一些IF/Then语句按组重新分配值