高效地将SAS数据集转换为CSV

26

有人能告诉我将SAS数据集以编程方式快速转换为CSV文件的最佳方法吗?我知道可以使用数据步骤并输出到文件等方式。但那是唯一的方法吗?

谢谢, Adnan。

4个回答

35

类似这样的东西?

proc export data=sashelp.class
    outfile='c:\temp\sashelp class.csv'
    dbms=csv
    replace;
run;

是的,那是我们讨论过的选项之一。您知道它与数据步骤方法相比如何扩展吗? - Adnan
4
根据日志,proc export 生成一个data null步骤来写出文本文件。因此,我猜测从一开始就使用data步骤在CPU时间方面会更有效率。使用data步骤可以更好地控制输出。 - rkoopmann
1
我可能最终会使用数据 _null_,因为我希望控制导出哪些列以及列值的格式化/非格式化等方式。 - Adnan
1
我注意到在批处理模式下运行使用proc export创建csv或其他平面文件的SAS程序时,必须使用-noterminal选项。 - Banjer

11

你错过了 %ds2csv 宏:http://support.sas.com/documentation/cdl/en/lebaseutilref/64791/HTML/default/viewer.htm#n0yo3bszlrh0byn1j4fxh4ndei8u.htm - Robert Penridge

8
这里提到了许多创建csv的方法,但并未涉及这些方法的效率。我创建了一个包含100,000行和5列的样本数据集(temp)来测试和比较将SAS数据集导出为名为temp.csv的csv文件的方法。
第一种方法:使用导出过程。运行时间:0.43秒。
PROC EXPORT data=temp 
     outfile="temp.csv" dbms=csv replace;

快速运行时间和简单的内置灵活性,可选择其他选项。但是,对于自定义方面并不是最强的。


第二种方法:使用Print过程的ODS。 运行时间:14.09秒。

ODS csv file="temp.csv";
PROC PRINT data=temp noobs;
RUN;
ods csv close;

这种方法对于大多数情况来说是三种选项中最差的选择,虽然有一些特殊用例。它适用于临时输出以前编写过的过程,特别是如果你希望输出保留在lst文件中(如果不太大的话)。当你想要将另一个过程(例如复杂的tabulate)转换为文件而无需进一步操作时,这种方法也可能会很有用。如果您不需要在lst文件中打印输出,请关闭您的清单(ods listing close),否则这将花费更长的时间。
第三种方法:文件声明。运行时间:0.06秒。
DATA _null_;
    FILE "temp.csv ";
    SET temp;
    put (_all_) (',');
RUN;

虽然这种方法的性能并不差,但它不直观且看起来令人困惑。正如上面提到的,您可以更好地控制输出,并且它是所有方法中运行时间最快的。


3
注意:使用 data null 方法不会在您的 .csv 文件的第一行输出变量名称,这可能会成为一个问题。 - Ketil Tveiten
1
你应该在FILE语句中使用DSD选项,而不是手动编写分隔符。否则,你可能得到一个无法解密的文件。请注意,添加一些代码来编写标题行并不是很难。 - Tom
@Tom 我感觉另一个答案正在路上...? - mjsqu

3

修改的data _NULL_方法

这是对data _NULL_方法的一种修改,它在第一个数据步骤中将标题行写入文件,然后在第二个数据步骤中继续用数据行写入同一文件。

%macro outputCSV(dataset,file);
data _NULL_;
   file "&file." dlm=',' dsd;
   length header $ 2000;
   dsid=open("&dataset.","i");
   num=attrn(dsid,"nvars");
   do i=1 to num;
      header = trim(left(coalescec(varlabel(dsid,i),varname(dsid,i))));
      put header @;
   end;
   rc=close(dsid);
run;

data _NULL_;
   set &dataset.;
   file "&file." mod dlm=',' dsd;
   put (_all_) (+0);
run;
%mend;

%outputCSV(sashelp.class,~/temp4.csv)

它可以与keepdrop数据集选项一起使用(令人惊讶的是),但不幸的是,当使用open()打开数据集时,nvars属性会考虑在keepdrop后的新变量数,但是varlabelvarname函数仍然使用它们的varnum查找变量。

在下面的示例中,从SASHELP.CLASS中仅提取Name(varnum=1)和Height(varnum=4),因为只保留了两个变量,nvars为2。但如果我们循环迭代num作为上限,我们会错过Height,因为它的varnum为4:
 62         data _NULL_;
 63           dsid = open("sashelp.class (keep=name height)","i");
 64           num = attrn(dsid,"nvars");
 65           do i=1 to 5;
 66             vname = varname(dsid,i);
 67             put i= vname= num=;
 68           end;
 69         run;
 
 i=1 vname=Name num=2
 NOTE: Argument 2 to function VARNAME(1,2) at line 66 column 13 is invalid.
 i=2 vname=  num=2
 NOTE: Argument 2 to function VARNAME(1,3) at line 66 column 13 is invalid.
 i=3 vname=  num=2
 i=4 vname=Height num=2
 NOTE: Argument 2 to function VARNAME(1,5) at line 66 column 13 is invalid.
 i=5 vname=  num=2
 dsid=1 num=2 i=6 vname=  _ERROR_=1 _N_=1

有两个选项:

  • 通过去掉第一遍的数据集选项来提取真正的nvars
  • 使用一个非常高的数字代替num,尽管这只会在日志中产生大量'invalid'提示

这是第一种方法,需要调用两次open函数:

%macro outputCSV(dataset,file);
data _NULL_;
   file "&file." dlm=',' dsd;
   length header $ 2000;
   dsid=open("%SCAN(&dataset.,1,()","i");
   num=attrn(dsid,"nvars");
   rc=close(dsid);
   dsid=open("&dataset.","i");
   do i=1 to num;
      header = trim(left(coalescec(varlabel(dsid,i),varname(dsid,i))));
      if _error_ = 0 then put header @;
      _error_ = 0;
   end;
   rc=close(dsid);
run;

data _NULL_;
   set &dataset.;
   file "&file." mod dlm=',' dsd;
   put (_all_) (+0);
run;
%mend;

%outputCSV(sashelp.class (keep=name height),~/temp4.csv)

在写完所有内容之后,大多数情况下选择使用PROC EXPORT或者如果没有太多变量,则明确列出变量可能更合适。这只是展示了可以做什么。


1
不需要使用那些陈旧的SCL函数,只需使用PROC TRANSPOSE创建一个按顺序排列的变量名数据集。proc transpose data=have(obs=0) out=name; var _all_; run; 然后使用简单的数据步骤编写标题行。接着在编写实际数据行的数据步骤中,在文件语句中添加MOD选项。 - Tom
是的,很好的想法,我曾尝试使用array _character_及其对应项,但无法按顺序输出列。 - mjsqu
感谢 @mjsqu!这是一个很好的答案 - 我将您的代码整合到我们的宏库中,希望这没问题:https://core.sasjs.io/mp__ds2csv_8sas.html - Allan Bowe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接