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