Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/hadoop/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在SAS中合并大型数据集_Sas - Fatal编程技术网

在SAS中合并大型数据集

在SAS中合并大型数据集,sas,Sas,我需要SAS大师的建议:)。 假设我有两个大数据集。第一个是一个巨大的数据集(大约50-100Gb!),其中包含电话号码。第二个包含前缀(2-4万个观测值)。 我需要为每个电话号码在第一个表中添加最合适的前缀 例如,如果我有一个电话号码+71230000和前缀 +7 +71230 +7123 最合适的前缀是+71230 我的主意。首先,对前缀表进行排序。然后在数据步骤中,处理电话号码表 data OutputTable; set PhoneNumbersTable end=_last;

我需要SAS大师的建议:)。
假设我有两个大数据集。第一个是一个巨大的数据集(大约50-100Gb!),其中包含电话号码。第二个包含前缀(2-4万个观测值)。 我需要为每个电话号码在第一个表中添加最合适的前缀

例如,如果我有一个电话号码
+71230000
和前缀

+7
+71230
+7123
最合适的前缀是
+71230

我的主意。首先,对前缀表进行排序。然后在数据步骤中,处理电话号码表

data OutputTable;
    set PhoneNumbersTable end=_last;
    if _N_ = 1 then do;
        dsid = open('PrefixTable');
    end;
    /* for each observation in PhoneNumbersTable:
       1. Take the first digit of phone number (`+7`).
          Look it up in PrefixTable. Store a number of observation of
          this prefix (`n_obs`).
       2. Take the first TWO digits of the phone number (`+71`).
          Look it up in PrefixTable, starting with `n_obs + 1` observation.
          Stop when we will find this prefix
          (then store a number of observation of this prefix) or
          when the first digit will change (then previous one was the
          most appropriate prefix).
       etc....
    */
    if _last then do;
        rc = close(dsid);
    end;
run;
我希望我的想法足够清楚,但如果不清楚,我很抱歉)

那你有什么建议? 谢谢你的帮助


当然,第一个表中的电话号码不是唯一的(可能会重复),不幸的是,我的算法没有使用它。

有几种方法可以做到这一点,可以使用格式或哈希表

使用格式的示例:

/* Build a simple format of all prefixes, and determine max prefix length */ data prefix_fmt ; set prefixtable end=eof ; retain fmtname 'PREFIX' type 'C' maxlen . ; maxlen = max(maxlen,length(prefix)) ; /* Store maximum prefix length */ start = prefix ; label = 'Y' ; output ; if eof then do ; hlo = 'O' ; label = 'N' ; output ; call symputx('MAXPL',maxlen) ; end ; drop maxlen ; run ; proc format cntlin=prefix_fmt ; run ; /* For each phone number, start with full number and reduce by 1 digit until prefix match found */ /* For efficiency, initially reduce phone number to length of max prefix */ data match_prefix ; set phonenumberstable ; length prefix $&MAXPL.. ; prefix = '' ; pnum = substr(phonenumber,1,&MAXPL) ; do until (not missing(prefix) or length(pnum) = 1) ; if put(pnum,$PREFIX.) = 'Y' then prefix = pnum ; pnum = substr(pnum,1,length(pnum)-1) ; /* Drop last digit */ end ; drop pnum ; run ; /*构建所有前缀的简单格式,并确定最大前缀长度*/ 数据前缀_fmt; 设置prefixtable end=eof; 保留fmtname“PREFIX”类型“C”maxlen; maxlen=max(maxlen,长度(前缀));/*存储最大前缀长度*/ 开始=前缀; 标签='Y'; 产出; 如果是eof,那么做; hlo='O'; 标签='N'; 产出; 调用symputx('MAXPL',maxlen); 结束; 放下马克斯伦; 跑 proc format cntlin=前缀\u fmt;跑 /*对于每个电话号码,从完整号码开始,减少1位数,直到找到前缀匹配为止*/ /*为了提高效率,最初将电话号码减少到最大前缀的长度*/ 数据匹配前缀; 设置电话号码表; 长度前缀$&MAXPL; 前缀=“”; pnum=substr(phonenumber、1和MAXPL); 直到(不缺少前缀)或长度(pnum)=1); 如果put(pnum,$PREFIX.)为'Y',则PREFIX=pnum; pnum=substr(pnum,1,长度(pnum)-1);/*删除最后一位*/ 结束; 降pnum; 跑
下面是一个哈希表示例

生成一些虚拟数据

data phone_numbers(keep=phone)
     prefixes(keep=prefix);
     ;

  length phone $10 prefix $4;
  do i=1 to 10000000;
    phone = cats(int(ranuni(0) * 9999999999 + 1));
    len = int(ranuni(0) * 4 + 1);
    prefix = substr(phone,1,len);
    if input(phone,best.) ge 1000000000 then do;
      output;
    end;
  end;

run;
假设最长前缀为4个字符,请首先尝试查找最长前缀的匹配项,然后继续,直到尝试了最短前缀。如果找到匹配项,则输出记录并继续进行下一次观察

data ht;
  attrib prefix length=$4;

  set phone_numbers;

  if _n_ eq 1 then do;
    declare hash ht(dataset:"prefixes");
    ht.defineKey('prefix');
    ht.defineDone();
  end;

  do len=4 to 1 by -1;
    prefix = substr(phone,1,len);
    if ht.find() eq 0 then do;
      output;
      leave;
    end;
  end;

  drop len;

run;

如果未找到匹配项,可能需要添加逻辑以输出记录,并将前缀字段留空?不确定您希望如何处理这种情况。

这里有另一个解决方案,它在速度方面非常有效,只要您可以在一个主要(也许可以)限制下工作:电话号码不能以0开头,并且必须是数字或转换为数字(即,不需要查找“+”)

我正在做的是构建一个1/null标志数组,每个可能的前缀一个1/null标志。但这不适用于前导0:因为“9512”和“09512”是相同的数字。这是可以解决的-在开始时添加一个“1”(因此,如果您可能有6位前缀,那么所有内容都是1000000+前缀),例如可以解决-但需要调整以下内容(可能会影响性能,尽管我认为不会太坏)。如果还需要“+”,则可能需要将其转换为数字;在这里,你可以说任何在开头加上“+”的词,比如2000000

好在每行最多只需要6个数组查询(大约),比其他任何搜索选项都快(因为临时数组是连续的内存块,所以只需“检查预先计算的6个内存地址”)。散列和格式化将是一个相当慢的块,因为它们必须重新查找每个块

一个主要的性能建议是:注意前缀可能不匹配的方式。检查6然后5然后4然后。。。可能更快,或者先检查1然后检查2然后检查3然后。。。可能更快。这完全取决于实际的前缀本身,以及实际的电话号码。如果你的大多数前缀是“+11”之类的,你几乎肯定会想从左边开始,如果这个人的一个带有“94”的数字很快就会被发现不匹配

有了这一点,解决办法就来了

data prefix_match;
  if _n_=1 then do;
    array prefixes[1000000] _temporary_;
    do _i = 1 to nobs_prefix;
      set prefixes point=_i nobs=nobs_prefix;
      prefixes[prefix]=1;
    end;
    call missing(prefix);
  end;  
  set phone_numbers;
  do _j = 6 to 1 by -1;
    prefix = input(substr(phone_no,1,_j),6.);
    if prefix ne 0 and prefixes[prefix]=1 then leave;
    prefix=.;
  end;
  drop _:;
run;

对于一个有40k个前缀和100m个电话号码(没有其他变量)的测试集,它在我(好的)笔记本电脑上运行了一分钟多一点,相比之下,6个前缀和100m个电话号码随格式解决方案而变化,4个前缀和100m个电话号码随哈希解决方案而变化(修改它以输出所有行,因为其他两个解决方案都是这样)。在我看来,这在性能方面是正确的。

太好了!谢谢!:)你能解释一下为什么要使用
drop maxlen语句而不是
drop=maxlen
option?,因为drop=不是drop语句的正确语法。您一定在考虑删除数据集选项。我估计运行一个50 gig的文件大约需要1到2个小时。因为这个问题是向SAS专家提出的,而且还涉及大数据,我想知道您是否可以帮助我回答有关SAS数据存储选项和大数据的一般问题:。我试图将SAS数据存储与常规RDBMS(如SQL Server)进行比较。在这方面的任何帮助都是非常感谢的。