Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Статистика в SPSS: за пределами кнопочного интерфейса. Выпуск 22


В рассылке используются материалы веб-сайта www.spsstools.ru

Содержание выпуска

Макросы. Начальные сведения

Новое на сайте www.spsstools.ru


Здравствуйте, уважаемые подписчики!

Макросы. Начальные сведения

Думаю, многие из вас знают о возможности оформлять синтаксис SPSS в так называемые макропроцедуры, или макросы. Макросы действительно подобны процедурам или функциям в языках структурного программирования. Они сочетают в себе заданную последовательность инструкций, к которым можно обращаться одной командой из любой части программы. Причём при обращении можно передавать аргументы, что делает макросы не просто инструментом структурирования программы, а мощным средством реализации алгоритмов.

В полезности макросов при программировании в SPSS убеждать кого-либо излишне. Достаточно обратить внимание читателя на то, что львиная доля примеров синтаксиса в "Коллекции Raynald'а" составлена с использованием макропроцедур. До сих пор я избегал в рассылке использования макросов, но не потому, что считаю их чересчур сложными, а потому, что овладение макросами - принципиально важный шаг в программировании в SPSS, требующий какого-то минимума вводных комментариев. Сегодня - именно такой, вводный выпуск рассылки.

Как пишет Рейналь Левек в своей книге SPSS Programming and Data Management, макросы обычно появляются в программе, если вам требуется, например:

- выполнить один и тот же анализ (последовательность действий) на многих переменных или нескольких файлах данных;

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

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

Когда мы будем разбирать примеры синтаксиса с использованием макросов, вы увидите, что под эту широкую классификацию попадает множество специальных задач, которые с макросами решаются быстрее и проще, чем без них.

В равной степени начинающим и опытным пользователям я бы рекомендовал ознакомиться с уже переведёнными разделами сайта www.spsstools.ru по макросам. Макроязык - достаточно объёмный технический вопрос и получить целостное представление о нём из одного выпуска рассылки невозможно.

Поэтому... На странице Мастер-класс по макросам вы найдёте важнейшие сведения о макросах (назначение, общие правила написания, примеры). Непременно обратите внимание на раздел Макрос ? синтаксический анализатор, обработчик строк. Многие особенности и кажущиеся "глюки" в поведении макросов станут понятны и прозрачны.

На странице Отладка макросов, как следует из её названия, собраны несколько ценных советов по выяснению причин "неправильной" работы макрокода.

На странице Макросы собраны примеры макросов, которые, в основном, ценны изяществом написания самих макросов. Не столь важно, какие именно практические задачи решают эти примеры. Вы можете использовать идеи и готовые конструкции отсюда для написания собственных макросов независимо от их назначения. Множество макросов "в деле" можно увидеть непосредственно на странице примеров синтаксиса: Синтаксис.

Читающим по-английски я могу рекомендовать уже упоминавшуюся выше книгу Raynald Levesque SPSS Programming and Data Management, а в качестве постоянного справочного материала - официальный справочник по синтаксису SPSS. Описание макрокоманд даётся в разделе DEFINE - !ENDDEFINE.

Указав на дополнительные источники информации, я сфокусируюсь в этом выпуске на простых примерах определения и вызова макросов, а также на способах передачи аргументов. Думаю, что со следующего выпуска это позволит нам начать разбор примеров макросов, содержащихся в "Коллекции".

 

Простейший пример. Пустой макрос. Он ничего не делает. Мы просто знакомимся с принципом его определения. Макрос задаётся внутри команд DEFINE - !ENDDEFINE. С точки зрения синтаксиса, это обычная команда, которая может быть написана и в одну строку. После инструкции DEFINE мы указываем имя макроса, к которому нам потом удобно будет обращаться. В данном случае имя начинается с восклицательного знака. Восклицательный знак - характерный символ при написании макрокоманд, но в имени макроса он вовсе необязателен. Определим вслед за макросом !mac1 макрос mac1, это будет отдельный макрос. Пустые скобки после имени символизируют отсутствие каких-либо аргументов. Когда SPSS получает инструкцию DEFINE с именем определяемого макроса, все последующие инструкции вплоть до команды !ENDDEFINE он интерпретирует как тело макроса. При вызове этого макроса в дальнейшем все инструкции из тела макроса будут исполнены.

Будучи раз определённым, макрос помещается в оперативной памяти до окончания сеанса работы с SPSS. Это значит, что обратиться к нему вы сможете и после того, как откроете другой файл данных, из другого файла синтаксиса и проч. Повторное определение макроса с тем же именем, которое уже имеется в памяти, вызывает переопределение макроса. Пользователь информируется об этом в окне результатов. Выполните дважды команды определения обоих макросов. Вы увидите, как SPSS сообщает о переопределении.

DEFINE !mac1()

!ENDDEFINE.

 

DEFINE mac1()

!ENDDEFINE.

Определение макроса !mac1 можно записать и так:

DEFINE !mac1() !ENDDEFINE.

Наконец, вызвать макрос на исполнение можно простым упоминанием его имени в коде за пределами определения макроса:

!mac1.

 

Макрос-константа. Если мы поместим внутрь макроса "что-то", это "что-то" будет подставляться каждый раз в то место кода, в котором встретится имя макроса. Отсюда - некоторые возможности автоматизации своей работы. Следующий макрос "запоминает" путь к рабочей директории. В дальнейшем это избавляет нас от написания пути целиком:

DEFINE !dp() 'c:\temp\' !ENDDEFINE.

 

GET FILE = 'Employee data.sav'. /* Я полагаю, по умолчанию у вас настроен путь к директории SPSS */.

SAVE OUTFILE = !dp+'mydata.sav'.

Чтобы убедиться в том, что SPSS при исполнении последней строки действительно выполнил желаемую команду "SAVE OUTFILE = 'c:\temp\mydata.sav'.", вставим перед вызовом макроса инструкцию "SET MPRINT=yes." Теперь макрос, перед тем как исполниться, будет "разворачиваться" (expand) у нас на глазах: отличный способ поиска ошибок в программировании.

SET MPRINT=yes.

SAVE OUTFILE = !dp+'mydata.sav'.

Отключить опцию MPRINT можно обратной командой:

SET MPRINT=no.

Разумеется, все эти трюки с MPRINT имеют смысл лишь в том случае, если у вас включена опция отображения в окне результатов командного синтаксиса, а если вы программируете в SPSS, это должно быть сделано (через меню, или командой "SET Printback=On.").

На место 'c:\temp' вы можете подставить какое-либо число, строку, имя переменной и использовать это в коде по своему усмотрению.

 

Макрос-набор команд. Туда, куда можно подставить "любую строку", можно подставить и исполняемый код:

DEFINE !mac2()

GET FILE = 'Employee data.sav'.

DESCRIPTIVES VARIABLES=salbegin salary.

!ENDDEFINE.

Никакой статистики пока не появляется. Мы лишь определили макрос. А теперь исполним его:

!mac2.

А как насчёт того, чтобы в определении одного макроса использовать уже ранее определённые макросы? И это можно:

DEFINE !mac2()

GET FILE = !dp+'mydata.sav'.

DESCRIPTIVES VARIABLES=salbegin salary.

!ENDDEFINE.

 

!mac2.

 

Макрос с параметрами. Возможность передачи в макросы аргументов (параметров) заметно повышает наш практический интерес к макроязыку. Незначительная доработка предыдущего примера даёт нам возможность мгновенно получить статистику по любой переменной из интересующего нас файла данных, какой бы файл ни был открыт в данный момент:

DEFINE !mac2(vars=!CMDEND)

GET FILE = !dp+'mydata.sav'.

DESCRIPTIVES VARIABLES=!vars.

!ENDDEFINE.

 

!mac2 vars=salary prevexp.

!mac2 salary prevexp.

В этом примере у макроса появляется аргумент vars, он определяется в скобках после имени макроса. При вызове всё, что находится после имени макроса и до точки-окончания вызова, понимается программой как значение аргумента vars. Есть некоторые особенности работы с аргументами, к которым надо привыкнуть. Несмотря на то, что мы назвали аргумент vars, в теле самого макроса надо ссылаться на него как на !vars. Хотя аргумент один, он содержит названия двух переменных, разделённых пробелом. Поскольку аргумент единственный и включает в себя всё, что находится до точки-окончания вызова, то нам (и, что самое важное, программе) безразлично, вызывать ли его с указанием на его имя, или без оного (соответственно, первый и второй варианты вызова в примере выше, эквивалентны).

 

Далее сформулируем несколько тезисов:

1. Макрос может принимать несколько аргументов. Второй и последующие аргументы определяются в тех же скобках, что и первый, но после знака "/".

2. Каждый аргумент может содержать одну или несколько самостоятельных "порций" информации (tokens). В примере выше аргумент vars содержал два "токена" - имена двух переменных. При вызове макроса множественные токены разделяются пробелами (как правило) или иными разделяющими знаками (что является темой отдельного разговора). Строка, заключенная в кавычки, является самостоятельным токеном.

3. Похоже, становится ясно, что значениями аргументов/токенов для макросов могут быть числа, имена переменных, текстовые строки, команды и логические выражения, и даже имена макросов.

4. Для разных ситуаций придумано несколько вариантов описания, задания и ссылок на аргументы. Эти варианты различаются ключевыми словами, стоящими в скобках при определении аргументов. Знакомое нам ключевое слово с макросимволом вначале: "!CMDEND" говорит, что значением этого аргумента будет всё, стоящее от конца имени макроса и до последней точки команды (либо от конца значения предыдущего аргумента и до последней точки команды). Рассмотрим правила, задаваемые другими ключевыми словами:

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

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

!CHAREND (символ) - значением аргумента считается всё, что находится в команде вызова макроса от окончания предыдущего аргумента до указанного символа.

Особое слово - !POSITIONAL (часто сокращается до !POS) указывает, что на аргумент мы собираемся ссылаться не по его имени, а по порядку следования его в списке аргументов. В этом случае !POS ставится на место имени аргумента, а затем следует одно из 4 ключевых слов, рассмотренных выше.

5. Кроме этого, можно управлять значениями аргументов по умолчанию, "развёртыванием" аргументов в листинге синтаксиса при вызове макроса и т.д. Эти и многие другие вопросы оставим пока без внимания.

 

Считая, что пример задания аргументов с !CMDEND разобран выше, рассмотрим остальные 3 случая задания:

 

!TOKENS. В макросе присутствуют 2 аргумента с именами а и b. Первый содержит одну порцию информации, второй - две порции. Команды в теле синтаксиса подразумевают, что аргументы должны содержать имена переменных для процедуры сравнения средних. В аргументе a задаётся имя группирующей переменной, а в аргументе b - 2 имени переменных, средние которых сравниваются по подгруппам. Обратите внимание на второй пример вызова макроса !mac3. Поскольку аргумент b принимает лишь две порции информации (два имени), всё, что стоит вслед за этим, интерпретируется как текст, подставляемый в конец тела макроса. Таким образом, мы получаем при вызове дополнительную статистику - таблицу дисперсионного анализа.

DEFINE !mac3(a=!TOKENS(1) /b=!TOKENS(2))

MEANS
TABLES= !b BY !a
/CELLS MEAN COUNT STDDEV .

!ENDDEFINE.

 

!mac3 a=gender b=salary salbegin.

!mac3 a=gender b=salary salbegin /STATISTICS ANOVA.

 

!ENCLOSE. Аналогичный пример мы рассматриваем в случае, когда первый аргумент может содержать произвольное число токенов. Значением аргумента будет считаться всё, что заключено в скобки. Второй аргумент вбирает в себя все оставшиеся значения до конца команды на вызов макроса.

DEFINE !mac4(a=!ENCLOSE('(',')') /b=!CMDEND)

MEANS
TABLES= !b BY !a
/CELLS MEAN COUNT STDDEV .

!ENDDEFINE.

 

!mac4 a=(gender) b=salary salbegin.

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

DEFINE !mac5(!POS=!ENCLOSE('(',')') /!POS=!CMDEND)

CORRELATIONS /VARIABLES=!1 WITH !2.

!ENDDEFINE.

 

!mac5 (jobtime educ) salary salbegin.

...а теперь так:

!mac5 (jobtime educ salary) salbegin.

Вы можете видеть, что к порядковым аргументам мы обращаемся не по имени, а по номеру: !1, !2 и т.д.

Кого-то восхитит возможность использования "собирательного" имени аргументов: !*. Такой макрос, независимо от положения скобок, построит матрицу корреляций каждой переменной с каждой:

DEFINE !mac5(!POS=!ENCLOSE('(',')') /!POS=!CMDEND)

CORRELATIONS /VARIABLES=!* WITH !*.

!ENDDEFINE.

 

!mac5 (jobtime educ) salary salbegin.

 

!CHAREND. Вариант, рассмотренный выше (со скобками) может быть переписан иначе с использованием ключевого слова CHAREND:

DEFINE !mac6(!POS=!CHAREND('/') /!POS=!CMDEND)

CORRELATIONS /VARIABLES=!1 WITH !2.

!ENDDEFINE.

 

!mac6 jobtime educ /salary salbegin.

 

В заключение выпуска рассмотрим чуть более сложный пример. Данный макрос генерирует полный факторный план для трёхфакторного эксперимента. Число и наименования уровней каждого фактора задаётся пользователем при вызове макроса. Поскольку токенами аргументов считается всё до условных символов или окончания команды вызова, число токенов может быть произвольным.

Здесь мы используем, в принципе, знакомую подписчикам команду определения файлов INPUT PROGRAM со вложенными циклами и инструкциями LEAVE (для чего нужна? Уберите её и сравните результаты). А кроме этого, используем специальные макроциклы !DO .. !IN ... !DOEND (именно так, с восклицательными знаками). В рамках этих циклов "на лету" определяются дополнительные макропеременные !f1, !f2, !f3, пробегающие значения всех токенов из своего аргумента. Таким образом мы осуществляем полный перебор.

DEFINE !mac7(!POS=!CHAREND('/') /!POS=!CHAREND('/') /!POS=!CMDEND)

INPUT PROGRAM.

- STRING f1 f2 f3 (A2).

- !DO !f1 !IN (!1)

- COMPUTE f1=!QUOTE(!f1).

- !DO !f2 !IN (!2)

- LEAVE f1.

- COMPUTE f2=!QUOTE(!f2).

- !DO !f3 !IN (!3)

- LEAVE f1 f2.

- COMPUTE f3=!QUOTE(!f3).

- END CASE.

- !DOEND.

- !DOEND.

- !DOEND.

- END FILE.

END INPUT PROGRAM.

EXECUTE.

!ENDDEFINE.

 

!mac7 A B C D F/ X Y Z/ N1 N2 N3.

 

Всего доброго, и с началом лета вас!

 

Ведущий рассылки,

Балабанов Антон

Новое на сайте www.spsstools.ru

Переведены и добавлены примеры синтаксиса:

Масштабирование графика.SPS

Одна ящичковая диаграмма на каждую категорию переменной.SPS

Синтаксис для анализа тестов.SPS

 

© См. www.spsstools.ru, 2005-2006


В избранное