【问题标题】:Creating a table of duplicates from SAS data set with over 50 variables从 SAS 数据集中创建包含 50 多个变量的重复项表
【发布时间】:2015-08-25 22:59:20
【问题描述】:

我需要加载到 Teradata 中的大型 SAS 数据集(54 个变量和超过 1000 万个观测值)。还必须出现重复项,并且我的机器未配置为 MultiLoad。我想简单地创建一个包含 300,000 个重复项的表,我可以将其附加到不接受它们的原始负载中。我在其他帖子中读到的逻辑似乎适用于只有几个变量的表。是否有另一种方法可以创建一个新表,其中列出了具有所有 54 个变量的相同组合的每个观察值。我试图通过使用 54 个变量的逻辑来避免 proc 排序。查询生成器方法似乎也效率低下。谢谢。

【问题讨论】:

    标签: duplicates sas


    【解决方案1】:

    你可以这样做:

    proc sql;
    create table rem_dups as 
    select <key_fields>, count(*) from duplicates
    group by <key_fields>
    having count(*) > 1;
    quit; 
    
    proc sql; 
    create table target as 
    select dp.* from duplicates dp 
    left join rem_dups rd 
    on <Key_fields>
    where <key_fields> is null;
    quit; 
    

    如果重复次数超过 300K,则此选项不起作用。而且,我不敢说我​​不了解 Teradata 以及您加载表格的方式。

    【讨论】:

      【解决方案2】:

      我建议您使用Proc sortindex,而不是试图避免proc排序。

      Read the document about index

      我确信除了_n_之外,必须有标识符来区分观察, 在索引的帮助下,按noduprecsnodupkey dupout = dataset 排序将是一个有效的选择。此外,索引还可以促进其他操作,例如合并/报告。

      无论如何,我不认为具有 1000 万个观测值(每个?)的数据集是一个好的数据集,更不用说 54 个变量了。

      【讨论】:

      • 我不明白这是如何回答这个问题的。
      • 我猜他想把所有重复的观察放到另一个数据集中。 proc sort 的 dupout 可以完成这项工作。
      • 当然,但我不确定index 的部分与此有什么关系 - 它并没有真正帮助现在,最后一句话也不应该是那里(10MM 观察的数据集没有任何问题,这在我的书中很小)。第三段是合理的。
      • 等等,我建议了带有一些选项的 proc 排序,你们中的很多人也建议过。并且为了提高效率,可以使用索引。为什么投反对票?
      • 反对票主要是最后一句话。我仍然不明白索引在这个特定任务中是如何有用的。正如我在上一条评论中所说 - 第三段是一个合理的答案,尽管他确实明确要求不要使用 proc 排序,所以我认为这还不够(因此我在回答中分别回答了如何使用 / o proc 排序)。
      【解决方案3】:

      使用proc sort 是一个很好的方法,您只需要创建一个更好的方法来关闭它。

      创建一些测试数据。

      data have;
        x = 1;
        y = 'a';
        output; 
        output;
        x = 2;
        output;
      run;
      

      创建一个新字段,基本上相当于将行中的所有字段附加在一起,然后通过md5()(散列)算法运行它们。这将为您提供一个很好的短字段,它将唯一标识该行上所有值的组合。

      data temp;
        length hash $16;
        set have;
        hash = md5(cats(of _all_));
      run;
      

      现在使用 proc 排序和我们的新哈希字段作为键。将重复记录输出到名为'want'的表中:

      proc sort data=temp nodupkey dupout=want;
        by hash;
      run;
      

      【讨论】:

      • 鉴于我忘记了 noduprec 的缺点,我认为这可能有一些价值 - 但我提出的一个建议是让 temp 成为 view(然后你在proc排序中也需要out)。这样你就不会多次写出整个数据集。
      • 同意,视图可能有助于加快速度。根据 OPs 代码,他可能只能够在已经存在的数据步骤中插入计算散列的行。 TBH 不过,1000 万条记录确实不算多,上面的代码应该可以很快运行,无需任何额外的优化。
      • @Joe - 这使用nodupkey。我刚刚测试了它,它没有遇到与noduprec相同的问题,所以应该没问题。
      • 正确 - 我的意思是 noduprec 有一个缺点,你避免它。 :)
      • 知道了...我不知道 noduprec 问题,所以这是一个很好的归档...
      【解决方案4】:

      先是几个sort相关的建议,然后是休息后的核心“快”建议。


      如果表完全未排序(即重复项可以出现在数据集中的任何位置),那么proc sort 可能是您最简单的选择。如果您有一个可以保证将重复记录相邻放置的键,那么您可以这样做:

      proc sort data=have out=uniques noduprec dupout=dups;
        by <key>;
      run;
      

      这会将重复记录(注意 noduprec 不是 nodupkey - 这要求所有 54 个变量都相同)放在辅助数据集中(上面的 dups)。但是,如果它们在物理上不相邻(即,key 有 4 或 5 个重复项,但只有两个是完全重复的),如果它们在物理上不相邻,则可能无法识别;您需要进行第二次排序,或者您需要在 by 语句中列出所有变量(这可能很混乱)。您还可以使用 Rob 的 md5 技术来简化这一点。

      如果表未“排序”但重复记录将相邻,您可以使用 bynotsorted 选项。

      data uniques dups;
        set have;
        by <all 54 variables> notsorted;
        if not (first.<last variable in the list>) then output dups;
        else output uniques;
      run;
      

      这告诉 SAS 如果事情的顺序不正确,不要抱怨,而是让您使用第一个/最后一个。虽然不是一个很好的选择,但特别是因为您需要指定所有内容。


      最快的方法可能是为此使用哈希表,如果你有足够的 RAM 来处理它,或者你可以以某种方式分解你的表(不会丢失你的重复)。 10m 行乘以 54(比如 10 字节)变量意味着 5.4GB 的数据,所以这只有在您有 5.4GB 的 RAM 可供 SAS 用于制作哈希表时才有效。

      如果您知道 54 个变量中的一个子集足以验证唯一性,那么 unique 哈希只需包含这些变量子集(即,它可能只有四个或五个索引变量)。 dups 哈希表必须包含所有变量(因为它将用于输出重复项)。

      这通过使用modify 来快速处理数据集,而不是重写大部分观察结果;使用remove 删除它们并使用哈希表output 方法将重复项输出到新数据集。 unq 哈希表仅用于查找 - 因此,同样,它可以包含变量的子集。

      我在这里还使用了一种技术,将完整的变量列表放入一个宏变量中,这样您就不必输入 54 个变量了。

      data class;   *make some dummy data with a few true duplicates;
        set sashelp.class;
        if age=15 then output;
        output;
      run;
      
      proc sql;
        select quote(name) 
          into :namelist separated by ','
          from dictionary.columns
          where libname='WORK' and memname='CLASS'
        ;  *note UPCASE names almost always here;
      quit;
      
      data class;
        if 0 then set class;
        if _n_=1 then do;               *make a pair of hash tables;
           declare hash unq();
           unq.defineKey(&namelist.);
           unq.defineData(&namelist.);
           unq.defineDone();
           declare hash dup(multidata:'y'); *the latter allows this to have dups in it (if your dups can have dups);
           dup.defineKey(&namelist.);
           dup.defineData(&namelist.);
           dup.defineDone();
        end;
        modify class end=eof;
        rc_c = unq.check();           *check to see if it is in the unique hash;
        if rc_c ne 0 then unq.add();  *if it is not, add it;
        else do;                      *otherwise add it to the duplicate hash and mark to remove it;
          dup.add();
          delete_check=1;
        end;
      
        if eof then do;                      *if you are at the end, output the dups;
          rc_d = dup.output(dataset:'work.dups');
        end;
      
        if delete_check eq 1 then remove;        *actually remove it from unique dataset;
      run;
      

      【讨论】:

      • 乔,如果数据未排序,您是否不需要两种排序,因为 noduprecs 仅删除相邻的重复项或 SAS 解决了该问题?另外,我没有在 SAS 9.4 文档中看到 noduprecs。
      • 嗯。我以为他们解决了这个问题-但我会看的。 (当然,您可以通过按每个字段排序来避免两种排序,但这很麻烦。)
      • @Reeza 嗯,我也看到它在 9.4 中丢失了。尽管我认为我记得 9.4 更改日志中的某些内容,但我找不到更改 noduprecs 的证据,所以我现在将调整答案,除非我再次找到它。感谢您了解这一点。
      • 我对此进行了简单的测试,看起来哈希解决方案并不像 Rob 的解决方案那样比 proc sort 快(或者只是对整个数据集的变量执行 nodupkey)。在某些情况下,这可能比 proc 排序更快,但考虑到所需的代码更多,我认为这并不是一个更好的解决方案。
      猜你喜欢
      • 2019-03-17
      • 1970-01-01
      • 1970-01-01
      • 2016-10-31
      • 1970-01-01
      • 2012-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多