【问题标题】:Recursively add to a data table in SAS递归添加到SAS中的数据表
【发布时间】:2015-03-06 19:10:30
【问题描述】:

我是 SAS 新手。我需要进行 x- 次迭代来填充我的名为 MYRS 的数据集。

每次迭代都需要 JOIN TABLE1 与 (TABLE2+ MYRS) MINUS 已经在 MYRS 表中的记录。

然后,我需要用其他匹配更新MYRS 表。目标是跟踪一系列电子邮件。

MYRS 本质上是TABLE1 的副本,并包含匹配的记录。有点棘手。 (简化模式)。 Table1 可以有 DUPS。

例如

TABLE1:
ID | EMAIL1 | EMAIL2 | EMAIL3 | EMAIL4|
1 | A | s | d | F
2 | g | F | j | L
3 | z | x | L | v
4 | z | x | L | v
2 | g | F | j | L

TABLE2:
EMAIL
A

MYRS (starts as empty dataset)
EMAIL1 | EMAIL2 | EMAIL3 | EMAIL4

逻辑:TABLE1 的电子邮件与TABLE2 中的电子邮件匹配。因此,需要显示此记录。其他记录与 TABLE2 中的任何内容都不匹配。但是因为Record1Record2共享the same ALTERNATIVE emailF,所以Record2也需要显示。但是因为Record2Record3 共享相同的备用电子邮件L,所以Record3 也需要显示。所以第四个......

proc sql;        
SELECT TABLE1.id,
    TABLE1.email1,
    TABLE1.email2,
    TABLE1.email3,
    TABLE1.email4
FROM TABLE1
INNER JOIN (
    SELECT EMAIL
    FROM TABLE2     
     UNION      
    SELECT EMAIL1 AS EMAIL
    FROM MYRS   
     UNION      
    SELECT EMAIL2 AS EMAIL
    FROM MYRS   
     UNION      
    SELECT EMAIL3 AS EMAIL
    FROM MYRS   
     UNION      
    SELECT EMAIL4 AS EMAIL
    FROM MYRS
    )
ON EMAIL=EMAIL1 OR EMAIL=EMAIL2 OR EMAIL=EMAIL3 OR EMAIL=EMAIL4
WHERE TABLE1.id NOT IN (
        SELECT DISTINCT ID
        FROM MYRS
        )
quit;

如何创建以下逻辑:

  1. 将其包装成某种函数
  2. sql执行前,统计MYDS中的记录数并保存
  3. 执行 SQL 并更新 MYDS
  4. 统计MYDS中的记录数
  5. 如果 MYDS 计数未更改,则停止执行
  6. 否则,转到 #3

我对 SAS 非常陌生(准确地说是 3 天),我正在尝试将所有内容放在一起。 (如果我要在 Java 中这样做,我会使用上面的逻辑)

【问题讨论】:

  • 您可能会编写一个宏来按照您上面设置的方式执行此操作,但我的一部分人说如果您重组数据,您可能会有更好的选择。你能发布一个有效的例子吗,我很难想象这个问题。
  • 根据您的数据大小,哈希表可能是解决此类问题的理想选择。

标签: recursion sas


【解决方案1】:

这是一种宏观方法,它主要遵循您的逻辑,但首先转换您的数据,输入/输出是IDs 的列表(您可以使用它轻松地往返电子邮件)。

这段代码可能会介绍很多你不熟悉的 SAS 特性,但下面的 cmets 和解释应该会有所帮助。如果仍有任何不清楚的地方,请查看链接或添加评论。

它需要输入数据:

  • inData:带有IDEMAIL* 变量的TABLE1
  • matched:已知通缉的初始名单IDs

返回:

  • matched:更新的通缉名单IDs

/* Wrap the processing in a macro so that we can use a %do loop */
%macro looper(maxIter = 5);
    /* Put all the emails in one column to make comparison simpler */
    proc transpose data = inData out = trans (rename = (col1 = email));
        by ID;
        var email:;
    run;        
    /* Initialise the counts for the %where condition */
    %let _nMatched = 0;
    %let nMatched = 1;
    %let i = 0;
    /* Loop until no new IDs are added (or maximum number of iterations) */
    %do %while(&_nMatched. < &nMatched. and &i < &maxIter.); 
        %let _nMatched = &nMatched.;
        %let i = %eval(&i. + 1);
        %put NOTE: Loop &i.: &nMatched. matched.;
        /* Move matches to a temporary table */
        proc datasets library = work nolist nowarn;
            delete _matched;
            change matched = _matched;
        quit;
        /* Get new matched IDs */
        proc sql noprint;
            create table matched as
            select distinct c.ID
            from _matched as a
            left join trans as b
                on a.ID = b.ID
            left join trans as c
                on b.email = c.email;
            /* Get new count */
            select count(*) into :nMatched from matched;
        quit;
    %end;
%mend looper;
%looper(maxIter = 10);

有趣的是:

  • proc transpose:将输入转换为一个深度表,以便所有电子邮件地址都在一个变量中,这使得编写电子邮件比较逻辑更简单(需要更少的重复)并将数据以一种更容易的格式放置必要时清理电子邮件地址(想想upcase()strip() 等)。
  • %macro %mend:用于定义macro 的语句。这是必要的,因为您不能在开放代码中使用宏逻辑或循环。我还添加了一个参数,以便您了解它是如何工作的。
  • %letselect into ::两种创建macro variables 的方法。宏变量以 &amp; 前缀引用,用于在 SAS 程序执行之前将文本插入到该程序中。
  • %do %while() %end:在宏中执行循环的方法之一。其中的代码将重复运行,直到条件评估为 false。
  • proc datasets:对数据集和库执行管理任务的过程。此处用于删除和重命名临时表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-13
    • 2017-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-25
    相关资源
    最近更新 更多