SAS BASE. Программирование на языке SAS BASE. Основы (1185351), страница 5
Текст из файла (страница 5)
до шага DATA, где используется!Теперь можно создать макроопределение:%macro readall;%do i=1 %to &tabnobs;_no= &i;set table(keep=c1) point=_no;row&i = c1;%end;%mend;data transposed2;%readalldrop c1;output;stop;run;data transposed1;_no=1;set table(keep=c1)point=_no;row1 = c1;_no=2;set table(keep=c1)point=_no;row2 = c1;drop c1;output;stop;run;70Программа с макросами для транспонирования таблицы%macro readall(j);%do i=1 %to &tabnobs;_no= &i;set table(keep=c&j) point=_no;row&i = c&j;%end;drop c&j;%mend;%macro doallcols;%do j=1 %to 4;%readall(&j)output;%end;%mend;data transposed2;%doallcolsstop;run;Как будет работать программа (шаг DATA) после компиляции макросов?Мы 4 раза вызываем макрос readallj, читающий данные из однойзаданной колонки исходной таблицы в новое наблюдение длятранспонированной таблицы.В какую программу «развернутся» эти два макроопределения? Этоможно реконструировать из log:1 data transposed2;2_no= 1;3set table(keep=c1)4row1 = c1;5_no= 2;6set table(keep=c1)7row2 = c1;8drop c1;9output;10_no= 1;11set table(keep=c2)12row1 = c2;13_no= 2;14set table(keep=c2)15row2 = c2;16drop c2;17output;18_no= 1;19set table(keep=c3)20row1 = c3;21_no= 2;22set table(keep=c3)23row2 = c3;24drop c3;25output;26_no= 1;27set table(keep=c4)28row1 = c4;29_no= 2;30set table(keep=c4)31row2 = c4;32drop c4;33output;34 stop;35 run;point=_no;point=_no;point=_no;point=_no;point=_no;point=_no;point=_no;point=_no;71Особенности макропроцессораСоздание 500000 макропеременных (не пытайтесь повторить это дома)data _null_;i=1;do while (i<=500000);call symputx('var'||put(i,Z6.),put(i,Z6.));i+1;,секend;run;Механизм хранениямакропеременных – медленныйпри большом размере хранимыхмакропеременных,не пользуйтесь им для хранениябольших объемов данных.(пользуйтесь наборами данных)Число макропеременныхДля более тонкой настройкиСм.
option msymtabmax: Once the maximum value is reached, additional macro variables arewritten out to disk.72%include (не работает в on-demand)• Вы можете “подставлять” в сеанс файлы с кодом SAS, и выполнять этоткод. Условие – чтобы файловая система с подставляемыми файламинаходилась на том же сервере, где установлен SAS.%include 'c:/workshop/myprogram.sas';• Чтобы отлаживать этот оператор на разных уровнях вложенности, естьспециальная опция:%INCLUDE 'c:/workshop/myprogram.sas’ /SOURCE2;Если эта опция включена, в log появляется код, который подставляется изуказанного файла и выполняется.73Пользовательские процедуры (FCMP)• Вы можете создавать собственные функции и подпрограммы (callroutines). Их можно использовать в разных шагах SAS (DATA, PROC SQL, впроцедурах SAS/OR (задачи оптимизации), SAS/STAT).• Особенность этого подхода - наличие централизованного хранилищапроцедур и функций (хотя у макросов тоже есть возможность сохранитьскомпилированный код в каталог и пользоваться им коллективно).Причем можно разделять «области видимости» функций.• Использует синтаксис, похожий на шаг DATA (но! со своимиособенностями)74Примерproc fcmp outlib=work.fun1.fun1;subroutine plus1(ind);outargs ind;ind=ind+1;endsub;Work.fun1 – это название набора данных, куда будутзаписаны (в специальной форме) функция иподпрограммаПодпрограмма plus1 (один входной аргументчислового типа,Тот же аргумент будет возвращен из подпрограммы –явно указываем с помощью outargs)endsub; после каждой функции/подпрограммыfunction myfactor(x);if (x=1) then return (1);Напишем свою функцию, вычисляющую факториал.else return (x*myfactor(x-1));Функция принимает и возвращает число.endsub;Return () – инструкция, которая возвращает результат иquit;options cmplib=work.fun1;data test;n=14;call plus1(n);f15=myfactor(n);f15a=fact(n);run;выходит из функции.Опция сmplib – где (и в каком порядке) будетпроизводиться поиск пользовательских функцийПосле вызова call, n=15Fact = это встроенная функция.75Пример 2 (Mandelbrot set plot)*proc fcmp outlib=work.funcs.temp ;function mnd (x0,y0); *returns color;/*For each pixel on the screen do:x0 = scaled x coordinate of pixel (must be scaled to lie somewhere in the mandelbrot X scale (-2.5, 1)y0 = scaled y coordinate of pixel (must be scaled to lie somewhere in the mandelbrot Y scale (-1, 1)*/x = 0;y = 0;iteration = 0;max_iteration = 1000;do while ( (x*x + y*y < 2*2) AND (iteration < max_iteration) );xtemp = x*x - y*y + x0;y = 2*x*y + y0;x = xtemp;iteration = iteration + 1;end;return(iteration);endsub;run;options cmplib=work.funcs.temp;data plotted;do x=-2.5 to 1 by 0.01;do y=-1 to 1 by 0.01;col=mnd(x,y);output;end;end;run;PROC GCONTOUR DATA = plotted;PLOT y * x = col /PATTERN;run;quit;* From wikipedia.76Просмотр своих функций и их отладка•Просмотр кода функции (если он не зашифрован)options cmplib=work.fun1;proc fcmpoutlib=work.fun1.fun1;listfunc myfactor;listfunc plus1;run;•Отладка функции – пользуемся log из функции.function myfactor(x);put x=;if (x=1) then return (1);else return (x*myfactor(x-1));endsub;•Отладка функции – ещё один способ (см.
окно Results-Listing, виден стеквызовов)proc fcmp outlib=work.fun1.fun1 TRACE ;function myfactor(x);if (x=1) then return (1);else return (x*myfactor(x-1));endsub;a=myfactor(15);Можно вызыватьput a=;run;функции прямо из proc fcmp77Процедура SQL• В SAS можно управлять структурой наборов данных с помощью языказапроса SQL.• SQL и шаг DATA дополняют друг друга. Подумайте, чем можно проще иэффективнее решать вашу задачу.• Справка: SAS® 9.3 SQL Procedure User's Guide• Совместимость: PROC SQL follows most of the guidelines set by the American NationalStandards Institute (ANSI) in its implementation of SQL.
However, it is not fully compliant withthe current ANSI standard for SQL. The SQL research project at SAS has focused primarily on theexpressive power of SQL as a query language. Consequently, some of the database features ofSQL have not yet been implemented in PROC SQL.• В общем, это ещё один способ работать с наборами данных SAS.• Синтаксис:proc sql <опции>;<Выражения языка SQL;>quit;78Создание таблицы и её вывод в отчет•Select выводит результаты SQL-запроса в отчет:proc sql;select * from ecsql1.qtr1_2007;quit;•Create table создаёт набор данных:proc sql;create table table1 asselect t1.order_id, t1.customer_id, t1.order_typefrom ecsql1.qtr1_2007 as t1where t1.order_type=2;quit;Избранные опции к proc sql:proc sql outobs=10;WARNING: Statement terminated early due to OUTOBS=10 option.proc sql inobs=10;19select * from ecsql1.qtr1_2007;WARNING: Only 10 records were read from ECSQL1.QTR1_2007 due to INOBS= option.proc sql noexec;NOTE: Statement not executed due to NOEXEC option.proc sql _method _tree;(информация от планировщика, официально не документировано, см.
Paper CS-11The SQL Optimizer Project: _Method and _Tree in SAS®9.1, Russ Lavery)79Объединение таблиц•«По горизонтали»proc sql;select * from ecsql1.qtr1_2007 as t1, ecsql1.customer as t2where t1.customer_id = t2.customer_id;quit;proc sql;select * from ecsql1.qtr1_2007 as t1 join ecsql1.customer as t2on t1.customer_id = t2.customer_id;quit;•«По вертикали», причем в новой таблице будут все переменные из входящихтаблиц (независимо от того, есть ли они сразу в обеих таблицах)proc sql;create table qtr12 asselect * from ecsql1.qtr1_2007outer union corrselect * from ecsql1.qtr2_2007;quit;См. Combining Queries with Set Operators80Использование функций SAS• В SQL-запросах можно использовать встроенные и пользовательскиефункции.proc fcmp outlib=work.fun1.fun1;function myfun(id) $ 4;str_id=put(id,10.);return(substr(str_id,1,4));endsub;run;options cmplib=work.fun1.fun1;proc sql;select order_id, myfun(order_id) as first_4_lett fromecsql1.qtr1_2007 ;quit;81Сведение данных• Подсчет агрегатовproc sql;select order_type, avg(quantity) format=3.1 label="Среднее!",sum(total_retail_price) format=dollar10.
label="это сумма"from ecsql1.order_factgroup by 1; *possible in group by, order by;quit;• Having: фильтрация по агрегатам:proc sql;select order_type, count(distinct customer_id), sum(total_retail_price)from ecsql1.order_factgroup by order_typehaving sum(total_retail_price) > 30000;quit;• Calculated: Операции с агрегатамиproc sql;select order_type, count(distinct customer_id) as people,sum(total_retail_price) as summ,calculated summ/calculated people as ratiofrom ecsql1.order_factgroup by order_type;quit;82Сведение данных. Remerge.• Эта особенность SAS SQL помогает сводить исходные данные и агрегатыбез вложенных запросов.• Задача: найти людей, которые имеют максимальную зарплату (salary) всвоей группе (gender).• Обычный SQL: с помощью вложенных запросовproc sql;select gender,salary from ecsql1.sales as t1,(select gender, max(salary) as maxsalaryfrom ecsql1.salesgroup by gender) as t2where t1.gender=t2.gender and t1.salary = t2.maxsalary;quit;• SAS SQL:proc sql;proc sql;select gender, salaryselect gender, salary,from ecsql1.salesmax(salary) as msgroup by genderfrom ecsql1.saleshaving salary = max(salary);group by genderquit;having ms=salary;quit;NOTE: The query requires remerging summary statistics back with the original83data.Использование макропеременных•С точки зрения макропроцессора, Proc SQL – обычная процедура, поэтомуподстановка макропеременных происходит без проблем:%let stat=min;proc sql;select * from ecsql1.salesgroup by genderhaving salary=&stat.(salary);quit;•В proc sql вы можете создавать макропеременные:proc sql;select avg(salary) into :macro_salfrom ecsql1.sales;quit;%put macro_sal=¯o_sal;•И несколько макропеременных (много трюков, см.
справку по INTO Clause):proc sql;select avg(salary),gender into :macro_sal1-:macro_sal2,:macro_gen1-:macro_gen2from ecsql1.salesgroup by gender;quit;%put macro_sal=¯o_sal1 macro_gen=¯o_gen1;%put macro_sal=¯o_sal2 macro_gen=¯o_gen2;84Использование макроопределенийoptions mprint mlogic symbolgen;%MACRO QTR12;proc sql;%do i=1 %to 2;select * from ecsql1.qtr&i._2007;%end;quit;%MEND;%QTR12MLOGIC(QTR12): Beginning execution.MPRINT(QTR12):proc sql;MLOGIC(QTR12): %DO loop beginning; index variable I; start value is 1; stop value is 2; byvalue is 1.SYMBOLGEN: Macro variable I resolves to 1MPRINT(QTR12):select * from ecsql1.qtr1_2007;MLOGIC(QTR12): %DO loop index variable I is now 2; loop will iterate again.SYMBOLGEN: Macro variable I resolves to 2MPRINT(QTR12):select * from ecsql1.qtr2_2007;MLOGIC(QTR12): %DO loop index variable I is now 3; loop will not iterate again.MPRINT(QTR12):quit;NOTE: PROCEDURE SQL used (Total process time):real time0.05 seconds.
. .MLOGIC(QTR12): Ending execution.85Задания1) В библиотеке ECPRG1 находятся наборы данныхEMPS2008, EMPS2009, EMPS2010. С помощью макросов иSQL произведите слияние этих наборов данных повертикали. (таблицы называются почти одинаково, адиапазон требуемых годов мы хотим менять)2) В той же библиотеке есть набор данныхLOOKUP_COUNTRY. Создать функцию, которая из столбцовLABEL и START сформирует строку типа “Andorra – AD“ (т.е.просто вставляет между ними дефис). Примените этуфункцию в SQL-запросе, который печатает таблицу вотчет.86Задания3) Пусть у нас есть таблица с произвольным числом числовых столбцов (соднотипными названиями).data wide_table;drop i;array col{1:23};do j=1 to 10;do i=1 to 23;col{i}=rand('uniform');end;output;end;run;Напишите программу (последовательность шагов data/proc), которая сама узнаёт, сколько вэтой таблице столбцов с названием “col*”, и создаёт новый набор данных, содержащийсумму этих столбцов.Подсказка: воспользуйтесь служебным представлением sashelp.vcolumnproc print data=sashelp.vcolumn;where libname="WORK";run;87.