统计图中节点/边的SAS数据步

统计图中节点/边的SAS数据步,sas,datastep,Sas,Datastep,假设我有一个名为links的数据集中表示的有向图,它有两个变量:from\u id和to\u id。我想使用SAS数据步骤做两件事:(1)计算节点的数量,(2)计算边的数量 假设链接数据集如下所示 from_id to_id ---------------- 1 2 2 3 3 1 3 2 在本例中,有3个节点和4条边。(我们可以假设链接中没有重复的边。节点为1、2和3。边是1->2、2->3、3->

假设我有一个名为
links
的数据集中表示的有向图,它有两个变量:
from\u id
to\u id
。我想使用SAS数据步骤做两件事:(1)计算节点的数量,(2)计算边的数量

假设
链接
数据集如下所示

from_id    to_id
----------------
   1         2
   2         3
   3         1
   3         2
在本例中,有3个节点和4条边。(我们可以假设
链接中没有重复的边。节点为1、2和3。边是1->2、2->3、3->1和3->2

下面是一个SAS宏,它结合使用SAS数据步骤和proc sql来计算节点和边。它工作得很好,但我希望使用SAS数据步骤,以便(可能)更快地计算节点和边

/* display number of nodes and edges for graph */
%macro graph_info(links);
data nodes;
    set &links;
    node_id = from_id;
    output;
    node_id = to_id;
    output;
    keep node_id;
run;

proc sql noprint;
    select count(distinct node_id) into :numNodes from nodes;
quit;
proc datasets lib=work nolist;
    delete nodes;
quit;

proc sql noprint;
    select count(*) into :numEdges from &links;
quit;

%put Nodes: &numNodes;
%put Edges: &numEdges;
%mend;

如果您有足够的内存,您可以使用散列对象来实现这一点

data _null_;
  set links end=lastrec;
  format node_id 8.;
  if _N_ eq 1 then do;
    declare hash h();
    h.defineKey("node_id");
    h.defineDone();
  end;
  node_id = from_id;
  rc=h.find();
  if rc ne 0 then h.add();
  node_id = to_id;
  rc=h.find();
  if rc ne 0 then h.add();
  if lastrec then do;
    call symput('numLinks', put(h.num_items, 8. -L));
    call symput('numEdges', put(_N_, 8. -L));
  end;
run;
请注意:此代码未经测试,因为我手头没有SAS安装。然而,基本想法应该是可行的。迭代数据步骤,将每个节点添加到哈希对象,并在最后一个对象上将宏变量设置为哈希对象的大小

data _null_;
  set links end=lastrec;
  format node_id 8.;
  if _N_ eq 1 then do;
    declare hash h();
    h.defineKey("node_id");
    h.defineDone();
  end;
  node_id = from_id;
  rc=h.find();
  if rc ne 0 then h.add();
  node_id = to_id;
  rc=h.find();
  if rc ne 0 then h.add();
  if lastrec then do;
    call symput('numLinks', put(h.num_items, 8. -L));
    call symput('numEdges', put(_N_, 8. -L));
  end;
run;

您可能有多少个节点?它们都适合内存吗?最多可容纳数亿个节点/边。数据集很容易达到10GB左右。虽然我可以访问内存更多的机器,但我的桌面客户端有8 GB的内存。如果它不适合内存,显然可以通过一个进程排序和一个数据步骤来完成。我要补充的两件事是:不要使用NOBS,因为如果数据集被修改,这可能会出错-使用N,这显然是安全的;和2:在添加节点之前,是否需要检查该节点是否存在于哈希中?否则您将添加重复的节点,我认为?我认为当您调用add()时,重复的节点将被删除,所以这样应该可以。但是关于N的观点很好。我将编辑。
363rc=h.defineKey(node\u id)然后
错误:第363行第9列的未初始化对象。
No.add()不会自动检查。测试后,我对您的代码进行了编辑-现在应该可以工作了(如果批准的话)。除此之外,你还有一些小的语法问题,我已经纠正了。太好了!只花了不到10分钟的时间,而之前我等待基于proc-sql的方法的时间超过了45分钟。再次感谢。