【问题标题】:SAS: Huge file/many tasks: split file into smaller, or split up the tasks?SAS:巨大的文件/许多任务:将文件拆分成更小的文件,还是拆分任务?
【发布时间】:2015-06-28 21:30:06
【问题描述】:

我有高频财务数据(毫秒),很多列,137 个 mio 观察/行,总大小 32Gb。我想使用 PROC TIMESERIES 将观察结果聚合到 30 秒的容器中。我的初始命令涉及很多变量/任务。

proc timeseries data=DATA out= DATA_SEC30; 
id DATETIME interval=sec30 setmissing=missing align=beg start = '01jan1999.00:05'dt end = '01dec2014.00:00'dt; 
var TRADE BID ASK MID / accumulate=last;
var TIME / accumulate=last;
var OF VOL / accumulate=total;
var DATE / accumulate=N;
run;

如果我运行此代码,我会收到以下错误消息:

错误:无法分配足够的内存。至少请求了 312070K 字节。您必须要么增加可用内存量,要么以不同的方式解决问题。

我的问题是解决问题的最佳方法是什么?

A) 将文件拆分为更小的(非重叠)文件,例如。日期,然后在每个子文件上运行上面的代码,最后把它们放在一起? 或

B) 将上述代码按步骤拆分,例如每个 VAR 语句一个,但在完整文件上运行?

答案可能是特定于程序的,也可能是特定于计算机的(但我希望得到一个“一般”的答案)。我使用 PROC TIMESERIES,计算机是一个服务器,SAS 分配了大约 256Gb 内存。

【问题讨论】:

    标签: sas


    【解决方案1】:

    首先,鉴于您遇到的特殊问题,我建议您联系 SAS 技术支持。您为 SAS 支付了很多钱,而您获得的一件事是对此类问题的几乎实时支持——通常来自 proc 的开发人员自己。一旦您超越了基本数据步骤和简单的过程(如SUMMARY/MEANS、TABULATE、FREQ 等),并进入高内存强度的东西(如TIMESERIES),通常会有一些特定于过程的优化,只有少数人可以做到可能知道。

    对于一般中哪种方法最适合解决此类问题,没有一个答案。当它不会影响结果时,最好拆分观察而不是为不同的变量重新运行 proc。这是因为 I/O 限制;四次读取相同的 32GB 与读取四次 8GB,后者显然更好。当然,有时(比如在回归分析中)这会改变结果,因此是不可取的。

    如果可能,您也可以使用 BY 语句来提供帮助。这避免了实际拆分数据集的必要性;相反,您有一些变量定义了一个组,并通过该 ID 运行,允许您一次调用一次运行 proc,但多次有效地运行分析,并仅生成一个最终输出数据集。这通常(但并非总是)避免内存不足的情况。我不知道 PROC TIMESERIES 是否适用于此,但我认为它可能适用于您的情况。

    这是一个示例,使用 PROC TIMESERIES 的the second example from the documentation。首先,我在整个 SASHELP.AIR 数据集上运行它,然后按年份组(这是四舍五入到最接近 5 倍数的年份)。注意 SERIES 数据集是如何相同的;因此,分析的那部分工作正常。但是 SEASON 数据集不相同,因为 BY 组分析意味着每个 BY 值都有单独的季节集。您需要了解 PROC TIMESERIES 如何处理您的数据,以了解 BY 组是否会影响事物。

     proc timeseries data=sashelp.air
                       out=series
                       outtrend=trend
                       outseason=season print=seasons;
          id date interval=qtr accumulate=avg;
          var air;
       run;
    
    
    
    data air;
      set sashelp.air;
      yeargroup = round(year(date),5);
    run;
    
     proc timeseries data=work.air
                       out=series2
                       outtrend=trend
                       outseason=season print=seasons;
          by yeargroup;
          id date interval=qtr accumulate=avg;
          var air;
       run;
    
       proc compare base=series compare=series2;
       run;
    

    【讨论】:

      【解决方案2】:

      为了在编写最少的代码和资源效率之间取得合理的折衷,我可能会使用不同的数据集选项多次运行 proc timeseries,例如

      proc timeseries data=DATA(firstobs = 1 obs = 10000000)...
      proc timeseries data=DATA(firstobs = 10000001 obs = 20000000)...
      

      在您的情况下,似乎只需将处理拆分为两次运行就足够了。像这样使用 obs 和 firstobs 可以避免创建索引或临时数据集,也可以避免读取整个数据集两次,因为 SAS 只需在第二次运行中寻找 firstobs 的位置,即无需实际读取任何先前的观察。

      根据您对proc timeseries 所做操作的复杂性以及其他人是否需要在您的服务器上使用大量内存,您可能会发现编写等效的数据步骤是值得的。这将在一次传递中为您提供一个输出数据集,并且会消耗更少的内存(可能只有几百 KB),但可能需要更多的工作来编写和维护。

      【讨论】:

      • 谢谢。 Observation num 1000001 可能处于 30 秒间隔的中间。我可以改用 WHERE 语句,使用日期吗?
      • 如果你担心这个问题,你可以编写一个从 obs 开始的试验数据步骤。 1000001 并继续读取记录,直到找到 30 秒周期的结尾。使用 where 子句/语句将花费至少两倍的时间,因为这将涉及对整个数据集进行多次读取以查看哪些记录匹配。如果您的数据集在时间变量上被索引,它可能不会那么糟糕,但不会差很多。
      猜你喜欢
      • 1970-01-01
      • 2013-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-14
      • 1970-01-01
      • 2013-06-01
      相关资源
      最近更新 更多