数据集 firstobs 中的错误

Posted

技术标签:

【中文标题】数据集 firstobs 中的错误【英文标题】:Error in data set firstobs 【发布时间】:2014-01-10 17:45:29 【问题描述】:

我对 SAS 非常非常陌生,并且一直在阅读 *** 问题和 SAS 文档,以便为非常特定的目的编写代码。我一直很难实现我的目标和理解 SAS,原因有两个:我只能通过 SSH 在远程服务器上执行代码,因为我本地没有 SAS(因此,每次更改时,我都需要上传文件,执行并取回日志和 lst 文件,检查错误),并且我读过的大多数介绍性主题并不立即适用于我的任务(我只对使用 SAS 自动执行某个数据提取过程感兴趣)。

我的目标是:

读取 CSV 文件中的某些代码(即股票的标识符); 循环每个代码,通过某些宏检索我需要的信息。

到目前为止,我已成功读取 .csv 并将该数据导入数据集。为了测试我需要的基础知识是否正常工作,我编写了以下代码。我的目标是通过一个循环将代码分配给某个“变量”currentticker(可能不是正确的名称)并打印它。 csv 文件只有两行,第一行是“IBM”,另一行是“DELL”。

libname mydir '~/';

data companies;
  infile 'sastests/data/tickers.csv' delimiter=',';
  input ticker $;
run;

proc sql;
 select    count(*)
 into      :OBSCOUNT
 from      companies;
quit;

proc print data=companies;
  var ticker;
run;

%do iter = 1 to &OBSCOUNT;
  data currentticker;
    set companies (firstobs = iter obs = iter);
  run;
  proc print data = currentticker;
  run;
%end;

当我浏览日志文件时,我在数据集的 firstobs 选项中立即收到错误。

Invalid value for the FIRSTOBS option.

为什么会这样? iter 不应该是一个数字,从而作为 FIRSTOBS 有效吗?

非常感谢您。

编辑 1:标题不能很好地描述问题。

编辑 2:用于单个代码的宏示例。必须使用 &ticker 提供查找。将调用lookup,然后调用getopt,最后调用export_tab。此代码不是我的作者,在 WRDS 作为示例代码提供后,我对其稍作修改。

%macro lookup;

  data idcodes (keep=secid);
  set optionm.secnmd;
  where lowcase(ticker) = &ticker;

  proc sort data=idcodes nodupkey;
    by secid;

  proc print data=idcodes;

%mend;

%macro getopt(year);

  proc sql;
    create table temp as
      select a.* 
      from
        optionm.vsurfd&year as a,
        idcodes as b
      where
        a.secid = b.secid;
  run;

  proc datasets;
    append base=work.&outputfile
    data=work.temp;
  run;

%mend;

%macro export_tab;

  proc export data=&outputfile outfile="&outputfile._out.txt" dbms=tab replace;
  run;

%mend;

【问题讨论】:

读入这些数据后,您实际上在 SAS 中做什么?如果您只是在执行上述操作,那么 SAS 是一个糟糕的工具(perl 会更好,python 等等)。如果您正在做一些更复杂的事情,如果您解释一下您在做什么,那么很有可能有更好的方法来做。 您当然可以将我的方法与那组宏一起使用。基本上,如果idcodes 数据集包含您想要的所有代码的所有 idcode,那么其余代码都可以正常工作。然后,当您进行导出时,您只需使用filevar 选项和文件名变量中的代码名称将导出从使用proc export 更改为数据步骤写入(就像我在回答中写的那样)。 dlm='09'x 如果你想用制表符分隔。 请注意您已经写了:%do iter = 1 to &OBSCOUNT;您实际上还需要在 to 前面有一个百分比: %do iter = 1 %to &OBSCOUNT; 【参考方案1】:

你需要在宏变量前面加上&,所以firstobs=&iter.

但是,我不确定您是否真的想这样做。几乎可以通过对数据集进行宏迭代来做任何事情,您可以通过对数据集进行常规迭代来做,也许还可以使用 BY 组。与使用内置 SAS 技术相比,宏迭代效率非常低。

要为数据集中的每一行调用一组代码,您可以执行以下操作。

%macro pulldata(ticker);
data stock_data;
set big_database;
where ticker="&ticker";
file "c:\mydir\myfile_&ticker..csv" dlm=',' lrecl=32767; *double period - first is macro variable delimiter;
put (_all_) ($);
run;
%mend pulldata;

data _null_;
set companies;
call execute('%pulldata(',ticker,')');
run;

您也可以这样做,我们使用filevar 选项允许将数据集放到多个文件中(必须按filevar 排序!)

proc sql;
select quote(ticker) into :tickerlist separated by ',' from companies;
quit;

data mydata;
set bigdata;
where ticker in (&tickerlist.);
filen = cats('c:\mydata\myfile_',ticker,'.csv');
run;

proc sort data=mydata;
by filen;
run;

data _null_;
set mydata;
file a filevar=filen dlm=',' lrecl=32767;
put (_all_) ($);
run;

【讨论】:

感谢您的回答。我正在访问 WRDS,这是一项将多个学术数据库分组的研究服务,他们自己建议使用 SAS。我没有使用不允许我进行批量数据请求的 Web 界面,而是寻求使用 SAS 来自动化我需要的数据提取。因此,我的想法是获取我想要提取数据的股票列表,然后逐个请求它(我需要单独的文件)。我已经成功地为一只股票使用了一个示例 SAS 脚本,并且它执行得非常快,所以就我的目的而言,它似乎是一个不错的选择。 啊,好的。所以你可能想要做的是创建一个包含所有你需要的文件的数据集,然后不管你的代码是什么,从 WRDS 中提取文件,把它放在一个宏中,接受像“股票名称”之类的参数。然后使用 CALL EXECUTE 调用该宏。我将在答案中编辑一个简短的解释。 (继续)基本思想是:获取一个代码列表,然后为每个代码执行一些宏(尚未编码)以提取我需要的数据 - 这实际上是打开 .sas 文件,执行 proc sql 以将数据限制为我需要的数据,并输出到 .csv 文件。 我上面列出的一般方法可能是更好的方法 - 第二种可能是最好/最有效的,前者是可以的(这是一种更有效的方法来做你想做的事情做)。数据步骤会很高兴地自行迭代,您无需请求宏来为您完成。【参考方案2】:

这基本上是另一个答案,所以把它放在这里。这就是我处理第二部分的方式——根本没有宏。我假设他们的年度数据集已经按 secid 排序;如果没有,这可能会有点复杂,只是为了避免合并。

proc sql;
select quote(ticker) into :tickerlist separated by ',' from companies;
quit;

data idcodes;  *you could also create this by merging optiomn.secnmd to companies by ticker.;
set optionm.secnmd;
where lowcase(ticker) in (&tickers.);
run;

proc sort data=idcodes nodupkey;
by secid;
run;

proc print data=idcodes;
run;

data lotsofyears/view=lotsofyears;
set
optionm.vsurfd2010
optionm.vsurfd2011
optionm.vsurfd2012
optionm.vsurfd2013
;  *or however many you need, you could generate this list if it is long;
by secid;
run;

data mydata;
merge lotsofyears(in=a) idcodes(in=b);
by secid;
filenm=cats("c:\mydir\mydata_",ticker,".dat"); *or secid if that is better;
run;
proc sort data=mydata;
by ticker;
run;
data _null_;
set mydata;
file a filevar=filenm dlm='09'x lrecl=32767;
put (_all_)($); *or perhaps a more complex put statement - see what proc export generates;
run;

【讨论】:

感谢您详尽而完整的回答,您非常有帮助。代码的某些部分我不完全理解,你能帮我吗?即: 第 3 行: where lowcase(ticker) in (&tickers.);股票代码应该是股票代码列表,但我如何创建它?通过上面的答案中的proc sql?第12行:数据lotsofyears/view=lotsofyears;我见过这种用法,但我不明白。在这种情况下,斜线 (/) 是什么意思?另外,我将阅读数据合并,因为我还不明白。 啊,我把它的创建留了出来——那是我之前的回答,是的,我会把它重新添加进去。视图正在创建一个数据集视图——就像一个 sql 视图,它没有'实际上并不遍历数据,它只是存储您希望如何遍历数据,以供以后使用。这就是您创建它的方式 - data <name> / view <name>MERGE 基本上相当于 SAS 的连接。 感谢您的回答。我仍然没有得到一些东西,我无法让它工作。我会尽快发布我的问题。 你好@Joe。我一直在审查代码并逐步完全理解它。再次感谢你的帮助。我现在的问题是速度:在数据合并中,当访问 optionm.vsurfd2013 时,我们谈论的是一个包含 1.3 亿个观察值的文件(或更多,我不确定值,会回到这个)。合并效率高吗?只运行代码直到数据 mydata 部分,然后为 mydata 的前 20 个观察结果执行 proc 打印需要一段时间。鉴于WRDS提供的宏使用proc sql,这样会不会更高效? 另外,合并的时候是在lotsofdata和idcodes之间。但是 idcodes 包含不同的 secid。从我读到的关于合并的内容中,in=a 和 in=b 应该放在 a 和 b 的零和一中,这取决于在某个观察中是否找到了“匹配”。当运行代码的最后一部分时,file a filevar=filenm, 将把每个观察值都输出到 filenm 给定的文件中。考虑到记录的数量,这会有效吗?

以上是关于数据集 firstobs 中的错误的主要内容,如果未能解决你的问题,请参考以下文章

sas,combine,未知代码数据集观察

在SAS中keep语句放在data后和放在set后有啥区别?

如何解决 BigQuery 中的“在美国位置找不到数据集”错误?

当训练集包含监督分类中的一些错误数据时,我该怎么办?

如何处理已有标题的数据?

使用来自两个数据集的变量创建计算字段时 Tableau 中的错误