楼主: crackman
15194 47

跟crackman读SAS程序(15)--如何将宏变量按照字母顺序排列 [推广有奖]

楼主
crackman 发表于 2010-8-24 10:33:59

跟crackman读SAS程序(14)---学会利用ROUND函数

DATA _null_;
cost = 4.99;
units = 3;
ucost = Round(cost/units,.01);
PUT cost units ucost ;
  RUN;


DATA _null_;
x = 234.2357222;
x2 = Round(x, .25); * the nearest quarter;
x3 = Round(x, .05); * the nearest nickel;
x4 = Round(x, 5);   * the nearest 5 dollars;
Put x x2 x3 x4;
  RUN;


DATA _null_;
dt = dhms('12mar2003'D,14,23,10); * create a datetime - 2:23pm;
dt2 = Round(dt,hms(0,15,00)); * round it to nearest 15 minutes;
dt3 = Round(dt,hms(0,7,30)); * round it to nearest 7 1/2 minutes;
dt4 = Round(dt,hms(0,0,15)); * to the nearest 15 seconds;
Put (dt dt2 dt3 dt4) (DATETIME. ' ');
  RUN;


DATA _null_;
dt = '12mar2003:14:23:10'DT; * create a datetime - 2:23pm;
dt2 = Round(dt,'0:15:00'T); * round it to nearest 15 minutes;
dt3 = Round(dt,'0:7:30'T); * round it to nearest 7 1/2 minutes;
dt4 = Round(dt,'0:00:15'T); * to the nearest 15 seconds;
Put (dt dt2 dt3 dt4) (DATETIME. ' ');
RUN;

我们经常用ROUND函数,主要是指定的小位数。
第一个DATA _NULL_,结果为
4.99 3 1.66
第二个DATA _NULL_,结果为
234.2357222 234.25 234.25 235
其实这个时候是把0.25 0.05 5作为小位数修正一个间隔距离了,例如对于0.25来说,234.2357222 应该是和234.00 234.25 234.50 看看234.2357222在这三个数比较靠近谁,就输出。同样对于0.05来说,234.2357222应该和234.05 234.10 234.15 234.20 234.25 234.30这样间隔0.05的数字进行比较,最后就是234.25了。其他一样
这个程序实际对应为货币计算的,下面的为对应时间的计算,不过注意表达 一个HMS函数,一个用的是T格式。




已有 4 人评分论坛币 学术水平 热心指数 信用等级 收起 理由
hopewell + 1 + 1 + 1 精彩帖子
醉_清风 + 1 + 1 + 1 又学习了 期待更多技巧性的 或者是宏方面的 支持
soporaeternus + 1 + 1 使用的技巧,热心的楼主......
peijiamei + 100 + 4 + 4 对论坛有贡献

总评分: 论坛币 + 100  学术水平 + 7  热心指数 + 7  信用等级 + 2   查看全部评分

已卖:401份资源

院士

83%

还不是VIP/贵宾

-

威望
6
论坛币
91928 个
通用积分
23.5045
学术水平
424 点
热心指数
505 点
信用等级
256 点
经验
112978 点
帖子
2940
精华
0
在线时间
2532 小时
注册时间
2007-4-26
最后登录
2025-6-25

初级热心勋章 中级热心勋章 初级学术勋章 初级信用勋章

沙发
crackman 发表于 2010-8-24 10:48:21 |AI写论文
%let x=100;
%let a=200;
%macro putsorted(class);                                                                                                               
                                                            
                                                        
   %let cls = %upcase(&class);                                                                                                         
   proc sql;                                                                                                                           
      create view new as select * from sashelp.vmacro                                                                                   
   %if "&cls" eq "_AUTOMATIC_" %THEN                                                                                                   
      where scope='AUTOMATIC';                                                                                                         
   %else %if "&cls" eq "_GLOBAL_" %then                                                                                                
      where scope='GLOBAL';                                                                                                            
   %else %if "&cls" eq "_LOCAL_" %then                                                                                                  
      where scope^='AUTOMATIC' and scope^='GLOBAL' and scope^='PUTSORTED';                                                              
   %else %if "&cls" eq "_USER_" %then                                                                                                   
      where scope^='AUTOMATIC' and scope^='PUTSORTED';                                                                                 
   %else %if "&cls" eq "_ALL_" %then                                                                                                   
      where scope^='PUTSORTED';                                                                                                         
   %else %do;                                                                                                                           
      %put Unrecognized CLASS of macro variables: &cls;                                                                                 
      %return;                                                                                                                          
   %end;                                                                                                                                
      order by name;                                                                                                                    
   quit;                                                                                                                                
   data _null_;                                                                                                                        
      set new;                                                                                                                          
      put scope +1 name +1 value;                                                                                                      
   run;                                                                                                                                 
%mend;                                                                                                                                 
                                                                                                                                       
%putsorted(_global_)
其实这个里面值得学习的一点就是在宏里面用SQL根据IF  THEN ELSE判断不同的筛选条件来获得不同作用范围的宏变量按照字母顺序输出
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:crackman Ackman sas程序 CRACK Man 程序 SAS crackman
已有 4 人评分学术水平 热心指数 信用等级 收起 理由
kaeod + 1 + 1 + 1 精彩帖子
bullstag + 1 精彩帖子
醉_清风 + 1 + 1 + 1 期待更多作品
soporaeternus + 1 + 1 不错,继续支持!!

总评分: 学术水平 + 4  热心指数 + 3  信用等级 + 2   查看全部评分

藤椅
crackman 发表于 2010-8-24 13:32:25

跟crackman读SAS程序(16)---更新有主数据集中的观测数据

/* Example 1: Only first matching observation updated */
/*            due to duplicates in master             */
proc printto;
run;
options;
data Dairy(index=(Item));
  input Item $ Inventory Price ;
datalines;
Milk 15 1.99
Milk 3 1.99
Soymilk 8 1.79
Eggs 24 1.29
Cheese 14 2.19
;
data Dairy_current_price;
  input Item $ price_increase;
datalines;
Milk .05
Butter .10
;
data Dairy;
  set Dairy_current_price;
  modify Dairy key=Item;
  select (_iorc_);
    when (%sysrc(_sok)) do;
      /* calculate new price for match, and replace observation */
      Price=Price + Price_increase;
      replace;
    end;
    when (%sysrc(_dsenom)) do;
      /* When item is not in master, reset _ERROR_ flag */
      /* and output note to log.                        */
      _ERROR_=0;
      put "Item not in stock --- " Item;
    end;
    otherwise do;      /* Unplanned condition, stop the data step */
      put 'Unexpected ERROR: _iorc_= ' _iorc_;
      stop;
    end;
  end;
run;
proc print data=dairy;
run;
/* Example 2: Forcing updates to occur on all duplicates in master */

/* Use DO loop to apply single transaction to multiple consecutive */
/* duplicates in master data set.                                  */

data Dairy(index=(Item));
  input Item $ Inventory Price ;
datalines;
Milk 15 1.99
Milk 3 1.99
Soymilk 8 1.79
Eggs 24 1.29
Cheese 14 2.19
;

data Dairy_current_price;
  input Item $ price_increase;
datalines;
Milk .05
Butter .10
;


data Dairy;
  set Dairy_current_price;
  master_count = 0;
  do until (_IORC_=%SYSRC(_DSENOM));
  modify Dairy key=Item;
   select (_iorc_);
    when (%sysrc(_sok)) do;
      Price=Price + Price_increase;
      master_count + 1;
      replace;
    end;
    when (%sysrc(_dsenom)) do;
      _ERROR_=0;
      if master_count = 0 then put "Item not in stock --- " Item;
    end;
    otherwise do;
      put 'Unexpected ERROR: _iorc_= ' _iorc_;
      stop;
    end;
   end;
  end;
run;

proc print data=dairy;
run;

对于这段程序,更多的是翻译工作,值得学习几点
1.更新原程序中的数据,用了MODIFY
2.使用INDEX来数据集的索引,使得主数据集(被更新的数据集)按照ITEM为主要关键变量存储
3.这里使用了SELECT WHEN 来选择性的执行不同的程序语句,这里选择的变量是宏变量_iorc_,这个宏变量的结果由两个,是根据%sysrc(_sok)和%sysrc(_dsenom)两个的返回结果来判断,我用%put 来读这两返回的结果,一个是0,一个是1230015,不知道1230015是怎么计算出来的?也就是等于_iorc等于0时,就是寻找到了按照ITEM这个关键变量匹配的主数据集中的观测,而_dsenom则是没有寻找,这里注意SELECT WHEN使用方法,以及STOP的使用,以及在代码编写规范里面强调的PUT输出错误信息这个特点。但是结果出来之后,发现同样是MIKE,却只修改了第一个MIKE,看看第二个程序,使用循环语句 DO UNTIL。

data Dairy(index=(Item));
  input Item $ Inventory Price ;
datalines;
Milk 15 1.99
Milk 3 1.99
Soymilk 8 1.79
Eggs 24 1.29
Cheese 14 2.19
;

data Dairy_current_price;
  input Item $ price_increase;
datalines;
Milk .05
Butter .10
;


data Dairy;
  set Dairy_current_price;
  master_count = 0;
  do until (_IORC_=%SYSRC(_DSENOM));

  modify Dairy key=Item;
   select (_iorc_);
    when (%sysrc(_sok)) do;
      Price=Price + Price_increase;
      master_count + 1;
      replace;
    end;
    when (%sysrc(_dsenom)) do;
      _ERROR_=0;
      if master_count = 0 then put "Item not in stock --- " Item;
    end;
    otherwise do;
      put 'Unexpected ERROR: _iorc_= ' _iorc_;
      stop;
    end;
   end;
  end;
run;

proc print data=dairy;
run;

在这里面,用了一个指示变量,用来表示有没有寻找到可以修改的观测。
这段程序值得学习,特别是在DATA步跟新数据的时候。
已有 2 人评分学术水平 热心指数 收起 理由
soporaeternus + 1 + 1 支持支持!!
peijiamei + 4 + 3 对论坛有贡献

总评分: 学术水平 + 5  热心指数 + 4   查看全部评分

板凳
reolin 发表于 2010-8-24 13:41:25
汗,我什么时候能达到斑竹的境界

报纸
crackman 发表于 2010-8-24 13:46:34

跟crackman读SAS程序(17)----POINT在SET中的使用

data one;
  input var1 $ var2;
datalines;
A 10
B 22
C 5
D 41
E 33
;
run;
data two;
/*添加END这个参数为了检验是否到了最后的一个观测对象*/
  set one end=finished;
/*如果没有到最后一个观测,执行DO循环里面的语句*/
  if not finished then do;
/*定义和计算读入的观测的PT值,根据自动变量_N_来计算*/
  pt = _N_ + 1;
/*重复SET,并且修改变量VAR2的名字,确定读入数据时执行的顺序步骤,按照PT的值的从小到大的顺序来读入相应的观测数据*/
  set one (keep= var2 rename= (var2 = next_var2)) point=pt;
/*将当前数据集中的VAR2减去读入进行中的NEXT_VAR2*/
  diff = var2 - next_var2;
  end;
  else next_var2 = .;
run;
proc print; run;
已有 1 人评分学术水平 热心指数 收起 理由
pobel + 1 + 1 精彩帖子

总评分: 学术水平 + 1  热心指数 + 1   查看全部评分

地板
jinkesale 发表于 2010-8-24 13:50:04
收藏了,谢谢分享

7
crackman 发表于 2010-8-24 15:07:36

跟crackman读SAS程序(18)-如何查看SAS附带的输出结果样式

%let path=c:\temp;  
%macro showstyle(style);
ods html path="&path"(url=none) file="&style..html"
    contents=temp(notop nobot) frame="frame.html" style=&style;
ods proclabel "Style name";
proc print data=sashelp.class contents="Styles.&style";
run;
ods html close;
%mend;
ods path work.templat(update) sashelp.tmplmst(read);
filename temp "&path\contents.html" mod;
ods html path="&path"(url=none) contents=temp(nobot);
ods html exclude stats;
ods output stats=styles(where=(type ne "Dir"));
proc template;
   list styles;
run;
proc sort data=styles;
   by path;
run;
data one;
   set styles;
   by path;
   if first.path then
      call execute('%showstyle('||path||')');
run;
data _null_;
   file temp;
   put "</body>";
   put "</html>";
run;
ods path reset;

这里有几个地方值得学习
1.PROC TEMPLATE列出了所有SAS附带的输出结果展示的样式
2.用CALL EXECUTE调用宏程序。
3.宏程序里面的主要的是ODS参数的设置,以及最后对ODS PATH RESET。
已有 1 人评分学术水平 热心指数 收起 理由
soporaeternus + 1 + 1 支持!支持!支持!

总评分: 学术水平 + 1  热心指数 + 1   查看全部评分

8
crackman 发表于 2010-8-24 15:30:53

跟crackman读SAS程序(19)---根据BY分组创建不同的数据集

/*用宏程序按照数据集中的BY分组变量来创建不同的数据集*/
data test;
  input color $ num;
datalines;
blue 1
blue 2
blue 3
green 4
green 5
red 6
red 7
red 8
;
/* 创建一个新的宏变量VARn*/
/* 创建一个新变量flag,这个用来记录每一组,按照BY分了三组,每一组里面的FLAG是一样的,但是不同的COLOR组是不一样,递增的关系
例如1,2,3然后根据FLAG创建宏变量
VAR1 VAR2 VAR3.....*/
data we;
  set test end=eof;
  by color;
  if first.color then do;
   flag+1;
   call symput('var'||put(flag,8. -L),color);
  end;
  /* 最后一个观测时,将此时的FLAG创建并赋值给宏变量TOT,也就是TOT这个宏变量记录了分组数 */                              
  if eof then call symput('tot',put(flag,8. -L));
run;
/* 动态创建数据集,根据宏变量根据IF THEN语句判断输出到不同的数据集中*/
                                       
%macro groups(dsn,byvar);
  data %do i=1 %to &tot; /*如果TOT=3的话,那么就是等价于&var1,&var2,&var3*/
         &&var&i
       %end;;
    set &dsn;
      %do i=1 %to &tot;
        if &byvar="&&var&i" then output &&var&i;
      %end;
  run;
%mend groups;
%groups(test,color)
proc print data=blue;
  title 'Blue';
run;
proc print data=green;
  title 'Green';
run;
proc print data=red;
  title 'Red';
run;




这里有一个技巧就是
call symput('var'||put(flag,8. -L),color);
这句是创建的一个系列的宏变量,而不是一个宏变量
可以对照symget来看看
已有 3 人评分学术水平 热心指数 信用等级 收起 理由
soporaeternus + 1 + 1 支持支持
redaring + 1 + 1 + 1 很实用的程序
pobel + 1 + 1 + 1 精彩帖子

总评分: 学术水平 + 3  热心指数 + 3  信用等级 + 2   查看全部评分

9
pobel 在职认证  发表于 2010-8-24 16:12:42
也可以用call execute();

data test;
  input color $ num;
datalines;
blue 1
blue 2
blue 3
green 4
green 5
red 6
red 7
red 8
;

proc sql;
    select distinct color into : dslist separated by " "
          from test;
run;

data _null_;
     if _n_=1 then call execute("data &dslist;  set test;");
         set test end=last;
         by color;
         if first.color then  call execute("if color="||quote(strip(color))||" then output "||color||";");
         if last then call execute("run;");
run;
已有 1 人评分学术水平 热心指数 收起 理由
crackman + 1 + 1 精彩帖子

总评分: 学术水平 + 1  热心指数 + 1   查看全部评分

和谐拯救危机

10
823954913 发表于 2010-8-24 16:26:38
data test;
  input color $ num;
datalines;
blue 1
blue 2
blue 3
green 4
green 5
red 6
red 7
red 8
;
data blue green red;
set test;
if color='blue' then output blue;
if color='green' then  output green;
if color='red' then output red;
run;

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2025-12-25 03:29