87
Программирование на языке SAS BASE Лекция 1. Основы. Звежинский Дмитрий, SAS Russia/CIS [email protected] 1 Замечания об ошибках и опечатках просьба направлять лектору.

Программирование на языке SAS/BASE57705.selcdn.com/MSU_2013/LEC1.pdf · SAS Enterprise guide • Интерфейс для визуального программирования

Embed Size (px)

Citation preview

Программирование на языке SAS BASE

Лекция 1. Основы.

Звежинский Дмитрий, SAS Russia/[email protected]

1Замечания об ошибках и опечатках просьба направлять лектору.

Где взять эти лекции?И примеры программ?

• http://tiny.cc/msu_sas

2

SAS Enterprise guide• Интерфейс для визуального

программирования (в том числе через SAS on-demand)

• Но мы будем в нем программировать вручную (т.е. с помощью кода на языке SAS)

• Enterprise Guide не выполняет код – он отправляет его для выполнения на сервер, где стоит дистрибутив SAS

• В Enterprise Guideвозвращается результат выполнения программы (например, отчет) или журнал с отладочной информацией (например, ошибками).

3

Инструкции по установке SAS Enterprise guide (в версии on-demand) были даны ранее.

Как написать программу?

• Проект с программой сохраняется на вашем компьютере

• Данные хранятся на удаленном сервере (можно загружать и создавать свои).

4

• Можно сделать несколько отдельных программ (изображается в виде значка с бегущим человечком) и запускать их по отдельности ( ) или вместе ( ).

SAS on-demand настроен для работы с кодировкой UTF:Будьте аккуратны при работе с многобайтовыми кодировками!

Журнал выполнения (Log)

• Log – средство для отладки и диагностики выполнения программы. Работает для всех процедур SAS.

• Выводит текст запущенной программы и ошибки (если есть). Ошибки подробно описаны, иногда даются предложения по исправлению.

• Даже если ошибок сразу не видно, рекомендуется вдумчиво изучить Log.

5

Введение. Обзор языка SAS BASE

Данные (наборы

данных SAS, сторонние форматы)

Шаг DATA

(преобразование данных)

Набор данных SAS

Шаг PROC

Создание отчета

Создание набора

данных SAS(для

дальнейшего анализа)

6

Структура программы на языке SAS BASE

• Линейная структура программы. Нет циклов, операторов условного перехода.• Разные части программы обмениваются друг с другом данными в виде наборов

данных SAS. Эти части практически не связаны друг с другом.• Основная структура данных – набор данных (SAS data set). Все данные лежат на

жестком диске в виде файлов. Поэтому данных может быть очень много!• Нет инкапсуляции (в смысле сокрытия реализации кода за интерфейсом)• Только две (!) основные синтаксические конструкции:

• Шаг DATA (работа с данными – создание, чтение, добавление, изменение)• Шаг PROC – всё остальное

• Исторически основная цель программы – создание отчета (описание или анализ исходных данных) или запроса к данным (получение «среза» данных).

Наборы данных SAS (datasets)• Наборы данных – обычные «плоские» таблицы

7

• Переменные (столбцы) – одного из двух типов (числовые )или текстовые ( )

• Для хранения чисел отводится 8 байт. Для хранения текста – от 1 до 32767 байт.

• Названия переменных – до 32 символов: _ a-z 0-9• Регистр в названии переменной не важен• Нельзя начинать название переменной с цифры

Именно наборы данных SAS (либо данные, которые представляются в этом виде) обязаны подаваться на вход процедур (шаг proc)

Каждый столбец имеет набор атрибутов (правый клик мышью на заголовок – > properties), среди них: length (макс. кол-во байт, которые можно хранить в этой переменной для каждого наблюдения), name (название), label (ярлык, текстовое поле, где можно хранить более подробное описание переменной), type (тип), format (формат – правило для отображения данных в отчет или на экран)

Для работы с данными в формате SAS dataset можно применять большой набор собственных алгоритмов, а также стандартный язык запросов (SQL)

Наборы данных SAS (продолжение)• Наборы данных – обычные файлы (*.sas7bdat)

• Можно прозрачным образом подключать данные практически в любом виде (от excel/access до промышленных баз данных) через набор механизмов (engines).

• Импорт данных из большинства популярных форматов (file->import data)

• Можно создавать и редактировать прямо в Enterprise guide (file->new->data)

• Встроенный механизм для многопользовательского доступа (на чтение, с доступом на запись – нужно разбираться отдельно)

• SAS – это НЕ движок для базы данных (не гарантирует транзакционную целостность) и НЕ менеджер для организации хранения данных (разделение доступа, аудит данных и проч.), хотя некоторые возможности для этих целей у него имеются.

8

Библиотеки• Возникли как подход к централизованному хранению и

прозрачному использованию данных в программах SAS

9

Самый простой случай библиотеки –это наборы данных, находящиеся в одной директории.

При запуске SAS сразу имеется несколько служебных библиотек, временная библиотека Work (она будет очищена при отключении от сервера или завершении процесса sas.exe) и персональная библиотека Sasuser (данные хранятся постоянно).

В качестве библиотек можно подключать данные, которые физически находятся не в формате наборов данных SAS (промышленные БД, excel, access). Для большей части вашей программы будет всё равно, как (и где) данные хранятся.

Подключение библиотеки в on-demand

10

1. Подключиться к серверу SASApp

2. Подключить (Assign) нужную библиотеку

Создание библиотек• Подключение библиотеки производится:

– либо через «wizard» (Tools->assign project library) – ф.с. на сервере

– либо программным путём (оператор libname):

libname mylib ‘c:\dir_with_data‘;

mylib - название библиотеки: 0-9, a-z, _, не может начинаться с цифры, не более 8 символов длиной

• Подключенная таким образом библиотека «живет» до завершения процесса sas.exe (для Guide - до отключения от сервера)

• Теперь в программе можно обращаться к набору данных не указывая полный путь (c:\dir_with_data\testdataset.sas7bdat), а с помощью 2-х уровневого имени (которое записывается через точку):

mylib.testdataset

Если первая часть не указана – предполагается библиотека Work

Содержимое библиотеки можно посмотреть в окне «Server list», или с помощью процедуры:

proc contents data=sasuser._all_;

run;

11

Нельзя в on-demand

Программа на языке SAS Base

12

1 options linesize=95 pagesize=52;

2

3 data work.NewSalesEmps;

4 length First_Name $ 12 Last_Name $ 18

5 Job_Title $ 25;

6 infile 'newemps.csv' dlm=',';

7 input First_Name $ Last_Name $

8 Job_Title $ Salary;

9 run;

10

11 proc print data=work.NewSalesEmps;

12 run;

13

14 proc means data=work.NewSalesEmps;

15 class Job_Title;

16 var Salary;

17 run;

Программа на языке SAS Base• Программа не требует явного подключения «библиотек» с

процедурами, которые есть в установленном дистрибутиве SAS («#include»)

• Программа выполняется «сверху вниз» по шагам

• Минимальный «кусочек» программы, который SAS может выполнить, это один шаг (начинается с операторов «data», «proc»)

• Можно выполнить один или несколько шагов программы (выделить код мышкой и нажать кнопку RUN)

• Каждый оператор должен заканчиваться «;»• Каждый шаг должен заканчиваться операторами «run;»,

«quit;», или началом следующего шага

• Форматирование свободное (программу можно записать в одну строку, оператор можно разбивать на несколько строк)

13

Справка• Справка в свободном доступе (веб-интерфейс либо pdf)

http://support.sas.com/documentation

14

1) Поиск справки по элементам языка SAS BASE нужно начинать с описания интересующей процедуры (и уже в ней искать справку о конкретном операторе)

2) Пункт overview – общие слова о том, что может делать процедура (шаг PROC)

3) Пункт examples – для самых нетерпеливых

4) Дополнительные материалы*) Материалы конференции SUGI (обмен опытом между пользователями)*) Справки по конкретным продуктам SAS

Рекомендуется иметь под рукой:SAS/STAT(R) 9.3 User's GuideSAS(R) 9.3 Functions and CALL Routines: ReferenceBase SAS(R) 9.3 Procedures Guide, Second EditionSAS(R) 9.3 SQL Procedure User's Guide…

Шаг DATA• Обработку данных нужно было делать ещё до того, как был принят стандарт

для SQL (wiki: в 1986 году первый стандарт языка SQL был принят ANSI, SAS –развивается с 1966г, с 1976 как коммерческий продукт).

• Шаг DATA дополняет SQL и наоборот (SQL – работа с множеством наблюдений, шаг DATA – работа с единичными наблюдениями). Чем пользоваться для конкретных целей – нужно думать.

• Шаг DATA очень часто требует существенно меньше ресурсов по сравнению с SQL (важно если данных много), но нужно изучить логику его работы, которая бывает нетривиальной.

• Позволяет создавать и манипулировать наборами данных SAS (включая запись, чтение наборов данных, чтение необработанных данных, изменение структуры, создание агрегатов, объединение таблиц, фильтрацию наблюдений, можно использовать условные переходы, циклы, вызов пользовательских и встроенных функций, ...).

• Мы посмотрим малую часть того, что может шаг DATA. Справка по DATA STEP:

– SAS(R) 9.3 Language Reference: Concepts, Second Edition -> DATA Step Concepts

– SAS(R) 9.3 Language Reference: Concepts, Second Edition -> Dictionary of Language Elements -> SAS Data Set Options

15

Шаг DATAСамая простая операция – создание копии набора данных:

новый набор данных

исходный набор данных

Что происходит при запуске такого шага?(см. Overview of DATA Step Processing: Flow of Action)

16

26 data employees;

27 set employee_list;

28 run;

1) Фаза «компиляции»: - проверка синтаксиса- создание вектора данных (PDV) – области в

памяти, где хранятся значения переменных для одного наблюдения (строчки) из исходного набора данных, включая новые и служебные переменные.

- создание дескриптора (служебной части) для нового набора данных (хранит информацию о типах, названиях переменных, свойства набора данных и проч.)

Что происходит после фазы «компиляции»?

2) Фаза «выполнения» – выполнение “цикла” внутри шага data. Одна итерация цикла – это обработка одного наблюдения (строчки)

У нас он состоит только из одного оператора SET и неявных операторов, которых мы в программе не видим.

Вопрос: Когда этот цикл закончится?17

Шаг DATA26 data employees;

27 set employee_list;

28 run;

PDV:(в памяти)

Ошибок в синтаксисе нет

VAR1 VAR2 VAR3 … … … … … …

employees:(на диске)

Названия, типы и свойства переменных взяты из исходной таблицы на фазе компиляции

Data Set Name … Observations …

Member Type … Variables ..

Engine .. Indexes …

Created … Observation Length …

Last Modified … Deleted Observations …

VAR1 (Num) VAR2 (Char) VAR3 (Num)

Оператор SET

18

26 data employees;

27 set employee_list;

28 run;

PDV

VAR1 VAR2 VAR3

employees

Data Set Name … Observations …

Member Type … Variables ..

Engine .. Indexes …

Created … Observation Length …

Last Modified … Deleted Observations …

VAR1 (Num) VAR2 (Char) VAR3 (Num)

Employee_list

Data Set Name … Observations …

Member Type … Variables ..

Engine .. Indexes …

Created … Observation Length …

Last Modified … Deleted Observations …

VAR1 (Num) VAR2 (Char) VAR3 (Num)

1 AAA 200

2 BBB 201

3 CCC 202

0. Проверка на достижение конца исх. файла1. Явный оператор Set = Чтение из

Employee_list в PDV2. Неявный оператор Output = сброс

содержимого PDV в employees3. Неявный оператор Return = возврат к

началу цикла внутри шага DATA

1 AAA 200

1 AAA 200

2 BBB 201

2 BBB 201

3 CCC 202

3 CCC 202

Выбор наблюдений по условию

19

26 data employees;

27 set employee_list;

28 where age <= 65 and upcase(gender) = "M" ;

29 run;

Symbol Mnemonic

Equivalent

= EQ

^= NE

¬= NE

~= NE

> GT

< LT

>= GE

<= LE

IN

Symbol Mnemonic

Equivalent

& AND

| OR

! OR

¦ OR

¬ NOT

ˆ NOT

~ NOT

Замечания:1. Для числовых значений:

0 или . = Falseвсё остальное = True

( . – это пропущенное значение, missing)2. Операторы min (><) и max (<>):если A<B, то A><B вернёт значение A3. Оператор конкатенации для символьных значений:'grade '||'A'Этот оператор не обрабатывает пробелы, которые могут содержаться в переменных. Особенность хранения символьных переменных: значения добиваются пробелами справа до максимального размера переменной (см атриб. length)

Вхождение в список: state in ('NY','NJ','PA')

Действия с переменными на шаге DATA

Изменение значения переменной (или создание новой переменной):

При компиляции в оперативной памяти формируется специальная структура данных – Program Data Vector, который содержит место для всех переменных, имеющихся внутри шага DATA. Если Bonus был в employee_list – его свойства берутся оттуда, если нет – в PDV появляется новая переменная.

Откуда берутся свойства новой переменной?

1. Можно явно задавать самим (напр., тип, формат, длину)

2. Если они не заданы явно, то берутся свойства по умолчанию или из контекста программы (длина, тип)

3. При использовании функций – задаются самой функцией (тип, длина).

20

26 data employees;

27 set employee_list;

28 if upcase(Country)='US' then Bonus = 500;

29 else Bonus=0;

30 run;

* См. SAS(R) 9.3 Language Reference: Dictionary

Операторы условного перехода

1. Выполнение нескольких операторов в одной ветви условного перехода: IF expression THEN do;

…; …;…;

end;<ELSE do;

…;end;>

2. Ещё один вариант условного перехода (аналог switch-case):SELECT<(select-expression)>;

WHEN (when-expression-1) statement;<WHEN (when-expression-n) statement;><OTHERWISE statement;>

END;

Задание – найти справку по select-when и посмотреть примеры кода.21

Функции*Функции – это подпрограммы, которые возвращают одно значение

function-name (argument-1<, …argument-n>)

function-name (OF шаблон-названия)

Могут применяться на шаге DATA и PROC (например, в условиях-фильтрах)

Примеры функций:

SUM(argument,argument,... ) – сумма аргументов (пропущенные значения игнор.)

Sum и оператор «+» могут работать

по разному. Чему равны a1 и a2

в temp?

UPCASE(argument) – перевод символьной строки в верхний регистр

PUT(source, format.) – перевод числового аргумента в символьный с исползованием формата (format)

INPUT(source,informat.) – перевод символьного аргумента в числовой с использованием формата для ввода (informat)

Функции можно применять друг к другу без создания промежуточных переменных

22* Справка: SAS(R) 9.3 Functions and CALL Routines: Reference

B (Num) C (Num)

. 1

41 data temp;

42 set in_tab;

43 a1=b+c;

44 a2=sum(b,c);

45 run;

in_tab

Функции для даты и времениВнутренний формат даты в SAS – число дней с 01 января 1960 года

Внутренний формат времени – число секунд с полуночи

Внутренний формат временной метки (datetime) – число секунд с полуночи 01 января 1960 года

Для работы с такими данными (все хранятся в переменных числового типа) есть, в частности, функции:

23

DATE Текущая дата во внутр. Формате

DATEPART Извлекает часть, содержащую дату, из временной метки

DATETIME Текущая дата/время (timestamp)

DAY Число из даты во внутр. формате: day ( ’01jan2013’d ) -> 1 ; day (19359) -> 1

DHMS Returns a SAS datetime value from date, hour, minute, and second values.

HMS Returns a SAS time value from hour, minute, and second values.

HOUR Час из внутр. формата времени или временной метки

INTCK Количество временных промежутков, укладывающихся на данный интервал (годы, месяцы, недели …)

INTNX Increments a date, time, or datetime value by a given time interval, and returns a date, time, or datetime value.

MDY Дата во внутреннем формате из месяца, числа, года: Mdy(1,1,2013) -> 19359

MINUTE минуты из внутр. формата времени или временной метки

MONTH Месяц из внутр. формата даты

QTR Returns the quarter of the year from a SAS date value.

SECOND Returns the second from a SAS time or datetime value.

TIME Returns the current time of day as a numeric SAS time value.

TIMEPART Извлекает часть, содержащую время, из временной метки

TODAY Текущая дата во внутр. формате даты

WEEK Номер недели из внутр. формата даты

WEEKDAY День недели из внутр. формата даты

YEAR Год из внутр. формата даты

YRDIF Returns the difference in years between two dates according to specified day count conventions; returns a person’s age.

Формат*• Это правило для вывода данных

24* см. SAS(R) 9.3 Formats and Informats: Reference

1 data test;

2 x=19359;

3 y=19359;

4 format y ddmmyy.;

5 z1=put(x,ddmmyy.);

6 z2=input(z1,ddmmyy10.);

7 run;

Числовой тип

Тоже числовой тип, но выводится как дата

Преобразовали число в строку символов

… и наоборотИнформация о формате (для переменной Y) сохраняется в дескрипторе набора данных.

1) При применении формата сами данные не меняются (переменная y - число)2) Формат в SAS – это не только форматирование данных, но и метод табличного поиска (создание и поддержка централизованных справочников). Часто применяется, чтобы избежать хранение избыточных данных.3) Шаблоны для вывода на экран можно создавать самому (proc format, Tasks -> Data -> Create format … ).

Вывод наблюдений в наборы данных

25

1 data test1 test2;

2 x=19359;

3 output test1;

4 x=19360;

5 output test1 test2; * output ;

6 format x ddmmyy.;

7 run;

Компиляция:1) Формирование PDV (только 1 переменная: х),2) Формирование дескрипторов наборов данных test1, test23) Информация о формате записана в дескрипторы test1 и test2

Выполнение:А) Заносим х=19359 в PDV, Б) Сбрасываем содержимое PDV в test1 (явный оператор output)В) Заносим х=19360 в PDV, Г) Сбрасываем PDV в test1, test2 (явный оператор output)Д) Завершение шага DATA

АБВГ

Опции набора данных (keep, drop, where, end)

26

1 data test1 (keep=x y);

2 x=today();

3 y=datetime();

4 z=time();

5 keep x y;

6 run;

Опция набора данных – в test1 будут выведены только x,y

Оператор keep - во все наборы данных будут выведены только x,y

ИЛИ

Keep: оставить в наборе данных только указанные переменныеDrop: оставить все переменные за исключением указанных

1 data test;

2 set ecprg1.accounts

3 (where=(Employee_ID between 11000 and 11999));

4 run; Опция во входящем наборе данных, фильтрация при чтении данных (если в новом наборе данных – при записи)

1 data test;

2 set ecprg1.accounts

3 (rename=(account=code));

4 run; Опция работает в исходящем и входящем наборе данных, переменная account будет переименована в code (в данном случае-в PDV и исходящем наборе данных)

Программирование на языке SAS BASE

Лекция 2. Основы.

Звежинский Дмитрий, SAS Russia/[email protected]

Замечания об ошибках и опечатках просьба направлять лектору.

Установка SAS on-demand

P.S. Если к Вам будут обращаться с проблемами установки, может быть поможет:

При инсталляции клиента возникла ошибка, требовалось установить .NET Framework 4. Ноэто не помогло, ровно как и SP1. Помоглаустановка языкового пакетаhttp://www.microsoft.com/ru-ru/download/details.aspx?id=3324

28

Циклы DO

1 data test;

2 n=0;

3 do until(n>=5);

4 n+1;

5 output;

6 end;

7 run;

8

9 data test;

10 n=0;

11 do while(n<5);

12 n+1;

13 output;

14 end;

15 run;

16

17 data test;

18 do n=1 to 5;

19 output;

20 end;

21 run;

1.

2.

3.

По умолчанию новая переменная инициализируется пропущенным значением

В данном случае – то же, что n=n+1;

Вывести в набор данных целые цифры от 1 до 5 (включительно)

Условие проверяется в конце цикла

Условие проверяется в начале цикла

29

1 data test;

2 n=1;

3 lbl1:

4 output;

5 n=n+1;

6 if n<=5 then go to lbl1;

7 run;

А если хочется, можно вообще без циклов:

Особенности шага Data• Тип переменной и её «длина» (атрибут length)

Вопрос: какая длина будет у переменных? А какое значение?

При выполнении оператора “=“:

• Длина числовой переменной по умолчанию 8 байт

• Длина символьной «наследуется».

30

числовая символьная

length a 4; length a $ 4;

x=a; x=a;

x1='ABCDE';

Особенности шага Data

• Посмотрим две программы:

• Вопросы: а) когда закончится выполнение программ?

• б) сколько итераций сделает цикл в каждой программе?

• в) будет ли отличаться результат?

Смотрим в log:

31

№1 №2

data test;set work.test1;

run;

data test;set work.test1;set work.test1;

run;

Work.test

NOTE: There were 2 observations read from the data set WORK.TEST1.NOTE: The data set WORK.TEST has 2 observations and 2 variables.NOTE: DATA statement used (Total process time):

real time 0.00 secondscpu time 0.00 seconds

...NOTE: There were 2 observations read from the data set WORK.TEST1.NOTE: There were 2 observations read from the data set WORK.TEST1.NOTE: The data set WORK.TEST has 2 observations and 2 variables.

Первый шаг data

Второй шаг data

Особенности шага Data

• Как работает эта программа?

32

data test;set work.test1;set work.test1;

run;

Итерация 1.Первый set: записывает первое наблюдение test1 в PDVВторой set: записывает первое наблюдение test1 в PDVНеявный оператор output (Содержимое PDV переносится в новый набор данных)Неявный оператор returnИтерация 2.Первый set: записывает второе наблюдение test1 в PDVВторой set: записывает второе наблюдение test1 в PDVНеявный оператор output (Содержимое PDV переносится в новый набор данных)Неявный оператор returnИтерация 3.Первый set: наткнулись на конец файла, шаг data закончен.

Оператор put выводит в log содержимое одной или нескольких переменных PDV

Набегающие суммы• Пример: каким образом пронумеровать наблюдения?

33

1 data test;

2 ctr=0;

3 put ctr=;

4 set ecprg1.contacts;

5 ctr=ctr+1;

6 put _all_;

7 run;

8

9 data test;

10 retain ctr 0;

11 set ecprg1.contacts;

12 ctr=ctr+1;

13 run;

14

15 data test;

16 set ecprg1.contacts;

17 ctr+1;

18 run;

Выводит значение переменной в log

Просмотр содержимого PDV (в log)

Не работает

Создается новая переменная ctr, инициализируется нулём, её значение не будет сбрасываться в missing в начале каждой итерации шага DATA

Эта запись – аналог двух операторов в предыдущей программе (retain и увеличение счетчика)

Сортировка наборов данных (Proc SORT)

34

1 proc sort data=ecprg1.contacts out=tempsort;

2 by descending name;

3 run;

4

5 proc sort data=ecprg1.nonsalesdupes(keep=employee_id first last)

6 dupout=dup1 out=nondup1 NODUPKEY;

7 by employee_id;

8 run;

9 proc sort data=ecprg1.nonsalesdupes(keep=employee_id first last)

10 dupout=dup2 out=nondup2 NODUPRECS;

11 by employee_id;

12 run;

1 proc sort data=ecprg1.contacts out=tempsort;

2 by descending name;

3 run;

4

5 proc sort data=ecprg1.nonsalesdupes(keep=employee_id first last)

6 dupout=dup1 out=nondup1 NODUPKEY;

7 by employee_id;

8 run;

9 proc sort data=ecprg1.nonsalesdupes(keep=employee_id first last)

10 dupout=dup2 out=nondup2 NODUPRECS;

11 by employee_id;

12 run;

Куда будет выведен отсортированный набор данных?

Входящий набор данныхПо каким переменным сортировать?

Proc SORT умеет искать и выделять дубликаты:

А

Б

А: Дубликатами считаются записи с одинаковым значением employee_id. Дубликаты выводятся в набор данных dup1, все остальные записи – в nondup1

Б: Дубликатами считаются записи, если они полностью совпадают друг с другом (все поля, которые мы читаем из nonsalesdupes: employee_id, first, last)

Оператор by (шаг DATA)• Если набор данных отсортирован по некоторой переменной, на шаге DATA мы

можем работать с маркерами начала и конца группы наблюдений с одним и тем же значением этой переменной.

35

Пример:Как посчитать сумму Quantity для каждого Customer_ID?

1 proc sort data=ecprg1.usorders04 out=usord_sort;

2 by customer_id;

3 run;

4

5 data summary_cust (keep=sum customer_id);

6 set usord_sort;

7 by customer_id;

8 if first.customer_id=1 then sum=0;

9 sum+quantity;

10 if last.customer_id then output;

11 run;

Сортировка!

First.variable = 1 для первого наблюдения в группе, =0 для других наблюдений,Last.variable =1 для последнего наблюдения в группе, =0 для других наблюдений

Операторы where, if (создание выборки на шаге DATA)

• Оператор where (как и опция набора данных where) работает только с переменными, которые уже есть во входящем наборе данных.

• Оператор where работает не только на шаге DATA, но и в процедурах.

• If работает со всеми переменными, которые присутствуют в PDV, в том числе со служебными и «новыми»

36

1 data plist1;

2 set ecprg1.product_list;

3 where product_id between 210000000000 and 219999999999 ;

4 run;

5

6 data plist2;

7 set ecprg1.product_list;

8 two_digits=int(product_id/10000000000);

9 if two_digits = 21 ;

10 run;

Задача: выбрать наблюдения, где product_list начинается с цифр 21

В первом случае мы используем для фильтрации оператор where и переменную, которая уже есть во входящем наборе данных. Во втором – создаем новую переменную и пользуемся оператором “if” (без “then”, т.е. создающим выборку).

Операторы where, if (создание выборки на шаге DATA)

Полезные операторы и функции для работы с текстом:– Поиск подстроки с учетом регистра

where string CONTAINS ‘Woman‘ ;

– Простой шаблон: знак подчеркивания – любой символ, процент – любое количество любых символов, регистр важен

where string LIKE ‘%Wom_n%‘ ;

– Поиск без учета регистра: см. функцию find

where find(string,‘woman‘, ‘I‘) >0 ;

– Вырезать подстроку: см. функцию substr, второй аргумент – номер символа, начиная с которого её вырезать, третий – сколько символов вырезать

where substr(string,1,5)= ‘woman‘ ;

Эту же функцию можно использовать для замены части текста

– Длина текстовой строки без учета конечных пробелов: см. функцию length

where length(string)= 5 ;

– Замена в тексте комбинации символов: см. функцию tranwrd

37

Использование RegExp*

38* http://support.sas.com/rnd/base/datastep/perl_regexp/regexp-tip-sheet.pdf

1 data plist;

2 set ecprg1.product_list;

3 where prxmatch('/^Woman/', product_name )>0;

4 run;

В SAS можно использовать «регулярные выражения» - стандарт для поиска шаблонов в тексте.

Примеры: 1) Поиск наблюдений, где product_nameначинается со слова “Woman”:

Prxmatch возвращает номер первого символа, где найден указанный шаблон.

1 data plist(keep=product_name product_name1);

2 set ecprg1.product_list;

3 where prxmatch('/Woman/', product_name )>0;

4 product_name1= prxchange('s/Woman/Man/', -1, product_name);

5 run;

2) Поиск наблюдений и замена с помощью регулярных выражений:

Prxchange производит указанное кол-во замен (-1 = без ограничений) по шаблону в тексте, указанном в третьем аргументе (product_name).

Call routines* (процедуры)• Это ещё один вариант подпрограмм, отличается от функций тем, как

возвращаются результаты.

• Их нужно вызывать с помощью оператора CALL:

CALL routine-name (argument-1<, ...argument-n>);

CALL routine-name (OF variable-list);

При этом аргумент может передавать значение в процедуру и/или в него возвращается какой-то результат работы процедуры.

Примеры использования шаблонов для названия переменных-аргументов:

call cats(result,of y1-y15);

call cats(result,of y:);

Первый пример - конкатенация 15 символьных переменных (y1, y2, y3, … , y 15) в переменную result. Второй пример – конкатенация всех переменных, которые начинаются с «y». (тогда они все должны быть правильного типа!)

call missing(sales);

Одному или нескольким аргументам будет присвоено пропущенное значение (missing) – числовое или символьное, в зависимости от типа аргумента.

39* Справка: SAS(R) 9.3 Functions and CALL Routines: Reference

Очередь для переменной (Lag)

• Шаг DATA последовательно читает наблюдения из набора данных. Что делать, если нужно запомнить значение переменной, и использовать его на следующей итерации шага DATA?

Пример:Посчитаем разницу между значениями переменной hires в текущем и в прошлом году.

40

1 data dif1;

2 set ecprg1.yearly_saleshires;

4 dif0=lag(hires);

5 dif1=hires-lag(hires);

6 dif2=dif(hires);

7 run;

1. Можно смотреть не на одно, а на несколько наблюдений назад (функции lag2(..), lag3(..), … 2. Каждая функция lag в программе формирует свою очередь. 3. При вызове функции возвращается значение из начала очереди, далее происходит сдвиг и в конец очереди помещается текущее значение аргумента.4. Перед первой итерацией шага DATA очередь заполняется пропущенными значениями (missing).

Импорт данных• Есть программные способы, обсуждение которых сложно показать в on-

demand.

• Поэтому, если формат файлов не слишком сложный, выберите

file->open->data

• Выберите библиотеку, куда вы хотите сохранить данные в виде набора данных SAS (on-demand: work)

• Если данные находятся в виде необработанных файлов с данными (raw data), вдобавок запустите для них мастер импорта:

41

PROC PRINT• Распечатка набора данных (листинг) в виде отчета.

PROC PRINT <option(s)>;

BY <DESCENDING> variable-1 <…<DESCENDING>variable-n>;

….

VAR variable(s) <option>;

В заголовке PROC Print указывается название набора данных и некоторые настройки отчета.

Оператор By (не обязательный) задает разбивку отчета по указанным переменным (требуется предварительная сортировка набора данных)

Оператор Var (не обязательный) задает структуру отчета, в нем перечисляются переменные, которые мы хотим вывести в отчет. Если этого оператора нет – выводятся все столбцы из набора данных.

Пример:

42* Base SAS® 9.3 Procedures Guide -> PRINT Procedure

1 proc print data= ecprg1.customer noobs;

2 var customer_id country gender;

3 run;

PROC MEANS• Отчет с описательной статистикой для набора данных (в том числе с

разбивкой по классифицирующей переменной)

43* Base SAS® 9.3 Procedures Guide -> MEANS Procedure

proc means data=ecprg1.monthly_prices n mean max min;

var unit_cost_price;

class month;

run;

Процедура умеет рассчитывать ~ 30 разных статистик для выборки

PROC GPLOT

44

1 proc gplot data=ecprg1.budget;

2 plot (Yr2003 Yr2005) * Month / overlay;

3 run;

Это процедура позволяет, в частности, создавать линейные графики.Пример: построить два линейных графика на одних осях координат, данные находятся в наборе данных budget.

* SAS/GRAPH® 9.3 Reference -> SAS/GRAPH procedures -> GPLOT procedure

Диаграммы

45

proc gchart data=ecprg1.donate;

pie qtr /

DISCRETE sumvar=amount;

run;

quit;

http://robslink.com/SAS/Home.htmhttp://support.sas.com/sassamples/graphgallery/PROC_GCHART.html

На что способен SAS/Graph (примеры + программы)

Манипуляции с выводом1. Сохранение нескольких отчетов в файл стороннего формата

ods pdf file=‘~/my.pdf';

proc gchart data=ecprg1.donate;

pie qtr / DISCRETE sumvar=amount;

run;

quit;

proc print data=ecprg1.donate;

run;

ods pdf close;

Пояснения:

*) ~/ : обозначение домашней директории в linux

*) Вместо формата pdf можно использовать другие форматы: HTML, RTF, … LaTeX,…

*) Справка: SAS(R) 9.3 Output Delivery System: User's Guide, Second Edition

46

Манипуляции с выводом2. Сохранение объекта из отчета в набор данныхproc means data=ecprg1.budget;

var yr2003 yr2004;

run;

Шаг 1. Узнать имя объекта:ods trace on;

proc means data=ecprg1.budget;

var yr2003 yr2004;

run;

ods trace off;

Шаг 2:ods output Summary=work.tab1;

proc means data=ecprg1.budget;

var yr2003 yr2004;

run;

47

Задания• Установить SAS On-Demand по инструкции.

• Самостоятельно проделать демонстрации со слайдов, подумать над вопросами

• Создайте с помощью Excel файл с двумя колонками, x и y. Причем x=-10:0.1:10, а y вычисляется как sin(x)

• Импортируйте файл Excel в набор данных SAS средствами SAS Enterprise Guide (меню file-> open->data …)

• Напишите шаг Data, где вычисляется «скользящая» сумма по этому набору данных с заданным «окном» (пусть 5 точек)

• Постройте значение этой суммы на графике

48

Задания• Напишите шаг data, где создаётся набор данных с двумя

переменными (x, y) и 50 наблюдениями. В каждом наблюдении x выбирается случайно (равномерно распределено от -1 до 1), а y считается как x^2.

• Отсортируйте этот набор данных по переменной x.

• Численно проинтегрируйте y(x), например, с помощью формулы трапеций, воспользовавшись вторым шагом data.

• Найдите самостоятельно «рецепты», как можно объединить «по вертикали» два набора данных. Напишите программу, которая это делает с таблицами ecprg1.2008, ecprg1.2009 и ecprg1.2010

49

Макроподстановки• Мы научились писать код на языке SAS Base, но он не очень «гибкий».

– У нас нет возможности организовать условное ветвление программы между частями кода

– … и циклы, внутри которых выполняются шаги программы.

– Мы не можем повторно использовать отлаженную часть кода.

– Нет возможности вводить в программу параметры для повторного использования кода в разных частях программы. Если нужно поменять один и тот же кусок кода – только средствами редактора(search - replace)

• Чтобы решить эти задачи, в SAS есть надстройка над языком SAS Base, которая называется SAS Macro.

• Help: SAS® 9.3 Macro Language Reference

• По сути это продвинутый (и автоматизированный) вариант «copy»+«paste». Путь разработчика – написать и отладить программу безмакросов, а потом добавить макросы.

50

Как работает макропроцессор• Существуют специальные инструкции, чтобы управлять

макроподстановками в код программы, условными переходами и динамическим созданием кода (когда используются подстановки с параметрами)

• Макропроцессор выполняет обработку программы до её компиляции (синтаксической проверки) и исполнения. После работы макропроцессора должен получиться код на языке SAS BASE без каких-либо макро-инструкций. Другими словами, синтаксис и логика макро-языка и SAS BASE изолированы друг от друга. Мы должны научиться их «дружить» между собой.

• Первый пример макроинструкции – это создание и подстановка макропеременной.

Пример: распечатаем n первых наблюдений из набора данных, где n будет задаваться макропеременной.

Решение без макросов: использовать опцию к набору данных «obs=«

proc print data=ecprg1.donate(obs=10);

run;

51

Как работает макропроцессор• Создание макропеременной (одним оператором можно создать только одну

переменную):

%let numb_of_obs = 10 ;

• Название – не более 32 символов английского алфавита (+ цифры и знак подчеркивания), регистр не важен, начинается с буквы или знака подчеркивания.

• Всё, что стоит между знаком «=» и знаком «;» является значением макропеременной numb_of_obs.

• Любое значение макропеременной – это текст, который потом будет куда-то подставлен. Разделения на символьный и числовой тип – нет.

• Математические выражения не выполняются

• Регистр хранимого текста сохраняется

• Минимальная длина 0 символов, максимальная – 65534 симв.

• Пробелы с начала и с конца значения удаляются.

• Значение макропеременной «живёт» до конца сеанса (или завершения процесса SAS)

• …или до применения макрофункции %symdel ;

52

Пользовательские макропеременные• Вывод в log значения макропеременной:%put &numb_of_obs ;

• Подстановка макропеременной в программу:proc print data=ecprg1.donate(obs=&numb_of_obs);

run;

• Log:15 %let numb_of_obs = 10 ;

16 %put &numb_of_obs ;

10

17 proc print data=ecprg1.donate(obs=&numb_of_obs);

18 run;

• По умолчанию все средства для отладки выключены, и мы не видим сообщений от макропроцессора.

• Макропеременные можно подставлять одну в другую:15 %let x=aaa;

16 %let x=&x bbb;

17 %put &x;

aaa bbb

• Задание явной границы (.) в коде для названия макропеременной:15 %let x=aaa;

16 %let x=&x.bbb;

17 %put &x;

aaabbb 53

Отладка макропеременных• Вывод в log только пользовательских переменных:

%PUT _USER_ ;

• Вывод в log всех макропеременных:

%PUT _ALL_ ;

• Включить глобальную опцию symbolgen:15 options symbolgen;

16 %let x=aaa;

17 %let x=&x.bbb;

SYMBOLGEN: Macro variable X resolves to aaa

18 %put &x;

SYMBOLGEN: Macro variable X resolves to aaabbb

aaabbb

• Выключить её, если макрос отлажен: options nosymbolgen;

• Log всегда содержит информацию об ошибках разрешения макроподстановок:

17 %let x=&x11.bbb;

WARNING: Apparent symbolic reference X11 not resolved.

18 %put &x11;

WARNING: Apparent symbolic reference X11 not resolved.

&x11

54

Работа с макропеременными• Подстановка переменных в программу:15 %let library= ecprg1 ;

16 %let dataset= donate ;

17 data temp1;

18 set &library..&dataset ;

19 run;

NOTE: There were 16 observations read from the data set ECPRG1.DONATE.

NOTE: The data set WORK.TEMP1 has 16 observations and 3 variables.

• Подстановка переменной в символьные константы:Одинарные кавычки – макропроцессор не подставляет значение макропеременной, двойные кавычки – подставляет:15 %let text1= Privet! ;

16 data _null_;

17 put "&text1";

18 put '&text1';

19 run;

Privet!

&text1

• Автоматические макропеременные:SYSDATE, SYSDATE9, SYSDAY, SYSTIME – дата, день недели и время, когда был запущен

процесс SAS (могут отличаться от текущих!)SYSLAST – название самого последнего набора данных, который был созданSYSERR – код возврата шага DATA или PROC (0=ошибок нет)SYSLIBRC – код возврата оператора LIBNAME (создание ссылки на библиотеку,

0=ошибок нет)

55

Программирование на языке SAS BASE

Лекция 3:Макросы и SQL

Звежинский Дмитрий, SAS Russia/[email protected]

56Замечания об ошибках и опечатках просьба направлять лектору.

Решение домашних заданий

Нам нужны рабочие программы (не проекты) с вашим sas code на адрес

[email protected]

с пометкой в subject “VMK Course Task #” с номером задания.

57

Макроопределения• Макропроцессор может динамически создавать код, используя заданные

шаблоны для макроподстановки.

• Шаг 1. Определение макрофункции.%macro my_macro_fun;

proc print data=ecprg1.donate;

var employee_id qtr amount;

run;

%mend;

• Шаг 2. Вызов макрофункции: если макроопределение было занесено в макропроцессор, оно подставляется в сеанс и выполняется.

%my_macro_fun

Компиляция и выполнение шага происходит, когда будут разрешены (=подставлены) все макропеременные, то есть можно писать что-то типа:%macro my_macro_fun1;

proc print data=ecprg1.donate;

%mend;

%macro my_macro_fun2;

var employee_id qtr amount;

%mend;

%my_macro_fun1

%my_macro_fun2

run; 58

Макропроцессор запомнит этот кусок кода

Вопрос: чем отличаются макроопределения от макропеременных?(ответа пока не было)

Порядок выполнения макроопределения

15 options mcompilenote=all;

16 %macro test1;

17 data _null_;

18 a=&ttt;

19 run;

20 %mend;

NOTE: The macro TEST1 completed compilation without errors.

5 instructions 88 bytes.

21 %test1

MLOGIC(TEST1): Beginning execution.

NOTE: Line generated by the invoked macro "TEST1".

21 data _null_; a=&ttt; run;

_

22

MPRINT(TEST1): data _null_;

WARNING: Apparent symbolic reference TTT not resolved.

MPRINT(TEST1): a=&ttt;

MPRINT(TEST1): run;

59

Этот код компилируется (запоминается) макропроцессором, т.к. он не содержит ошибки макро-синтаксиса, но в нем могут присутствовать другие виды ошибок (разрешение макро переменных, или ошибки SAS BASE)

Макропеременной «ttt» не существует, ошибка в разрешении этой переменной привела к появлению в программе SAS непонятной конструкции

Обратите внимание, что макро-переменные разрешаются после выполнения макроопределения

Отладка макроопределений• Options mcompilenote=ALL;

NOTE: The macro MYMACRO completed compilation without errors.

• Options mlogic;

Помогает отлаживать условные переходы в макропрограммах

• Options mprint;

Печатает код, который генерируется макросом

• Список макроопределений (не работает в on-demand)proc catalog cat=work.sasmacr;

contents;

run;quit;

• Список макропеременных: служебное представление sashelp.vmacro

• Отключите все отладочные опции (Options mcompilenote=NONE nomlogic nomprint; ) после отладки.

60

Вызов макроопределений• Макропеременные можно подставлять в макроопределения.Options mcompilenote=ALL mlogic mprint symbolgen;

%let dataset=ecprg1.donate ;

%let vars=employee_id qtr amount;

%macro my_macro_fun1;

proc print data=&dataset;

var &vars;

run;

%mend;

%my_macro_fun1

61

Определяем макропеременные

Определяем макроопределение

Вызов макроопределения16 %let dataset=ecprg1.donate ;

17 %let vars=employee_id qtr amount;

18 %macro my_macro_fun1;

19 proc print data=&dataset;

20 var &vars;

21 run;

22 %mend;

NOTE: The macro MY_MACRO_FUN1 completed compilation without errors.

5 instructions 104 bytes.

23 %my_macro_fun1

MLOGIC(MY_MACRO_FUN1): Beginning execution.

SYMBOLGEN: Macro variable DATASET resolves to ecprg1.donate

MPRINT(MY_MACRO_FUN1): proc print data=ecprg1.donate;

SYMBOLGEN: Macro variable VARS resolves to employee_id qtr amount

MPRINT(MY_MACRO_FUN1): var employee_id qtr amount;

MPRINT(MY_MACRO_FUN1): run;

NOTE: . . .

MLOGIC(MY_MACRO_FUN1): Ending execution.

LOG:

Параметры в макроопределениях• В макроопределения можно передавать параметры.%macro my_macro_fun1(dataset, vars);

proc print data=&dataset;

var &vars;

run;

%mend;

%my_macro_fun1(ecprg1.donate,employee_id qtr amount)

62

NOTE: The macro MY_MACRO_FUN1 completed compilation without errors.

9 instructions 232 bytes.

20 %my_macro_fun1(ecprg1.donate,employee_id qtr amount)

MLOGIC(MY_MACRO_FUN1): Beginning execution.

MLOGIC(MY_MACRO_FUN1): Parameter DATASET has value ecprg1.donate

MLOGIC(MY_MACRO_FUN1): Parameter VARS has value employee_id qtr amount

SYMBOLGEN: Macro variable DATASET resolves to ecprg1.donate

MPRINT(MY_MACRO_FUN1): proc print data=ecprg1.donate;

SYMBOLGEN: Macro variable VARS resolves to employee_id qtr amount

MPRINT(MY_MACRO_FUN1): var employee_id qtr amount;

MPRINT(MY_MACRO_FUN1): run;

NOTE: ...

MLOGIC(MY_MACRO_FUN1): Ending execution.

LOG:

2 аргумент1 аргумент

У макропеременных есть области видимости, см help -> Examples of Macro Variable Scopes. Областью видимости переменной можно принудительно управлять с помощью %global (перем. видна во всем макрокоде) и %local (только в данном макросе)

• В макроопределениях можно задать параметры с помощью двух нотаций (позиционная и по ключевому слову). значение параметра по умолчанию, а также передавать параметры в макроопределение в произвольном порядке

%macro my_macro_fun1(dataset, var1=employee_id,var2=qtr, var3= );

proc print data=&dataset;

var &var1 &var2 &var3 ;

run;

%mend;

%my_macro_fun1(ecprg1.donate)

. . .

MLOGIC(MY_MACRO_FUN1): Parameter DATASET has value ecprg1.donate

MLOGIC(MY_MACRO_FUN1): Parameter VAR1 has value employee_id

MLOGIC(MY_MACRO_FUN1): Parameter VAR2 has value qtr

MLOGIC(MY_MACRO_FUN1): Parameter VAR3 has value

%my_macro_fun1(ecprg1.donate,var2=amount)

. . .

MLOGIC(MY_MACRO_FUN1): Parameter VAR2 has value amount

MLOGIC(MY_MACRO_FUN1): Parameter VAR1 has value employee_id

MLOGIC(MY_MACRO_FUN1): Parameter VAR3 has value

63

Параметры в макроопределениях

LOG:

LOG:

Условный переход%if &var = CHANGE %then

%do;

...ПОДСТАНОВКА1

%end;

%else %if &var = SAME %then

%do;

...ПОДСТАНОВКА2

%end;

• В условии, которое проверяет оператор %if, должны находиться макропеременные и/или макрофункции, то есть то, с чем может «разобраться» макропроцессор на момент вызова этого выражения.

• Оператор %if можно вызвать только внутри макроопределения:15 %let var=1;

16 %if &var =0 %then

ERROR: The %IF statement is not valid in open code.

17 %do;

• Проверяемое выражение должно возвращать «число», в противном случае макропроцессор выдаёт ошибку.

• Чтобы вычислить арифметическое выражение в макропроцессоре, нужно использовать функцию %eval(…). Её особенность – принимает только целые аргументы и округляет результат до целого.

ERROR: A character operand was found in the %EVAL function or %IF condition where a

numeric operand is required. The condition was:

4+0.9

15 %put %eval(4+0.9);

16 %put %eval(1/3);

0 64

Операции, которые можно использовать для %if• Список (IN) (не работает без options minoperator;)15 %macro test;

16 %let var=A;

17 %if &var IN A B C D %then %put true;

18 %else %put false;

19 %mend;

20 %test

true

• 0 = false, <>0 = true15 %macro test;

16 %if 0 %then %put true;

17 %else %put false;

18 %mend;

19 %test

False

• Условие вычисляется после разрешения макропеременных16 %macro test;

17 %let var=1;

18 %let oper= ~;

19 %let var2=0;

20 %if &var &oper &var2 %then %put true;

21 %else %put false;

22 %mend;

23 %test

true

65SAS(R) Macro Language: Reference->Macro Expressions->Defining Arithmetic and Logical Expressions

• %SYSEVALF(expression<, conversion-type> )

Вычисление арифметических и логических операций (в т.ч. с нецелыми числами)15 %put %sysevalf(4+0.9);

4.9

• %SYSFUNC (function(argument-1 <...argument-n>)<, format> )

Выполняет функцию SAS и возвращает результат16 %put %sysfunc(ceil(0.9));

1

17 %put %sysfunc(today());

19498

• %NRSTR (character-string)

Экранировка служебных символов, в том числе «&»15 %let xstring1=&VARVAR;

16 %let xstring2=%nrstr(&VARVAR);

17 %put &xstring1;

WARNING: Apparent symbolic reference VARVAR not resolved.

&VARVAR

18 %put &xstring2;

&VARVAR

• %SUBSTR (argument, position<, length> ) 19 %put %SUBSTR (argument, 4, 4 ) ;

umen

66

Макрофункции

* см. SAS® 9.3 Macro Language Reference

Циклы• Можно использовать только внутри макроопределений.

• Справка: %DO, Iterative Statement ; %DO %UNTIL Statement ; %DO %WHILE Statement

• Пример: создание 10 наборов данных, внутри каждого – по 10 наблюдений%macro test;

%do i=1 %to 10;

data test&i;

do i=1 to 10;

output;

end;

run;

%end;

%mend;

%test

• В примере шаг DATA с 10 разными названиями набора данных будет выполнен 10 раз.

• В циклах SAS MACRO можно использовать макроопределения и макропеременные.

67

Symputx• Вы можете создать макропеременную на шаге DATA 15 data _null_;

16 set ecprg1.donate end=_tab;

17 if _tab then call symputx('tabnobs',_N_);

18 run;

NOTE: There were 16 observations read from the data set ECPRG1.DONATE.

...

19 %put &tabnobs;

16

• Вы можете прочитать макропеременную на шаге DATA data donatelast;

lastobs=input(symget('tabnobs'),5.);

put lastobs;

set ecprg1.donate point=lastobs;

output;

stop;

run;

• Symget возвращает значение символьного типа, даже если в макропеременной хранилось число (в этом случае нужно выполнить преобразование типов).

• Ключ “point=“ оператора “set” позволяет прочесть наблюдение с указанным номером во входящем наборе данных, при этом указывается название переменной числового типа (где хранится номер наблюдения)

68

В чем отличия от этой программы:data donatelast;

set ecprg1.donate point=&tabnobs;

output;

stop;

run;

Программа с макросами для транспонирования таблицы*

69* Это - пример для изучения языка программирования, в реальных задачах так лучше не делать

Будем последовательно решать эту задачу, заодно вспомним некоторые особенности шага DATA.Первый шаг – написать программу (или её часть) без макросов и подумать, где нам понадобятся макросы (м.б. для каких-то общих случаев?).

data table;

input c1 c2 c3 c4;

datalines;

1 2 3 4

5 6 7 8

;

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;

Операторы input и datalines позволяет задать данные прямо внутри шага DATA. У нас будет 4 столбца и 2 наблюдения.

Транспонируем первый столбец.Прочитаем первое наблюдение, занесём его в столбец row1 нового набора данныхПотом второеИ занесем его в столбец row2 нового набора данных.Выбросим переменную c1Выведем одно (единственное) наблюдениеЯвно остановим шаг DATA (не обязательно).Здесь макросов нет, но есть повторяющийся кусок кода.

• Чтобы заменить повторяющиеся части кода на макроопределение

нам нужно знать кол-во наблюдений в исходной таблице (или кол-во

столбцов в транспонированной)data _null_;

set table end=_tab;

if _tab then call symputx('tabnobs',_N_);

run;

%put &tabnobs;

• Макропеременная определ. до шага DATA, где используется!

• Теперь можно создать макроопределение:%macro readall;

%do i=1 %to &tabnobs;

_no= &i;

set table(keep=c1) point=_no;

row&i = c1;

%end;

%mend;

data transposed2;

%readall

drop c1;

output;

stop;

run;

70

Программа с макросами для транспонирования таблицы

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;

%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;

%doallcols

stop;

run;

71

Программа с макросами для транспонирования таблицыКак будет работать программа (шаг DATA) после компиляции макросов?Мы 4 раза вызываем макрос readallj, читающий данные из одной заданной колонки исходной таблицы в новое наблюдение для транспонированной таблицы.В какую программу «развернутся» эти два макроопределения? Это можно реконструировать из log:

1 data transposed2;

2 _no= 1;

3 set table(keep=c1) point=_no;

4 row1 = c1;

5 _no= 2;

6 set table(keep=c1) point=_no;

7 row2 = c1;

8 drop c1;

9 output;

10 _no= 1;

11 set table(keep=c2) point=_no;

12 row1 = c2;

13 _no= 2;

14 set table(keep=c2) point=_no;

15 row2 = c2;

16 drop c2;

17 output;

18 _no= 1;

19 set table(keep=c3) point=_no;

20 row1 = c3;

21 _no= 2;

22 set table(keep=c3) point=_no;

23 row2 = c3;

24 drop c3;

25 output;

26 _no= 1;

27 set table(keep=c4) point=_no;

28 row1 = c4;

29 _no= 2;

30 set table(keep=c4) point=_no;

31 row2 = c4;

32 drop c4;

33 output;

34 stop;

35 run;

Особенности макропроцессораСоздание 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 are written out to disk.

72

,сек

Число макропеременных

%include (не работает в on-demand)• Вы можете “подставлять” в сеанс файлы с кодом SAS, и выполнять этот

код. Условие – чтобы файловая система с подставляемыми файлами находилась на том же сервере, где установлен SAS.

%include 'c:/workshop/myprogram.sas';

• Чтобы отлаживать этот оператор на разных уровнях вложенности, есть специальная опция:

%INCLUDE 'c:/workshop/myprogram.sas’ /SOURCE2;

Если эта опция включена, в log появляется код, который подставляется из указанного файла и выполняется.

73

Пользовательские процедуры (FCMP)• Вы можете создавать собственные функции и подпрограммы (call

routines). Их можно использовать в разных шагах 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;

function myfactor(x);

if (x=1) then return (1);

else return (x*myfactor(x-1));

endsub;

quit;

options cmplib=work.fun1;

data test;

n=14;

call plus1(n);

f15=myfactor(n);

f15a=fact(n);

run; 75

Work.fun1 – это название набора данных, куда будут записаны (в специальной форме) функция и подпрограммаПодпрограмма plus1 (один входной аргумент числового типа, Тот же аргумент будет возвращен из подпрограммы –явно указываем с помощью outargs)endsub; после каждой функции/подпрограммы

Напишем свою функцию, вычисляющую факториал.Функция принимает и возвращает число.Return () – инструкция, которая возвращает результат и выходит из функции.

Опция сmplib – где (и в каком порядке) будет производиться поиск пользовательских функций

После вызова call, n=15

Fact = это встроенная функция.

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;

76

Пример 2 (Mandelbrot set plot)*

* From wikipedia.

Просмотр своих функций и их отладка

• Просмотр кода функции (если он не зашифрован)options cmplib=work.fun1;

proc fcmp

outlib=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;

77

Можно вызывать функции прямо из proc fcmp

Процедура SQL• В SAS можно управлять структурой наборов данных с помощью языка

запроса SQL.

• SQL и шаг DATA дополняют друг друга. Подумайте, чем можно проще и эффективнее решать вашу задачу.

• Справка: SAS® 9.3 SQL Procedure User's Guide

• Совместимость: PROC SQL follows most of the guidelines set by the American National

Standards Institute (ANSI) in its implementation of SQL. However, it is not fully compliant with the current ANSI standard for SQL. The SQL research project at SAS has focused primarily on the expressive power of SQL as a query language. Consequently, some of the database features of SQL 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 as

select t1.order_id, t1.customer_id, t1.order_type

from ecsql1.qtr1_2007 as t1

where t1.order_type=2;

quit;

Избранные опции к proc sql:proc sql outobs=10;

WARNING: Statement terminated early due to OUTOBS=10 option.

proc sql inobs=10;

19 select * 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-11

The 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 t2

where t1.customer_id = t2.customer_id;

quit;

proc sql;

select * from ecsql1.qtr1_2007 as t1 join ecsql1.customer as t2

on t1.customer_id = t2.customer_id;

quit;

• «По вертикали», причем в новой таблице будут все переменные из входящих таблиц (независимо от того, есть ли они сразу в обеих таблицах)

proc sql;

create table qtr12 as

select * from ecsql1.qtr1_2007

outer union corr

select * from ecsql1.qtr2_2007

;

quit;

80См. Combining Queries with Set Operators

Использование функций 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 from

ecsql1.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_fact

group 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_fact

group by order_type

having 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 ratio

from ecsql1.order_fact

group 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 maxsalary

from ecsql1.sales

group by gender) as t2

where t1.gender=t2.gender and t1.salary = t2.maxsalary;

quit;

• SAS SQL:proc sql;

select gender, salary,

max(salary) as ms

from ecsql1.sales

group by gender

having ms=salary;

quit;

83

proc sql;

select gender, salary

from ecsql1.sales

group by gender

having salary = max(salary);

quit;

NOTE: The query requires remerging summary statistics back with the original

data.

Использование макропеременных• С точки зрения макропроцессора, Proc SQL – обычная процедура, поэтому

подстановка макропеременных происходит без проблем:%let stat=min;

proc sql;

select * from ecsql1.sales

group by gender

having salary=&stat.(salary);

quit;

• В proc sql вы можете создавать макропеременные:proc sql;

select avg(salary) into :macro_sal

from ecsql1.sales;

quit;

%put macro_sal=&macro_sal;

• И несколько макропеременных (много трюков, см. справку по INTO Clause):proc sql;

select avg(salary),gender into :macro_sal1-:macro_sal2,:macro_gen1-:macro_gen2

from ecsql1.sales

group by gender;

quit;

%put macro_sal=&macro_sal1 macro_gen=&macro_gen1;

%put macro_sal=&macro_sal2 macro_gen=&macro_gen2;

84

Использование макроопределенийoptions mprint mlogic symbolgen;

%MACRO QTR12;

proc sql;

%do i=1 %to 2;

select * from ecsql1.qtr&i._2007;

%end;

quit;

%MEND;

%QTR12

MLOGIC(QTR12): Beginning execution.

MPRINT(QTR12): proc sql;

MLOGIC(QTR12): %DO loop beginning; index variable I; start value is 1; stop value is 2; by

value is 1.

SYMBOLGEN: Macro variable I resolves to 1

MPRINT(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 2

MPRINT(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 time 0.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.vcolumn

proc print data=sashelp.vcolumn;

where libname="WORK";

run;

87