【问题标题】:SAS: Improving the speed of a do loop with proc importSAS:使用 proc import 提高 do 循环的速度
【发布时间】:2014-02-13 00:07:48
【问题描述】:

我有超过 3400 个 CSV 文件,大小在 10kb 到 3mb 之间。每个 CSV 文件都有这个通用文件名:stockticker-Ret.csv 其中stockticker 是股票代码,如 AAPL、GOOG、YHOO 等,并且在给定日期的每一分钟都有股票回报。我的 SAS 代码首先从 SAS 数据集中的 stockticker-Ret.csv 文件中加载所有股票代码名称。我遍历每个股票代码以将适当的.csv 文件加载到名为want 的SAS 数据集中,并在want 上应用一些数据步骤,并将每个股票代码的最终数据集want 存储在名为global 的SAS 数据集中。可以想象,这个过程需要很长时间。有没有办法改进我下面的DO LOOP 代码以使这个过程更快?

/*Record in a sas dataset all the csv file name to extract the stock ticker*/
    data yfiles;
    keep filename;
    length fref $8 filename $80; 
    rc = filename(fref, 'F:\data\'); 
    if rc = 0 then do; did = dopen(fref); 
    rc = filename(fref); end; else do; length msg $200.; msg = sysmsg(); put msg=; did = .; end;
    if did <= 0 then putlog 'ERR' 'OR: Unable to open directory.';
    dnum = dnum(did);
    do i = 1 to dnum; filename = dread(did, i); /* If this entry is a file, then output. */ fid = mopen(did, filename); if fid > 0 then output; end;
    rc = dclose(did);
    run;

/*store in yfiles all the stock tickers*/
    data yfiles(drop=filename1 rename=(filename1=stock));
    set yfiles;
    filename1=tranwrd(filename,'-Ret.csv','');
    run;

    proc sql noprint;
    select stock into :name separated by '*' from work.yfiles;
    %let count2 = &sqlobs;
    quit;


    *Create the template of the desired GLOBAL SAS dataset;
    proc sql;
    create table global
    (stock char(8), time_gap num(5), avg_ret num(5));
    quit;

    proc sql;
    insert into global
    (stock, time_gap,avg_ret)
    values('',0,0);
    quit;

    %macro y1;
    %do i = 1 %to &count2;
    %let j = %scan(&name,&i,*);
    proc import out = want datafile="F:\data\&j-Ret.csv"
    dbms=csv replace;
    getnames = yes;
    run;


    data want;
    set want; ....

    ....[Here I do 5 Datasteps on the WANT sasfile] 


/*Store the want file in a global SAS dataset that will contain all the stock tickers from the want file*/

    data global;
    set global want; run;

    %end;
    %mend y1;
    %y1()

如您所见,全局 SAS 数据集针对我存储在 global 中的每个 want 数据集进行扩展。

【问题讨论】:

  • 文件有共同的布局吗?
  • 是的,他们有一个共同的布局

标签: performance sas do-loops


【解决方案1】:

假设文件有一个共同的布局,你不应该用PROC IMPORT 导入它们或做循环。您应该使用一个数据步将它们全部阅读。即:

data want;
length the_file $500;
infile "f:\data\*.csv" dlm=',' lrecl=32767 dsd truncover firstobs=2 filename=the_file;
input
myvar1 myvar2 myvar3 myvar4;
stock_ticker=scan(the_file,'\',-1); *or whatever gets you the ticker name;
run;

现在,如果它们没有相同的布局,或者 readin 有一些复杂性,您可能需要比这更复杂的输入语句,但几乎总是可以通过这种方式实现。由于 IMPORT 的开销,具有大量 PROC IMPORT 的 Do 循环总是效率低下。

如果您不希望文件夹中的每个 .csv 文件(并且无法为您想要的内容编写掩码),或者如果您有一部分布局,则可以使用 FILEVAR 选项来读取文件来自一个共同的数据集。然后,如果需要,您可以分支到各种输入语句。

data want;
set yfiles;
infile a filevar=filename;
if filevar [some rule] then do;
input ... ;
end
;else if ... then do;
input ... ;
end;
run;

【讨论】:

  • 感谢您的回复。我喜欢第一个选项,但问题是,如果我将所有 csv 文件堆叠到一个 SAS 数据集开始,我无法区分每个“堆叠”,因为我不知道股票代码(或 ID,如果你愿意) 因为它们不在 csv 文件中。关于如何处理的建议?
  • 是的,您可以从 infile 语句中获取文件名 - 将更新答案。
  • 出色地完成了这项工作。我会看看它在整个数据步骤中的效果如何
猜你喜欢
  • 1970-01-01
  • 2015-03-24
  • 1970-01-01
  • 2019-08-01
  • 2014-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-16
相关资源
最近更新 更多