【问题标题】:SAS: Dynamically determine input fields from a datasetSAS:动态确定数据集中的输入字段
【发布时间】:2015-10-09 15:16:45
【问题描述】:

我正在尝试解析具有 300 多个字段的分隔数据集。而不是列出所有输入字段,如

    data test;
    infile "delimited_filename.txt"
            DSD delimiter="|" lrecl=32767 STOPOVER;

    input   field_A:$200.
            field_B :$200.
            field_C:$200.
            /*continues on */
    ;

我想我可以将所有字段名称转储到一个文件中,作为 sas 数据集读入,并填充输入字段 - 如果任何字段名称更改(添加/删除),这也可以让我动态控制数据集。有什么好的方法可以做到这一点?

非常感谢 - 我刚开始使用 sas,仍在努力解决它。

【问题讨论】:

  • 听起来你在正确的道路上。您是否尝试过 Proc Import 还是想要更多控制权?
  • 是的,我使用 proc import 来读取定义变量名称、长度、类型和标签的文件。从我广泛的谷歌来看,似乎最好的方法是编写一个宏——>读取头信息——>将数据文件输入语句输出到一个宏变量中——>在宏的末尾调用该宏变量.还没开始工作...
  • 您必须发布您拥有的文件的样本,但您在正确的轨道上。您还应该发布您尝试过但不起作用的代码。
  • 我想我想通了,把代码贴在下面。
  • 当将有关文件的元数据作为数据给出时,问题是如何编写 SAS 程序来读取文件?如果是这样,您应该提供您拥有的元数据的示例。要读取文件,您需要知道变量名称、顺序、类型(以及字符变量的最大长度)。您还需要了解需要将文本转换为存储值的任何字段(如 DATE 或 TIME 字段)的信息。您可能还需要提供格式和标签。

标签: sas sas-macro


【解决方案1】:

这对我有用 - 基本上使用宏语言“编写”数据开放代码并运行它。

注意:我的 indata_header_file 包含 5 列:Variable_Name、Variable_Length、Variable_Type、Variable_Label 和 Notes。

%macro ReadDsFromFile(filename_to_process, indata_header_file, out_dsname);

%local filename_to_process indata_header_file out_dsname;

/* This macro var contain code to read data file*/
%local read_code input_in_line; 
%put *** Processing file: &filename_to_process ...;

/* Read in the header file */
proc import OUT     = ds_header
        DATAFILE    = &indata_header_file.
        DBMS        = EXCEL REPLACE;        /* REPLACE flag */
        SHEET       = "Names";
        GETNAMES    = YES;
        MIXED       = NO;
        SCANTEXT    = YES; 
run;

%let id     = %sysfunc(open(ds_header));
%let NOBS   = %sysfunc(attrn(&id.,NOBS)); 
%syscall set(id); 

/* 
    Generates:
    data &out_dsname.;
    infile "&filename_to_process."
        DSD delimiter="|" lrecl=32767 STOPOVER FIRSTOBS=3;  
        input   
        '7C'x
*/

%let read_code = data &out_dsname. %str(;)
                        infile &filename_to_process.
                        DSD delimiter=%str("|") lrecl=32767 STOPOVER %str(;)
                        input ;

/*
    Generates:
    <field_name> : $<field_length>;
*/
%do i = 1 %to &NObs;
    %let rc             = %sysfunc(fetchobs(&id., &i));
    %let VAR_NAME       = %sysfunc(getvarc(&id., %sysfunc(varnum(&id., Variable_Name)) ));  
    %let VAR_LENGTH     = %sysfunc(getvarn(&id., %sysfunc(varnum(&id., Variable_Length)) ));    
    %let VAR_TYPE       = %sysfunc(getvarc(&id., %sysfunc(varnum(&id., Variable_Type)) ));  
    %let VAR_LABEL      = %sysfunc(getvarc(&id., %sysfunc(varnum(&id., Variable_Label)) ));
    %let VAR_NOTES      = %sysfunc(getvarc(&id., %sysfunc(varnum(&id., Notes)) ));      

    %if %upcase(%trim(&VAR_TYPE.)) eq CHAR %then 
        %let input_in_line = &VAR_NAME :$&VAR_LENGTH..;
    %else
        %let input_in_line = &VAR_NAME :&VAR_LENGTH.;

    /* append in_line statment to main macro var*/
    %let read_code = &read_code. &input_in_line. ;
%end; 

/* Close the fid */
%let rc = %sysfunc(close(&id));

%let read_code = &read_code. %str(;) run %str(;) ;

/* Run the generated code*/
&read_code.

%mend ReadDsFromFile;

【讨论】:

  • 使用%local 语句来本地化您的输入参数没有任何作用(它们会自动在本地范围内)。您可以删除该代码。这是证据:%macro blah; %let a = 2; %put blah &amp;=a; %mend; %macro test(a=1); *%local a; *COMMENT/UNCOMMENT THIS LINE TO TEST; %put test1 &amp;=a; %blah; %put test2 &amp;=a; %mend; %test;
【解决方案2】:

听起来您想根据元数据生成代码。数据步骤实际上比宏更容易编码和调试。 假设您有描述输入数据的元数据。例如,让我们使用有关 SASHELP.CARS 的元数据。我们可以从现有数据集上的现有 DICTIONARY.COLUMNS 元数据构建我们的元数据。让我们将 INFORMAT 设置为 FORMAT,因为该表没有分配 INFORMAT 值。

proc sql noprint ;
 create table varlist as
   select memname,varnum,name,type,length,format,format as informat,label
   from dictionary.columns
   where libname='SASHELP' and memname='CARS'
 ;
quit;

现在让我们制作一个包含数据的示例文本文件。

filename mydata temp;
data _null_;
  set sashelp.cars ;
  file mydata dsd ;
  put (_all_) (:);
run;

现在我们只需要使用元数据来编写一个可以读取该数据的程序。我们真正需要做的就是定义变量,然后添加一个简单的 INPUT firstvar -- lastvar 语句来读取数据。

filename code temp;
data _null_;
  set varlist end=eof ;
  by varnum ;
  file code ;
  if _n_=1 then do ;
    firstvar=name ; 
    retain firstvar ;
    put 'data ' memname ';'
      / '  infile mydata dsd truncover lrecl=1000000;'
    ;
  end;
  put '  attrib ' name 'length=' @;
  if type = 'char' then put '$'@ ;
  put length ;
  if informat ne ' ' then put @10 informat= ;
  if format ne ' ' then put @10 format= ;
  if label ne ' ' then put @10 label= :$quote. ;
  put '  ;' ;
  if eof then do ;
    put '  input ' firstvar '-- ' name ';' ;
    put 'run;' ;
  end;
run;

现在我们可以使用 %INCLUDE 运行生成的代码。

%include code / source2 ;

【讨论】:

    猜你喜欢
    • 2022-01-23
    • 1970-01-01
    • 2020-07-23
    • 1970-01-01
    • 2015-06-21
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多