【发布时间】:2017-05-17 22:05:40
【问题描述】:
我有一个带有分层编码列表变量的数据集。 层次的逻辑由 LEVEL 变量和 CODE 字符变量的前缀结构决定。 共有 6 个(代码长度从 1 到 6)“聚合”级别和终端级别(代码长度为 10 个字符)。
我需要更新节点变量(终端节点的计数 - 聚合级别不计入“更高”聚合,只计算终端节点) - 所以一个级别的计数总和,例如每个级别 5 的总数计数与每个级别 6 相同。 我需要计算(总结)“更高”级别节点的权重。
注意:我偏移了输出表的 NODES 和 WEIGHT 变量,以便您可以更好地了解我在说什么(只需将每个偏移量中的数字相加,您就会得到相同的值)。
EDIT1:同一代码可以有多个观察值。一个独特的观察是 3 个变量 code + var1 + var2 的组合。
输入表:
ID level code var1 var2 nodes weight myIndex
1 1 1 . . 999 999 999
2 2 11 . . 999 999 999
3 3 111 . . 999 999 999
4 4 1111 . . 999 999 999
5 5 11111 . . 999 999 999
6 6 111111 . . 999 999 999
7 10 1111119999 01 1 1 0.1 105,5
8 10 1111119999 01 2 1 0.1 109,1
9 6 111112 . . 999 999 999
10 10 1111120000 01 1 1 0.5 95,0
11 5 11119 . . 999 999 999
12 6 111190 . . 999 999 999
13 10 1111901000 01 1 1 0.1 80,7
14 10 1111901000 02 1 1 0.2 105,5
所需的输出表:
ID level code var1 var2 nodes weight myIndex
1 1 1 . . 5 1.0 98,1
2 2 11 . . 5 1.0 98,1
3 3 111 . . 5 1.0 98,1
4 4 1111 . . 5 1.0 98,1
5 5 11111 . . 3 0.7 98,5
6 6 111111 . . 2 0.2 107,3
7 10 1111119999 01 1 1 0.1 105,5
8 10 1111119999 01 2 1 0.1 109,1
9 6 111112 . . 1 0.5 95,0
10 10 1111120000 01 1 1 0.5 95,0
11 5 11119 . . 2 0.3 97,2
12 6 111190 . . 2 0.3 97,2
13 10 1111901000 01 1 1 0.1 80,7
14 10 1111901000 02 1 1 0.2 105,5
这是我想出的代码。它就像我想要的那样工作,但是伙计,它真的很慢。我需要更快的方法,因为这是 Web 服务的一部分,必须根据请求“立即”运行。 欢迎任何有关加快代码速度或任何其他解决方案的建议。
%macro doit;
data temporary;
set have;
run;
%do i=6 %to 2 %by -1;
%if &i = 6 %then %let x = 10;
%else %let x = (&i+1);
proc sql noprint;
select count(code)
into :cc trimmed
from have
where level = &i;
select code
into :id1 - :id&cc
from have
where level = &i;
quit;
%do j=1 %to &cc.;
%let idd = &&id&j;
proc sql;
update have t1
set nodes = (
select sum(nodes)
from temporary t2
where t2.level = &x and t2.code like ("&idd" || "%")),
set weight = (
select sum(weight)
from temporary t2
where t2.level = &x and t2.code like ("&idd" || "%"))
where (t1.level = &i and t1.code like "&idd");
quit;
%end;
%end;
%mend doit;
基于@Quentin 解决方案的当前代码:
data have;
input ID level code : $10. nodes weight myIndex;
cards;
1 1 1 . . .
2 2 11 . . .
3 3 111 . . .
4 4 1111 . . .
5 5 11111 . . .
6 6 111111 . . .
7 10 1111110000 1 0.1 105.5
8 10 1111119999 1 0.1 109.1
9 6 111112 . . .
10 10 1111129999 1 0.5 95.0
11 5 11119 . . .
12 6 111190 . . .
13 10 1111900000 1 0.1 80.7
14 10 1111901000 1 0.2 105.5
;
data want (drop=_:);
*hash table of terminal nodes;
if (_n_ = 1) then do;
if (0) then set have (rename=(code=_code weight=_weight));
declare hash h(dataset:'have(where=(level=10) rename=(code=_code weight=_weight myIndex=_myIndex))');
declare hiter iter('h');
h.definekey('ID');
h.definedata('_code','_weight','_myIndex');
h.definedone();
end;
set have;
*for each non-terminal node, iterate through;
*hash table of all terminal nodes, looking for children;
if level ne 10 then do;
call missing(weight, nodes, myIndex);
do _n_ = iter.first() by 0 while (_n_ = 0);
if trim(code) =: _code then do;
weight=sum(weight,_weight);
nodes=sum(nodes,1);
myIndex=sum(myIndex,_myIndex*_weight);
end;
_n_ = iter.next();
end;
myIndex=round(myIndex/weight,.1);
end;
output;
run;
【问题讨论】:
-
真实数据有多大?我正在考虑一些丑陋的蛮力方法。
-
“在每个偏移量中添加数字”是什么意思?你能在这里使用多级格式吗?
-
@Quentin 真实数据是动态变化的,但总是在 4-5000 次观察之间,所以不是很大。
-
@Reeza 我只是想更好地解释/可视化我想要通过偏移量实现的目标。 misalingned/offseted 值来自同一层次结构级别,因此您可以更好地看到,它总是加起来相同的数字(权重或节点数)。我不知道多级格式是如何工作的,但会检查一下。
-
@Quentin, user667489 Quentin 解决方案的平均 CPU 时间为 6.84 秒,而 user667489 的方法为 0.82 秒。那是一些 -88% 的 CPU 时间改进。绝对实时时间几乎与 -88% 的相对改进相同。汤姆的接近花了半多分钟。哈希表查找的速度给我留下了深刻的印象。
标签: sql sas sum hierarchy recursive-query