我对SAS很陌生,我很难理解如何用SAS宏语言编写数据驱动的程序。但是, proc lua 对我有意义。尽管如此,我想知道两者。
下面的代码 - 可能是愚蠢的 - 说明了我正在努力的概念。它随机列出了猫的名字,然后找出哪些猫是顽皮的,哪些是好的。然后它打印出一个圣诞节清单,让我知道哪些猫应该买礼物以及我可以花多少钱。
我在翻译/实现SAS宏语言时遇到困难的部分代码是:
1)确定第j个cat后缀的部分,然后将其打印到日志中。如何动态更改宏变量的值,然后在宏循环中使用它们来写入日志?有没有办法在宏中使用'call symput'或'symget'?
2)如何在宏循环中写入多个数据集,类似于我在下面所做的。
3)如何在sas宏中调用用 proc fcmp 编译的自定义函数来控制宏的流程。
* This macro create a list of cat names;
%macro getsomecats(num);
%local mycat;
%let mycat = cat1;
%do j = 2 %to #
%let mycat = &mycat.%str( cat)&j.;
%end;
&mycat
%mend;
* SAS macro that duplicates the Excel RANDBETWEEN function. Taken from
http://blogs.sas.com/content/iml/2015/10/05/random-integers-sas.html;
%macro RandBetween(min, max);
(&min + floor((1+&max-&min)*rand("uniform")))
%mend;
* Get the number of cats that will be in our list;
data _null_;
seed = %randbetween(1,50);
call symputx('myseed',seed);
run;
* Make a random list of cat names;
%let morecats = %getsomecats(&myseed.);
* Reference some custom functions compiled with proc fcmp;
options cmplib=(MY_FUNCS.PURE_MATH);
libname NUMBERS '/folders/myfolders';
* Make two data sets: one for all of my cats, and another for
the cats that I should by Christmas presents;
proc lua;
submit;
-- Import Lua libraries
require 'string'
require 'math'
-- If the tables I want to create exist, then delete them.
if sas.exists('my_cats') then
sas.submit([[
proc delete data=my_cats;
]])
print('my_cats deleted')
end
if sas.exists('xmas_list') then
sas.submit([[
proc delete data=xmas_list;
]])
print('xmas_list deleted')
end
-- Set up some data sets
sas.new_table('my_cats', {
{name='Name', type='C', length=8},
{name='Status', type='C', length=8},
{name='Gender', type='C', length=6}
})
sas.new_table('xmas_list', {
{name='Name', type='C', length=8},
{name='Status', type='C', length=8},
{name='Gender', type='C', length=6},
{name='Budget', type='N', length=8}
})
-- Create data set handels for our new data set
local dsh1 = sas.open('my_cats', 'u')
local dsh2 = sas.open('xmas_list', 'u')
-- Declare some useful variables
local suffix, status, gender, name
local ub = 1 -- upper bound for 'for' loop
local mystr = sas.symget("morecats")
-- Find out upper bound on number of cats
for j = 1, string.len(mystr) do
if mystr:sub(j,j) == ' ' then ub = ub + 1 end
end
mystr = nil -- we do not need mystr anymore
print('Making my christmas list:') -- Write header in log
for j = 1, ub do
-- Create a suffix for jth cat; I am very confused about
-- how to do this in the SAS macro language.
if j % 10 == 1 and j % 100 ~= 11 then suffix = 'st'
elseif j % 10 == 2 and j % 100 ~= 12 then suffix = 'nd'
elseif j % 10 == 3 and j % 100 ~= 13 then suffix = 'rd'
else suffix = 'th' end
-- Find out if the jth cat has been naughty or nice.
-- 'isprime' is a custom function compiled with proc fcmp,
-- it returns 1 if a number is prime and 0 if it is composite.
if sas.isprime(j) == 1 then
status = 'naughty'
else
status = 'nice'
end
-- Assign the cat a gender randomly. I would like to
-- know how to this in the SAS macro language, including
-- how to use a list so that I can reference the two different
-- charchteristics of gender.
if sas.ranuni(0) < .5 then
gender = {'male', 'he'}
else
gender = {'female', 'she'}
end
-- Get the cats name; scan the macro variable
-- 'morecats' for the jth entry.
name =sas.scan(sas.symget("morecats"),j)
-- Write information in our log about this cat,
-- again, I cannot figure out how to deal with the
-- suffix part here.
print('My '..j..suffix.." cat's name is "..name..
', and '..gender[2]..' is usually '..status)
-- Add the jth cat to my data set of cats
sas.append(dsh1)
sas.put_value(dsh1,"Name", name)
sas.put_value(dsh1,"Status", status)
sas.put_value(dsh1,"Gender", gender[1])
sas.update(dsh1)
-- If the jth cat is usually nice then, add him or her
-- to the data set of cats that need to by Christmas
-- presents for.
if status == 'nice' then
local budget = 10 * sas.phi(math.random(30))
sas.append(dsh2)
sas.put_value(dsh2,"Name", name)
sas.put_value(dsh2,"Status", status)
sas.put_value(dsh2,"Gender", gender[1])
sas.put_value(dsh2,"Budget", budget)
sas.update(dsh2)
end
end
sas.close(dsh1)
sas.close(dsh2)
endsubmit;
run;
proc print data=xmas_list;
var _all_;
sum Budget;
run;
示例输出:
示例日志:
Making my christmas list:
My 1st cat's name is cat1, and she is usually nice
My 2nd cat's name is cat2, and he is usually naughty
My 3rd cat's name is cat3, and she is usually naughty
My 4th cat's name is cat4, and she is usually nice
My 5th cat's name is cat5, and she is usually naughty
My 6th cat's name is cat6, and he is usually nice
My 7th cat's name is cat7, and she is usually naughty
My 8th cat's name is cat8, and she is usually nice
答案 0 :(得分:1)
1)确定第j个猫后缀的部分,然后 将其打印到日志中。如何更改宏变量的值 在运行中然后在宏循环中使用它们来写东西 日志?有没有办法使用&#39;来电咨询&#39;或者&#39; symget&#39;在一个宏?
有一些宏语句如%PUT
用于向日志显示值。如果要在宏代码中执行循环,请使用%DO
语句。
%do i=1 %to 5 ;
%put I=&i ;
%end;
您可以使用%LET
分配宏变量值。
%let cat1=Fluffy;
%let cat2=Tiger ;
您可以从宏值构建宏变量引用。当您使用&&
时,它将被&
替换,并触发宏处理器再次传递以解析引用。
%let i=2 ;
%put Cat &i is &&cat&i ;
2)如何在宏循环中写入多个数据集, 类似于我在下面所做的。
您不能使用宏代码写入数据集。您可以使用宏代码生成可以写入数据集的SAS语句。并且您可以在不使用任何代码生成的情况下写入多个数据集。
data good bad;
set cats;
if status='nice' then output good;
else output bad;
run;
3)如何在sas中调用使用proc fcmp编译的自定义函数 宏控制宏的流程。
不确定这个,但为什么不只是有一个数据步骤来调用该函数?
data _null_;
call symputx('mvar',myfunc());
run;
%if (&mvar = 1) %then %do ;
...
%end;
答案 1 :(得分:1)
我将 proc lua 程序重新编写为数据步骤,正如Tom建议的那样,并且运行得更快。我能够通过创建一个包含我想要放入日志的消息的字符串来实现所需的日志,然后将其传递给put函数;之前,当我尝试过这样的事情时,我试图在put语句中构造字符串,这会返回错误。
echo $navbarCode;
答案 2 :(得分:0)
您可以通过将lua
从proc lua
中取出来实现。只要文件扩展名为%inc
,就可以直接在宏中使用.lua
lua代码。 mv_webout框架的sasjs宏采用了这种方法,以读取从javascript发送的数据。
这是一个简短的例子。
%macro my_lua();
filename mylua "%sysfunc(pathname(work))/some.lua";
data _null_;
file mylua;
put 'sas.submit([[';
put ' proc print data=sashelp.class;run;';
put ']])';
put 'print("some lua got in my macro code")';
run;
%inc mylua;
%mend;
%my_lua()