没有 proc SQL 的模糊连接



美好的一天,

我希望将两个日期合并到下一个最接近的日期。

数据集从500Mb到1G是巨大的,所以proc sql是不可能的。

我有两个数据集。第一个(舰队)有观测值,第二个有日期以及用于进一步处理的代号。喜欢这个:

data Fleet
CreatedPortalDate 
2013/2/19 
2013/8/22 
2013/8/25 
2013/10/01 
2013/10/07 
data gennum_list
date 
01/12/2014 
08/12/2014 
15/12/2014 
22/12/2014 
29/12/2014 
...

我想要的是这样的链接表:

data link_table
CreatedPortalDate date 
14-12-03  01/12/2014 
14-12-06  01/12/2014 
14-12-09  08/12/2014 
14-12-11  08/12/2014 
14-12-14  08/12/2014 

用逻辑

Date < CreatedPortalDate and (CreatedPortalDate - date) = min(CreatedPortalDate - date)

我想出的有点笨拙,我正在寻找一种有效/更好的方法来实现这一目标。

data all_comb; 
set devFleet(keep=createdportaldate);
do i=1 to n;
set gennum_list(keep=date) point=i nobs=n;
if createdportaldate > date 
and createdportaldate - 15 < date then do;/*Assumption, the generations are created weekly.*/
distance= createdportaldate - date; 
output; 
end;
end;
run;
proc sort data=all_comb; by createdportaldate distance; run;
data link_table; 
set _all_comb(drop=distance); 
by createdportaldate; 
if first.createdportaldate; 
run;
  • 任何想法如何改进或解决这个问题?
  • 无知的想法:我可以创建存储distance的哈希表吗?
  • 也许是阵列?不知何故。

编辑:

  • 通用格式
  • 十亿行从何而来?
    • 是的,还涉及其他数据,但日期是唯一的链接变量。
  • 排序?
    • 是的,数据已排序,可以再次排序。
  • 世代日期总是相隔七天吗?
    • 不。这是棘手的部分。 否则,我可以使用weekyear(或其他分箱)作为唯一标识符。

巨大是一个相对术语,今天的巨大是明天的斑点。

关键数据特征表明直接寻址查找方案是可能的

  • 日期值为整数。
  • 日期值范围有限。
  • 日期值或接下来 14 天中的任何一天将用作查找验证程序
  • 键是一个日期值,可用作数组索引。

加载一次Gennum查找,如下所示

array gennum_of ( %sysfunc(today()) ) _temporary_;
if last_date then
do index = last_date to date-1;
gennum_of(index) = prev_date;
end;
last_date = date;

并获取一个Gennum作为

if portaldate > last_date
then portal_gennum = last_date;
else portal_gennum = gennum_of ( portaldate );

如果由于按帐户 ID 分组而有很多行,则必须清除并加载每个组的 gennum 数组。

这是

sasby语句的典型应用。

data步骤中的by语句旨在读取两个或多个数据集,按公共变量排序。

公共变量是日期,但在两个数据集上的名称不同。在sql中,您可以通过要求一个变量与另一个变量相等来解决这个问题Fleet.CreatedPortalDate = gennum_list.date,但是by语句不允许这样的构造,因此我们必须在读取数据集时重命名(至少)其中一个变量。这就是我们在rename条款中所做的gennum_list

data all_comb;
merge gennum_list (in = in_gennum rename = (date = CreatedPortalDate))
Fleet (in = in_fleet);
by CreatedPortalDate;

我选择将by语句与merge语句组合在一起,尽管set也可以完成这项工作,但是两个输入数据集的顺序会有所不同。

另请注意,我请求 sas 创建指示变量in_gennumin_fleet,以指示值存在于哪个输入数据集中。知道这种类型的变量 id 未写入结果数据集很方便。

但是,我们必须从CreatedPortalDate中恢复date,当然

if in_gennum then date = CreatedPortalDate;

如果您不熟悉 sas,您会惊讶于上述语句不起作用,除非您明确指示 sas 将日期值从一个观察值retain到嵌套。(观察是行的行话。

retain date;

在这里,我们为从Fleet数据集读取的每个观察值写出一个观察结果。

if in_fleet then output;
run;

这种方法的优点是

  • 您需要更少的逻辑来正确组合来自两个输入数据集的观测值(这就是发明data步骤的目的)
  • 您永远不必在内存中保留值数组,因此不会有溢出问题
  • 这种解决方案在数据集的大小(除了排序)中是 1 阶 (O1),因此我们预先知道,数据量加倍只会使时间加倍。

    免责声明:此答案正在构建中。

它将在本周晚些时候进行测试

最新更新