保留并保持变量宏

时间:2019-08-07 21:09:21

标签: sas

我有一个大型数据集,其中包含许多变量(列)。变量名称包括

  • JUNE19_53410_Actual,
  • JUNE19_53410_Actual_Per_Unit,
  • JUNE19_53410_Budget,
  • JUNE19_53410_Budget_Per_Unit,
  • JUNE19_53410_Variance

依此类推...随着月份和帐户的更改,有数百种。

我想编写一个MACRO,其中新数据集中包含的唯一变量1)的顺序为Acutal,然后按Budget,然后按月交替,例如, 表格如下:

 JUNE19_53410_Actual  JUNE19_53410_Budget   AUG19_53410_Actual AUG19_53410_Budget 
  $12,000                $34,000            $23,000            $14,000
  $13,000                $64,000            $83,000            $11,000

我尝试了以下代码,但将其放入数据步骤后却出现错误

 %MACRO Keeping;
 retain
 &x._Actual  &x._Budget;
 keep 
 &x._Actual  &x._Budget;
 %MEND Keeping;

 data test;
 set June_2019;
 %Keeping;
 run; 

3 个答案:

答案 0 :(得分:2)

为什么要使用宏?

您使用宏“函数”的方式几乎不会减少代码,也很难阅读。 使用宏变量更容易。

我会做什么

/* List the variables you want */
%let myVars =
        JUNE19_53410_Actual JUNE19_53410_Budget
        AUG19_53410_Actual AUG19_53410_Budget
        ...
        DEC19_53410_Actual DEC19_53410_Budget
        ;
/* Define what dataset you create */
data want;
    /* I specify the order of the variables with a length statement */ 
    length &myVars 8;
    /* Read in your data */
    set have;
    /* keep only what you need */
    keep &myVars;
run;

您应该使用retainlength还是format

SAS按照您提到变量的顺序将变量放入数据集中。 set语句“提及”输入数据集中的所有变量,您无法再更改其顺序。因此,您应该在set语句之前提及变量。您有很多选择。

假设您希望ab成为数据集中的第一个变量,那么您有不同的选择

length a b 8;

这将ab定义为数字,每个以8字节存储(数字的最大和默认长度,以sas为单位)。您的输入数据的变量大小可能较小。然后,此length语句的副作用是输出数据集将更大。没什么大不了的。 您可以对length first_name last_name $32;中的字符变量执行相同的操作,但这会带来更大的风险:如果这些变量在输入数据集上较长,则可能会截断它们。

'保留a b;'

这避免了上述副作用,因此SAS建议使用。但是,我避免这样做,因为它改变了SAS处理这些变量值的方式。见下文。

format a b 12.4;

此选项应在12个位置打印,其中4个为小数。它隐式地将它们定义为数字,因为这是数字格式,并且长度默认为8个字节。

其他选项

您还可以在此处使用labelattribute语句。

retain的作用

通过默认设置,SAS将每个观察值(即行)的所有变量都设置为丢失。 Retain语句用于防止某些变量出现这种情况,例如

Data running_total;
    set transactions; /* a dataset with amount */
    retain total 0;   /* initialize as 0 for the first observation */
    total = total + amount;
run;

retain total 0;retain total; if _N_ = 1 then total = 0;的简写

在您的代码中,“保留”对变量的值没有影响,因为您要做的第一件事就是用set语句中的输入覆盖它们。

但是,如果在set语句之前添加分配,则保留确实会影响这些变量的值。因此,我避免使用它,而对数字变量使用length语句。

答案 1 :(得分:1)

严格来说,除非使用任何查看器查看数据集,否则数据集中列的顺序没有意义。像PRINT这样的PROC可以让您指定顺序。

尽管如此,如果您确实想保留默认顺序,则可以在宏变量中包含所有前缀的情况下执行以下操作:

%let months = %str(JUNE19_53410 AUG19_1234);

%macro genlist;

    %let ii = 1;
    %do %while (%scan(&months, &ii, %str( )) ~= %str());
      %let col = %scan(&months, &ii, %str( ));

      &col._actual &col._budget

      %let ii = %eval(&ii + 1);
    %end;

%mend;

data want;
  retain 
    %genlist;
  ;
  set have;
  keep
    %genlist;
  ;

run;

这将按以下顺序保留以下字段:

JUNE19_53410_actual
JUNE19_53410_budget
AUG19_1234_actual
AUG19_1234_budget

如果列数太大而无法手动填充,则可能需要另一个代码来生成months宏变量。在这种情况下,您可能会超过65536的限制,并且可能不得不求助于PROC EXECUTE等其他技术。

答案 2 :(得分:1)

将它们全部堆叠到一个数据集中,并添加一个指标变量。

    SET语句上的
  • INDSNAME存储输入数据集名称,它是 写入INPUT_FILE变量。
  • SCAN()解析不同组件的名称
  • INPUT(,monyy5。)尝试将月份转换为SAS日期,以便正确排序。这个 可能不起作用,因为您通常使用标准的JUNE2019 vs JUN2019。所以 您可以保留其特征并以其他方式进行转换。

    data want;
        length source input_file $50.;
        set <list of data sets> indsname = source;
    
        input_file = source;
        month = input(scan(input_file, 2, '._'), monyy5.);
        format month monyy5.;
        code = scan(input_file, 3, '._');
        budget_actual = scan(input_file, -1, '_'); * you can recode to what you need but seems like last bit will be enough; 
    
    run;
    

现在,您只有一个数据集,可以轻松过滤,排序,查询或将所有数据用于按需报告。不再需要清洗或重组数据或简单排序的循环。