如何在SAS中检测数据集中有多少个观测值(如果是空的话)?

如何在SAS中检测数据集中有多少个观测值(如果是空的话)?,sas,Sas,我想知道是否有一种方法可以检测数据集是否为空,即它没有观测值。 或者换句话说,如何获得特定数据集中的观测数量 这样我就可以写一个If语句来设置一些条件 谢谢。使用PROC-SQL很容易。进行计数并将结果放入宏变量中 proc sql noprint; select count(*) into :observations from library.dataset; quit; 有很多不同的方法,我倾向于使用带有open()和attrn()的宏函数。下面是一个简单的例子,在大多数情况下效果都很好

我想知道是否有一种方法可以检测数据集是否为空,即它没有观测值。 或者换句话说,如何获得特定数据集中的观测数量

这样我就可以写一个If语句来设置一些条件


谢谢。

使用PROC-SQL很容易。进行计数并将结果放入宏变量中

proc sql noprint;
 select count(*) into :observations from library.dataset;
quit;

有很多不同的方法,我倾向于使用带有
open()
attrn()
的宏函数。下面是一个简单的例子,在大多数情况下效果都很好。如果您要处理数据视图或更复杂的情况,如数据集上有标记为删除的记录或活动where子句,那么您可能需要更健壮的逻辑

%macro nobs(ds);
    %let DSID=%sysfunc(OPEN(&ds.,IN));
    %let NOBS=%sysfunc(ATTRN(&DSID,NOBS));
    %let RC=%sysfunc(CLOSE(&DSID));
    &NOBS
%mend;

/* Here is an example */
%put %nobs(sashelp.class);

下面是@cmjohns谈论的更完整的示例。如果为空,则返回0;如果缺少,则返回1;并且可以选择处理已删除的观察结果和where子句(请注意,在非常大的数据集上使用where子句可能会使宏花费很长时间)

用法说明:

%macro nobs(iDs=, iWhereClause=1, iNobsType=nlobsf, iVerbose=1);
  %local dsid nObs rc;

  %if "&iWhereClause" eq "1" %then %do;
    %let dsID = %sysfunc(open(&iDs));
  %end;
  %else %do;
    %let dsID = %sysfunc(open(&iDs(where=(&iWhereClause))));
  %end;

  %if &dsID %then %do;
    %let nObs = %sysfunc(attrn(&dsID,nlobsf));
    %let rc   = %sysfunc(close(&dsID));
  %end;
  %else %do;
    %if &iVerbose %then %do;
      %put WARNING: MACRO.NOBS.SAS: %sysfunc(sysmsg());      
    %end;
    %let nObs  = -1;
  %end;
  &nObs
%mend;
%put %nobs(iDs=sashelp.class);
%put %nobs(iDs=sashelp.class, iWhereClause=height gt 60);
%put %nobs(iDs=this_dataset_doesnt_exist);
此宏将返回数据集中的观察数。如果数据集不存在,则返回-1。我不建议将其用于ODBC libnames,只对SAS表使用

参数:

  • iDs—要检查的
    libname.dataset
  • Iwhere子句(可选)-适用的where子句
  • iNobsType(可选)NOBS或
    NLOBSF
    。有关说明,请参阅
宏定义:

%macro nobs(iDs=, iWhereClause=1, iNobsType=nlobsf, iVerbose=1);
  %local dsid nObs rc;

  %if "&iWhereClause" eq "1" %then %do;
    %let dsID = %sysfunc(open(&iDs));
  %end;
  %else %do;
    %let dsID = %sysfunc(open(&iDs(where=(&iWhereClause))));
  %end;

  %if &dsID %then %do;
    %let nObs = %sysfunc(attrn(&dsID,nlobsf));
    %let rc   = %sysfunc(close(&dsID));
  %end;
  %else %do;
    %if &iVerbose %then %do;
      %put WARNING: MACRO.NOBS.SAS: %sysfunc(sysmsg());      
    %end;
    %let nObs  = -1;
  %end;
  &nObs
%mend;
%put %nobs(iDs=sashelp.class);
%put %nobs(iDs=sashelp.class, iWhereClause=height gt 60);
%put %nobs(iDs=this_dataset_doesnt_exist);
用法示例:

%macro nobs(iDs=, iWhereClause=1, iNobsType=nlobsf, iVerbose=1);
  %local dsid nObs rc;

  %if "&iWhereClause" eq "1" %then %do;
    %let dsID = %sysfunc(open(&iDs));
  %end;
  %else %do;
    %let dsID = %sysfunc(open(&iDs(where=(&iWhereClause))));
  %end;

  %if &dsID %then %do;
    %let nObs = %sysfunc(attrn(&dsID,nlobsf));
    %let rc   = %sysfunc(close(&dsID));
  %end;
  %else %do;
    %if &iVerbose %then %do;
      %put WARNING: MACRO.NOBS.SAS: %sysfunc(sysmsg());      
    %end;
    %let nObs  = -1;
  %end;
  &nObs
%mend;
%put %nobs(iDs=sashelp.class);
%put %nobs(iDs=sashelp.class, iWhereClause=height gt 60);
%put %nobs(iDs=this_dataset_doesnt_exist);
结果

19
12
-1
安装


我建议设置一个宏并将其放置在自动调用位置

当我们有大数据集时,Proc-sql效率不高。虽然使用ATTR是一种很好的方法,但这可以在基本sas中实现,但下面是一个高效的解决方案,它可以通过读取一行来提供数十亿行的OB数:

data DS1;
set DS nobs=i;
if _N_ =2 then stop;
No_of_obs=i;
run;

诀窍是即使数据集为空也要生成输出

data CountObs;

    i=1;
    set Dataset_to_Evaluate point=i nobs=j; * 'point' avoids review of full dataset*;
    No_of_obs=j;
    output;  * Produces a value before "stop" interrupts processing *;
    stop;   * Needed whenever 'point' is used *;
    keep No_of_obs;
run;

proc print data=CountObs;
run;

上面的代码是我发现的最简单的方法,即使在数据集为空的情况下也可以生成观察数。我听说NOB可能很棘手,但上述方法适用于简单的应用程序。

稍有不同的方法:

proc contents data=library.dataset out=nobs;
run;

proc summary data=nobs nway;
class nobs;
var delobs;
output out=nobs_summ sum=;
run;

这将为您提供一个具有一个观测值的数据集;变量nobs的值等于数据集中的观测数,即使它是0。

我想我已经在尝试用这么多的答案重新发明轮子了。但我确实看到一些其他方法试图从实际数据集计数——对于大型数据集,这可能需要很长时间。以下是一种更有效的方法:

proc sql;
select nlobs from sashelp.vtable where libname = "library" and memname="dataset";
quit;

谢谢Laurent的快速回答。它似乎非常有用。Hi Laurent-这对于小数据集是可以的,但是对于大数据集,它可能需要相当长的时间来执行,因为它必须读取每个观察值,而不仅仅是查看表的元数据。请参阅下面的一些其他答案,以获得更有效的方法。
count(var_name)
读取每个观察值,但
count(*)
不读取。@Ryan如果这样做会很好,但不幸这是错误的。尽管如此,谢谢你,John。我稍后会尝试。不严格相关。但我有时觉得这太复杂了。在R中,相关的命令是nrow(data.frame1)@xiaodai,这就是为什么您应该使用宏自动调用库或
proc fcmp
,或两者兼用的原因。然后将代码简化为最后一部分:
%nobs(sashelp.class)
Hi Rob,我想您也是SAS的高级用户。当我理解代码时,我会尝试一下。无论如何,还是谢谢你。罗伯特,你知道如何修改以确定是否既没有obs也没有VAR吗?在这种情况下返回1。我尝试过使用各种attrn选项,但找不到方法。@米尔卡,当然,测试变量数量所需的代码是
%let nVars=%sysfunc(attrn(&dsID,nVars))。这行代码需要在运行
%let nobs
语句的地方执行。我将把其余的逻辑留给您,让您尽可能地了解您希望返回的值。+1对于不使用那些可怕的
%
符号的解决方案,请注意,在某些情况下,
nobs
不起作用。您需要将output语句移到set语句之前,以允许它处理零观测值的输入数据集。实际上,您需要使用NLOB而不是NOBS。这个变量考虑了删除的观测值(DELOB)的数量。很好的添加。如果您不想使用
sashelp.vtable,还可以使用
dictionary.tables
。我记不起确切的情况,但有一次我遇到一个情况,其中一个用了将近30秒的时间跑,而另一个则是瞬间。例如,
procsqlnoprint;从dictionary.tables中选择nlobs,其中libname='SASHELP'和memname='CLASS';退出