【问题标题】:How to Loop Through Variable Formats and Rename In SAS如何在 SAS 中循环变量格式和重命名
【发布时间】:2020-02-21 13:29:53
【问题描述】:

我有一个数据集,其中每列代表从 2018 年 2 月到 2025 年 12 月的不同月份、年份组合。这些列存储为字符,但我想将它们转换为数字。目前,这些列被命名为“FEB_18”、“MAR_18”、“NOV_19”、“JUL_22”等。

我想创建一个循环,获取每个变量并将其转换为数字。最初,我使用以下代码,但这会为每次迭代创建一个新数据集。

 %let months = JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC;

 %MACRO DOIT(Peak=); 

    %do i= 1 %to %sysfunc(countw(&Name.));
    %let Name2 = %scan(&months., &i.);
    %do j = 18 %to 25; 

proc sql;
    create table ppl as 
        select
        input(Label, Best12.) - 21916 as Contract format MMDDYY10., /* Excel to SAS Dates*/
        input(&Name2._&j., Best12.) as _&Name2._&j.
    from Transposed_&Peak.;
    %end;
    %end;
quit;


%mend DOIT; 
%DOIT(Peak = On);

提前致谢!

【问题讨论】:

  • 这是 Excel 数据透视表的导入吗?将年/月作为元数据(即年/月是列名)可能会有问题。数据中还有哪些其他列?您将如何按年或按月处理数据?旋转的数据结构(这将是一种分类形式)会更有用(每个 id/年/月一行)吗?分类形式允许 SAS 语法,例如 where class by
  • 我正在从彭博社提取数据——金融期货数据。所以每一行已经是一个单独的日期。每列标识合同约定的日期。
  • 听起来您只是在问如何将您的%do 循环从SQL 语句周围移动到SQL 语句的中间?你试过移动它吗?你有什么问题?
  • 转置为长格式。根据需要重新编码日期,因为它们现在是单个变量,然后根据需要转回宽格式。没有宏,并且对于数据的更改(例如添加新列)是完全动态的。
  • 你的问题是如何生成一系列变量名?找出模式 MON_YY 中的哪些变量?还有什么?

标签: loops sas rename sas-macro


【解决方案1】:

CONTENTS 过程将使数据集的元数据(列名、类型、列号等)可用作数据。根据这些数据,您可以构建执行转换所需的语句

例子:

X_feb_20 = input(feb_20, ?? best12.);  * parse value in character variable into a numeric variable;
drop feb_20;  * drop character variable from output data set;
rename x_feb_20 = feb_20;  * change the name of the numeric variable back to the orginal;

因此,需要对数据集中名称代表<mon>_<yy> 的所有字符列执行该模式。测试

input('01'||transtrn(name,'_','20'),anydtdte.) is not null 

将识别此类列名。

这是一个执行杂务的示例宏:

/* 
 * Fake some data to play with 
 */

%macro month_columns(from_month=, to_month=);

  %local index mon yy frstdate lastdate;

  %let frstdate = %sysevalf("01&from_month"D);
  %let lastdate = %sysevalf("01&to_month"D);

  %do date = %sysevalf("01&from_month"D) %to %sysevalf("01&to_month"D);
    %let date = %sysfunc(INTNX(MONTH,&date,0,E));

    %sysfunc(putn(&date,MONNAME3))_%sysfunc(putn(&date,YEAR2.))
  %end;

%mend;

data have;
  call streaminit(123);
  do stockid = 1 to 10;
    array futures $12 %month_columns(from_month=FEB2020, to_month=DEC2025);
    do over futures;
      futures = put(rand('uniform',50) + stockid * sin(_i_/40), 12.5);
    end;
    output;
  end;
run;

/* 
 * Chore macro
 */

%macro asnum_mon_yy_columns(data=, out=);

  %local index;

  proc contents noprint data=&data out=have_columns(keep=varnum name type);
  run;

  * SQLOBS will be number of rows (and thus names) that meet the date-like criteria ;

  proc sql noprint;
    select name into :name1-
    from have_columns
    where input('01'||transtrn(name,'_','20'),anydtdte.) is not null 
      and type = 2
    order by varnum
    ;
  quit;

  data &out;
    set &data;

    %do index = 1 %to &sqlobs;
      X_&&name&index = input(&&name&index,??best12.);
    %end;

    %if &sqlobs %then %do;
      drop   %do index = 1 %to &sqlobs;
                &&name&index
             %end;
      ;
      rename %do index = 1 %to &sqlobs;
                X_&&name&index = &&name&index
             %end;
      ;
    %end;
  run;

%mend;

/*
 * Invoke chore
 */

options mprint;

%asnum_mon_yy_columns(data=have, out=want)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    • 2014-06-17
    • 1970-01-01
    • 1970-01-01
    • 2018-05-11
    相关资源
    最近更新 更多