Мастер-класс по макросам
- Основы
- Макросы и точки — символы окончания команд
- Макрос — синтаксический анализатор, обработчик строк
- Полностью прокомментированный пример макроса (n независимых выборок объёма m)
- Замена символов в нескольких строковых переменных
- Меняем формат у многих переменных
- Версия 1: изменяем формат переменной (имя остаётся прежним) со строковой на строковую, с числа на строку, со строки на число
- Версия 2: то же самое, но с 5-10-20 переменными за раз.
- Версия 3: то же самое, но со ВСЕМИ строковыми или числовыми переменными, которые находятся между двумя указанными переменными в файле.
- Арифметические действия с макропеременными (для опытных пользователей)
- Ещё один тщательно прокомментированный макрос(создаёт столбцовые диаграммы, «заглушая» категории с небольшой частотой)
Дайте знать если, по вашему мнению, здесь стоит разместить ещё что-нибудь, или какой-то раздел раскрыт недостаточно ясно.
Основы
Чтобы приступать к изучению макросов, вы должны иметь понятие о синтаксисе SPSS.
Идея макроса аналогично понятию функции. Вы определяете его, а затем — вызываете. Макрос достаточно определить один раз за сессию работы с SPSS. Это делается серией команд, заключённых между инструкциями DEFINE и !ENDDEFINE. Сессия начинается, когда вы запускаете SPSS и заканчивается когда вы закрываете это приложение. Таким образом, даже если вы работаете в рамках одной сессии с разными файлами данных, разными окнами выдачи и синтаксиса, макрос всё ещё определён в оперативной памяти и может быть вызван без переопределения. Однако, если вы закрыли SPSS и запустили его снова, макрос потребуется определять заново. Это несложно сделать, если он сохранён у вас в файле синтаксиса.
Определения макроса могут быть размещены в любой части файла синтаксиса, поскольку они получают «приоритет» на обработку, т.е. команды определения макроса обрабатываются перед тем, как будут обработаны все остальные команды.
Вот очень пример очень простого макроса:
DEFINE !stats (myvars=!CMDEND)
FREQUENCY VARIABLES= !myvars /ORDER= ANALYSIS.
!ENDDEFINE.
Вы можете вызвать этот макрос на выполнение следующей командой:
!stats myvars=age sex status.
Здесь этом age sex и status – имена существующих в файле данных переменных, для которых вы хотите получить таблицы частот.
Инструкция DEFINE (первая строка определения макроса) задаёт имя макроса (в данном случае – !stats); имя не может быть длиннее 8 символов. Эта инструкция также говорит, что при вызове макроса вы должны указать переменные, представляющие для вас интерес в качестве значения аргумента myvars. Это сделано при вызове макроса: «myvars=age sex status».
Важно, что хотя аргумент определён как «myvars» в инструкции DEFINE, при обращении к нему внутри макроса следует пользоваться именем «!myvars».
Как только макрос определён, строка
!stats myvars=age sex status.
имеет тот же эффект, что и строка
FREQUENCY VARIABLES = age sex status /ORDER = ANALYSIS.
Вы можете сказать «Ну и в чём здесь преимущество?» Оно в том, что макросы могут делать куда более сложные вещи, чем построение частотных распределений. Такие вещи, которые без макросов потребовали бы тысячи строк кода и долгие часы работы. При использовании макроса вам достаточно одной строки, чтобы вызвать выполнение сотни строк кода. Причём параметры (аргументы) макроса можно задавать каждый раз разные.
На этом сайте находится около 140 различных макросов. Их проще всего искать, указывая ключевое слово !ENDDEFINE в строке поиска в окошке с левой стороны окна каждой страницы этого сайта.
Макросы и точки-символы окончания команд
Точки как символы окончания команды должны заканчивать каждую команду в файле синтаксиса при работе в интерактивном режиме (через окно синтаксиса). Точки не нужны при вызове макросов через инструкцию INCLUDE или при вызове их в автоматическом режиме (Production Facility). Мой совет – всегда использовать точки при написании команд синтаксиса.
Однако, последовательность макрокоманд, заключённых между "DEFINE" и "!ENDDEFINE.", расценивается как одна команда синтаксиса. Естественно, она заканчивается точкой после !ENDDEFINE. Нет необходимости ставить точку после каждой макрокоманды. В некоторых случаях постановка точки даже приведёт к возникновению «глюка» (см., например, этот макрос). Иногда это способно «сбить с толку» процессор SPSS. Отсюда — общее правило: не ставить точки после макрокоманд внутри макроса. Например, команда !DO !var=1 !TO !nbfiles не нуждается в постановке точки после неё.
Разумеется, внутри макроса могут встречаться обычные команды синтаксиса, которые необходимо заканчивать точкой, например:
SAVE OUTFILE=!QUOTE(!CONCAT("c:\Temp\new file ",!var,".sav")).
Макрос — синтаксический анализатор, обработчик строк
Основная вещь, которую надо понять о том, как работают макросы, это та, что макрос является простым синтаксическим анализатором («string parser»). Макрос выполняется целиком ещё до того, как начинается обработка первого наблюдения. Затем начинается видимая нам обработка синтаксиса, который сгенерировал макрос при своём исполнении. Иными словами, когда мы запускаем макрос, SPSS подставляет на место аргументов со значками «!» переданные параметры и генерирует код (синтаксис) (в английских текстах можно встреить термин macro's expansion, характеризующий этот процесс), который затем, после того как «выполнился» весь макрос, начинает исполняться, т.е. SPSS начинает непосредственную обработку данных.
Например, следующий макрос
DEFINE !example (var=!CMDEND)
!DO !vardo !IN (!var)
DESCRIPTIVES !vardo.
!DOEND
!ENDDEFINE.
будучи запущенным командой
!example var=age ss.
сначала «превращается» в синтаксис
DESCRIPTIVES age.
DESCRIPTIVES ss.
который потом выполняется.
Если мы это поняли, становится ясно, что макрокоманда команда вроде
!IF (!age) !GT age !THEN … !IFEND
лишена смысла. Лишена смысла, поскольку значения переменной age, как правило, варьируются от наблюдения к наблюдению. Но поскольку макрос «развёртывает» свой код ещё до начала обработки данных, то обработчику не ясно, выполнено условие !IF, или нет.
С другой стороны, такая команда в макросе приемлема:
COMPUTE years2=65 - !age.
ведь в ходе генерации кода, макрос подставляет на место !age имя переданной в качестве аргумента переменной (либо присваивает !age некоторое имя инструкцией !LET). Здесь такая замена никак не обусловлена значением конкретного наблюдения переменной, которое неизвестно до начала выполнения синтаксиса.
Полностью прокомментированный пример макроса
Я привожу макрос, а затем описываю назначение каждой строчки. (NB!Здесь строки пронумерованы лишь для удобства ссылок на них. Настоящий макрос номеров строк не содержит)
Как получить n независимых выборок объёма m из одного и того же файла?
* Ответ размещён в SPSSX-L rlevesque@videotron.ca 14.04.2001.
1 PRESERVE.
2 SET MPRINT=no.
3 *///////////////////////////////.
4 DEFINE !getsamp (nbcases=!TOKENS(1) /nbfiles=!TOKENS(1))
5 !DO !var=1 !TO !nbfiles
6 GET FILE='C:\Program Files\SPSS\GSS93 subset.sav'.
7 COMPUTE draw=UNIFORM(1).
8 COMPUTE dummy=1.
9 RANK VARIABLES=draw BY dummy /RANK INTO rank1.
10 SELECT IF rank1 LE !nbcases.
11 SAVE OUTFILE=!QUOTE(!CONCAT("c:\Temp\new file ",!var,".sav")).
12 !DOEND
13 !ENDDEFINE.
14 *///////////////////////////////.
15 *Следующая строка запускает весь процесс.
16 SET MPRINT=yes.
17 !getsamp nbcases=300 nbfiles=4.
18 RESTORE.
Определение макроса начинается с четвёртой строки и заканчивается строкой 13. Макрос вызывается в 17-й строке. Ещё раз обращаю внимание, что номера строк даны лишь для удобства комментария. Если вы хотите запустить этот макрос, номера строк следует удалить и проследить, что все команды начинаются с первой колонки, а все подкоманды начинаются с последующих колонок. Последнее необходимо для вызова макроса с помощью инструкции INCLUDE из другого файла синтаксиса.
| Комментарии к каждой строке |
Обратите внимание, что если целью извлечения выборок было подсчитать средние, стандартные отклонения или какие-то другие статистики по каждой выборке и затем сопоставить их, этот макрос мог бы быть переписан таким образом, что эти статистики записались бы в качестве наблюдений в один файл, т.е. макрос бы вернул не 4, 100 или 1000 файлов, а 1 файл с результатами. |
Замена символов в нескольких строковых переменных
В упражнениях на синтаксис по преобразованию строк для замены точек на запятые был использован следующий синтаксис:
LOOP IF INDEX(name2,".")>0.
- COMPUTE SUBSTR(name2,INDEX(name2,"."),1)=",".
END LOOP.
Использование такого метода для 100 переменных потребует 300 строк кода! Рассмотрим несколько похожих ситуаций и подыщем для каждой подходящее решение.
- Пример 1
Допустим, что строковые переменные, нуждающиеся в замене символов, имеют связанные имена (например, var1, var2, var3, …, или любые другие символы вместо var), но необязательно следуют одна за другой в файле. - Пример 2
Переменные имеют несвязанные имена, но расположены последовательно в файле данных (например, vara, name, address, …, product – следуют в файле одна за другой). - Пример 3
Предположим, что переменные имеют несвязанные имена и расположены непоследовательно в файле данных, однако все строковые переменные между первой из указанных и последней из указанных должны быть обработаны. - Пример 4
Условия — как в предыдущем примере, кроме этого некоторые из строковых переменных не должны подвергнуться обработке.
Файл [English]Замена символов во многих строковых переменных.SPS включает все 4 примера, они разобраны ниже.
Замена символов: пример 1
Строковые переменные, нуждающиеся в замене символов, имеют связанные имена (например, var1, var2, var3, …, или любые другие символы вместо var), но необязательно следуют одна за другой в файле.
Сгенерируем данные.
INPUT PROGRAM.
LOOP id=1 TO 3.
VECTOR var(100A8).
LOOP cnt=1 TO 100.
COMPUTE var(cnt)="txt.abc".
END LOOP.
END CASE.
END LOOP.
END FILE.
END INPUT PROGRAM.
EXECUTE.
Следующий метод не будет работать, поскольку команда SUBSTR требует имени реальной переменной. Элемент вектора v(cnt) она как имя переменной не распознаёт.
VECTOR v=var1 TO var100.
LOOP cnt=1 TO 100.
- LOOP IF INDEX(v(cnt),".")>0.
- COMPUTE SUBSTR(v(cnt),INDEX(v(cnt),"."),1)=",".
- END LOOP.
END LOOP.
EXECUTE.
Тут поможет использование DO REPEAT.
DO REPEAT v=var1 TO var100.
LOOP IF INDEX(v,".")>0.
- COMPUTE SUBSTR(v,INDEX(v,"."),1)=",".
END LOOP.
END REPEAT.
EXECUTE.
Использование следующего макроса также возможно.
SET MPRINT=no.
*/////////////////////.
DEFINE !replace(vname=!TOKENS(1)
/nbvars=!TOKENS(1)
/oldchar=!TOKENS(1)
/newchar=!TOKENS(1))
!DO !cnt=1 !TO !nbvars
LOOP IF INDEX(!CONCAT(!vname,!cnt),!oldchar)>0.
- COMPUTE SUBSTR(!CONCAT(!vname,!cnt),INDEX(!CONCAT(!vname,!cnt),!oldchar),1)=!newchar.
END LOOP.
!DOEND
EXECUTE.
!ENDDEFINE.
*/////////////////////.
SET MPRINT=yes.
Вызываем макрос.
!replace vname=var nbvars=100 oldchar='.' newchar=','.
В данном случае решение с DO REPEAT оказывается более простым, чем макрос, но стоит помнить, что в цикле DO REPEAT невозможно использование процедур с пересылкой аргументов, т.е. решение через макрос оказывается более общим.
Замена символов: пример 2
Переменные имеют несвязанные имена, но расположены последовательно в файле данных (например, vara, name, address, …, product – следуют в файле одна за другой).
Очень удобно было бы в данном случае просто указать макросу имена первой и последней переменных.
Один из «избранных» макросов (см. «Define list of variables between two variables.SPS») может нам в данном случае помочь.
Сгенерируем данные.
INPUT PROGRAM.
LOOP id=1 TO 3.
STRING strone text34 str2 beta gamma alpha (A8).
DO REPEAT var=strone text34 str2 beta gamma alpha.
COMPUTE var="txt.ab.c".
END REPEAT PRINT.
END LOOP.
END CASE.
END FILE.
END INPUT PROGRAM.
EXECUTE.
SAVE OUTFILE='c:\temp\testdata.sav'.
Допустим, мы хотим обработать все переменные между text34 и gamma включительно. Данное решение предполагает, что у нас на самом деле есть сотни переменных между этими двумя и нам не очень удобно перечислять их все при вызове макроса.
Обратите внимание, что данное решение может быть использовано и когда вам нужно обработать все переменные, начиная с некоторой, но вы по каким-то причинам не можете указать имя последней переменной. Тогда вы просто создаёте ещё одну строковую переменную (она размещается в конце файла) и указываете её имя в качестве последней переменной.
NB!: когда вы разместите вспомогательный макрос в своей папке макросов, не забудьте удалить определение данных и вызов этого макроса, оставьте только его определение.
INCLUDE FILE='c:\Program Files\SPSS\macros\DefineListOfVariablesBetweenTwoVariables.SPS'.
Вызовем макрос, который даст нам список всех переменных, расположенных между двумя указанными нами.
!DefList var1=text34 var2=gamma fname='c:\temp\testdata.sav'.
Вызов макроса на замену символов.
SET MPRINT=yes.
!rep_chr oldchar='.' newchar=',' vnames=!list1.
Определение макроса !rep_chr дано в примере 4 ниже.
Замена символов: пример 3
Предположим, что переменные имеют несвязанные имена и расположены непоследовательно в файле данных, однако все строковые переменные между первой из указанных и последней из указанных должны быть обработаны.
Используем решение, аналогичное примеру 2.
Сгенерируем файл данных.
INPUT PROGRAM.
LOOP id=1 TO 3.
STRING strone text34 str2 beta gamma (A8).
DO REPEAT var=strone text34 str2 beta gamma.
COMPUTE var="txt.ab.c".
END REPEAT PRINT.
END LOOP.
END CASE.
END FILE.
END INPUT PROGRAM.
EXECUTE.
Вставим числовую переменную перед последней строковой.
COMPUTE numvar=2.
STRING alpha(A8).
COMPUTE alpha="txt.a.b.c".
SAVE OUTFILE='c:\temp\testdata.sav'.
INCLUDE FILE='c:\Program Files\SPSS\macros\DefineListOfVariablesBetweenTwoVariables.SPS'.
Вызываем вспомогательный макрос, возвращающий список переменных, расположенных между двумя указанными.
!DefList var1=text34 var2=alpha fname='c:\temp\testdata.sav'.
Вызываем макрос на замену.
SET MPRINT=yes.
!rep_chr oldchar='.' newchar=',' vnames=!list1.
Обратите внимание, что будут возникать «ошибки» когда макрос попытается модифицировать числовые переменные (в частности, переменную numvar). Для них преобразования не пройдут. Однако на эти ошибки можно не обращать внимание, т.к. числовые переменные мы и так трогать не хотели.
Определение макроса !rep_chr дано в примере 4 ниже.
Замена символов: пример 4
Условия — как в предыдущем примере, кроме этого некоторые из строковых переменных не должны подвергнуться обработке.
В данном случае имена тех переменных, которые должны быть обработаны, должны в явном виде быть заданы в макросе.
INPUT PROGRAM.
LOOP id=1 TO 3.
STRING strone text34 str2 name alpha (A8).
DO REPEAT var=strone text34 str2 name alpha .
COMPUTE var="txt.ab.c".
END REPEAT PRINT.
END LOOP.
END CASE.
END FILE.
END INPUT PROGRAM.
EXECUTE.
Определяем следующий макрос.
SET MPRINT=no.
*/////////////////////.
DEFINE !rep_chr(oldchar=!TOKENS(1)
/newchar=!TOKENS(1)
/vnames=!CMDEND)
!DO !vname !IN (!vnames)
LOOP IF INDEX(!vname,!oldchar)>0.
+ COMPUTE SUBSTR(!vname,INDEX(!vname,!oldchar),1)=!newchar.
END LOOP.
!DOEND
EXECUTE.
!ENDDEFINE.
*/////////////////////.
Допустим, что мы хотим заменить точки на запятые в переменных text34, str2 и alpha. При этом они не последовательно расположены в файле данных.
Вызываем макрос следующим образом.
SET MPRINT=yes.
!rep_chr oldchar='.' newchar=',' vnames=text34 str2 alpha.
Разумеется, если нужно заменить символы «a» на «b», макрос следует вызвать в следующем виде.
!rep_chr oldchar='a' newchar='b' vnames=text34 str2 alpha.
Меняем формат у многих переменных
Этот макрос полезен, когда вам нужно преобразовать…
- строки одного типа в строки другого типа (ss);
- числовые переменные в строчные (ns);
- строковую переменную в числовую (sn),
- cохраняя при этом исходное имя переменной.
* rlevesque@videotron.ca 23.05.2001.
*/////////////////////.
DEFINE !convert (vname=!TOKENS(1)
/nformat=!TOKENS(1)
/type=!TOKENS(1))
/* где vname= имя переменной, у которой меняем формат*/.
* nformat = новый формат.
* type (характер изменения) = ss (если строку меняем на строку), ns или sn, где n=числовая и s=строковая.
!IF (!type='ss') !THEN STRING temp1234(!nformat).
COMPUTE temp1234=!vname.
!IFEND
!IF (!type='ns') !THEN STRING temp1234(!nformat).
COMPUTE temp1234=LTRIM(STRING(!vname,F18.0)).
!IFEND !IF (!type='sn') !THEN COMPUTE temp1234=NUMBER(!vname,F18.0).
FORMAT temp1234(!nformat).
!IFEND
MATCH FILES FILE=* /DROP=!vname.
RENAME VARIABLE (temp1234=!vname).
!ENDDEFINE.
*/////////////////////.
* Генерируем данные, чтобы продемонстрировать работу макроса.
DATA LIST LIST /var1(A8), var2(A8), var3(F8.0).
BEGIN DATA
abcdefg 254 235
adadad 128 265
END DATA.
LIST.
Пример 1.
!convert vname=var1 nformat=A5 type=ss.
*Эта команда конвертирует переменную var1 из строкового формата A8 в строковый же формат A5.
Пример 2.
!convert vname=var2 nformat=F8.2 type=sn.
*Эта команда конвертирует переменную var2 из строкового формата A8 в числовой формат F8.2.
* (Разумеется, если в строковой переменной содержатся строки, которые не могут быть интерпретированы как числа, соответствующее значение в числовой переменной будет пропущено).
Пример 3.
!convert vname=var3 nformat=A8 type=ns.
*Эта команда конвертирует переменную var3 из числового формата F8.2 в строковый формат A8.
**************************************.
Версия 2 предыдущего макроса (обобщение).
Допустим, нам нужно поменять формат у нескольких переменных (5—10—20) с одним и тем же преобразованием формата (ss, sn или ns). Мы сейчас изменим предыдущий макрос так, чтобы он за один вызов мог преобразовать все эти переменные.
SET MPRINT=yes.
*/////////////////////.
DEFINE !conver2 (type=!TOKENS(1)
/cformat=!TOKENS(1)
/nformat=!TOKENS(1)
/vnames=!CMDEND)
/* где…
* type = тип преобразования (см. предыдущий случай).
* cformat = предыдущий формат (требуется лишь когда type=ns чтобы точнее преобразовать числа в строки без лишних нулей после запятой и т.д.).
* nformat = новый формат.
* vnames= список имён переменных для замены формата.
!DO !vname !IN (!vnames)
!IF (!type='ss') !THEN STRING temp1234(!nformat).
COMPUTE temp1234=!vname.
!IFEND
!IF (!type='ns') !THEN STRING temp1234(!nformat).
COMPUTE temp1234=LTRIM(STRING(!vname,!cformat)).
!IFEND
!IF (!type='sn') !THEN COMPUTE temp1234=NUMBER(!vname,!nformat).
FORMAT temp1234(!nformat).
!IFEND
MATCH FILES FILE=* /DROP=!vname.
RENAME VARIABLE (temp1234=!vname).
!DOEND
!ENDDEFINE.
*/////////////////////.
* Проверяем макрос (используем 4 переменных вместо нескольких десятков).
DATA LIST LIST /var1(A8) vnum2(A8) varx(A8) vary(A8).
BEGIN DATA
1235.23 254.13 235.00 6532.20
53261.32 128.09 265.85 2591.99
END DATA.
LIST.
Изменяем формат так, чтобы в результирующей числовой переменной было 3 знака после запятой.
!conver2 type=sn nformat=F8.3 vnames=var1 vnum2 varx vary.
Вот листинг работы макроса из окна результатов. Обратите внимание, что это своего рода «отладка» — вместо макропеременных, имена которых начинаются с «!», подставлены значения конкретных переменных, имена которых были переданы в качестве аргументов — А.Б.
199 M>
200 M> COMPUTE TEMP1234=NUMBER( var1 , F8.3 ).
201 M> FORMAT TEMP1234( F8.3 ).
202 M>
203 M> MATCH FILES FILE=* /DROP= var1.
204 M> RENAME VARIABLE (TEMP1234= var1 ).
205 M>
206 M>
207 M> COMPUTE TEMP1234=NUMBER( vnum2 , F8.3 ).
208 M> FORMAT TEMP1234( F8.3 ).
209 M>
210 M> MATCH FILES FILE=* /DROP= vnum2.
211 M> RENAME VARIABLE (TEMP1234= vnum2 ).
212 M>
213 M>
214 M> COMPUTE TEMP1234=NUMBER( varx , F8.3 ).
215 M> FORMAT TEMP1234( F8.3 ).
216 M>
217 M> MATCH FILES FILE=* /DROP= varx.
218 M> RENAME VARIABLE (TEMP1234= varx ).
219 M>
220 M>
221 M> COMPUTE TEMP1234=NUMBER( vary , F8.3 ).
222 M> FORMAT TEMP1234( F8.3 ).
223 M>
224 M> MATCH FILES FILE=* /DROP= vary.
225 M> RENAME VARIABLE (TEMP1234= vary ).
226 M> .
227 M>
Конвертируем результат обратно в строки (но лишь с одним знаком после запятой).
!conver2 type=ns cformat=F8.1 nformat=A8 vnames=var1 vnum2 varx vary.
Вот листинг работы макроса для этого вызова.
233 M>
234 M> STRING TEMP1234( A8 ).
235 M> COMPUTE TEMP1234=LTRIM(STRING( var1 , F8.1 )).
236 M>
237 M>
238 M> MATCH FILES FILE=* /DROP= var1.
239 M> RENAME VARIABLE (TEMP1234= var1 ).
240 M>
241 M> STRING TEMP1234( A8 ).
242 M> COMPUTE TEMP1234=LTRIM(STRING( vnum2 , F8.1)).
243 M>
244 M>
245 M> MATCH FILES FILE=* /DROP= vnum2.
246 M> RENAME VARIABLE (TEMP1234= vnum2 ).
247 M>
248 M> STRING TEMP1234( A8 ).
249 M> COMPUTE TEMP1234=LTRIM(STRING( varx , F8.1 )).
250 M>
251 M>
252 M> MATCH FILES FILE=* /DROP= varx.
253 M> RENAME VARIABLE (TEMP1234= varx ).
254 M>
255 M> STRING TEMP1234( A8 ).
256 M> COMPUTE TEMP1234=LTRIM(STRING( vary , F8.1 )).
257 M>
258 M>
259 M> MATCH FILES FILE=* /DROP= vary.
260 M> RENAME VARIABLE (TEMP1234= vary ).
261 M> .
Версия 3 того же макроса.
Фактически, это то же, что и версия 2, но здесь мы его используем вместе с одним из «Избранных» макросов. Допустим, нам регулярно надо менять формат 600 переменных с одним и тем же типом трансформаций ((ss, sn или ns).
!DEfList var1=g var2=k fname="c:/temp/mydata.sav".
Определение макроса !DefList (определить список переменных) можно найти здесь.
Макрос, приведённый выше, создаёт макропеременную !list1, содержащую список всех переменных в файле c:/temp/mydata.sav между переменными var1 и var2.
Этот список затем используется в качестве аргумента для макроса !conver2:
!conver2 type=ns cformat=F8.1 nformat=A8 vnames=!list1.
Этот вызов макроса конвертирует все переменные между g и k (предполагается, что они числовые) в строки. Имена переменной остаются такими же. Меняется только формат.
NB!: если лишь некоторые переменные между g и k являются числовыми, мы можем использовать макрос !vartype (из той же группы «избранных» макросов) для получения списка только числовых (или только строковых) переменных. С его помощью мы укажем «правильный» список переменных в вызове !conver2.
Арифметика с макропеременными (для опытных пользователей)
Напрямую выполнять арифметические действия с макропеременными нельзя. Допустим, при условии, что есть следующие макрокоманды:
!LET !a=1.
!LET !b=2.
следующая команда недопустима:
!LET !c=!a + !b.
Вот обходной путь получения суммы !a и !b.
!LET !c=!LENGTH(!CONCAT(!BLANK(!a),!BLANK(!b)).
Мы создаём две пустые строки с длинами !a и !b, затем объединяем их и с помощью функции length записываем в !с длину итоговой строки – А.Б.
Не вполне человечный способ… Попробуйте выполнить деление (или вычислить логарифм !b) таким образом!
Допустим, нам требуется, чтобы макропеременная !myvar содержала результат достаточно сложных вычислений, например, ln(1), ln(2) или ln(3). Вообще – любое количество вычислений и любая функция могут быть использованы, эти 3 просто иллюстрируют метод. Обходной маневр заключается в том, что мы сначала вычисляем числовые переменные в файле данных, затем записываем их во вспомогательный макрос, который затем запускаем на выполнение и извлекаем из него значения.
SET MPRINT=yes.
*///////////////////////////////////.
DEFINE !doit(nbval=!TOKENS(1))
INPUT PROGRAM.
LOOP cnt=1 TO !nbval.
COMPUTE myval=LN(cnt).
END CASE.
END LOOP.
END FILE.
END INPUT PROGRAM.
Допустим, мы хотим сохранить 5 знаков после запятой.
FORMAT myval(F8.5).
Запишем значения макропеременной.
DO IF cnt=1.
WRITE OUTFILE='c:\temp\macro var.sps' /"DEFINE !values()"/myval.
ELSE IF cnt<!nbval.
WRITE OUTFILE='c:\temp\macro var.sps' /myval.
ELSE.
WRITE OUTFILE='c:\temp\macro var.sps' /myval /" !ENDDEFINE.".
END IF.
EXECUTE.
Запустим только что созданный синтаксис чтобы поместить в оперативную память его тело (содержащее ни что иное как значения переменной myval).
INCLUDE FILE='c:\temp\macro var.sps'.
EXECUTE.
!ENDDEFINE.
*///////////////////////////////////.
!doit nbval=3.
В следующем макросе переменная !myvar поочерёдно принимает значения ln(1), ln(2) и ln(3).
DEFINE !test()
!LET !cnt=!NULL
!LET !val=!EVAL(!values)
Функция !EVAL записывает в массив !val тело макроса !values.
!DO !myvar !IN (!val)
!LET !cnt=!CONCAT(!cnt,!BLANK(1))
COMPUTE !CONCAT(var,!LENGTH(!cnt))=!myvar.
!DOEND
EXECUTE.
!ENDDEFINE.
!test.
Изменим формат переменной чтобы увидеть все 5 знаков.
FORMAT var1 TO var3 (F8.5).
Вот результат работы (листинг) приведённого выше синтаксиса.
Ещё один тщательно прокомментированный макрос
Этот макрос печатает столбцовые диаграммы, скрывая столбцы, частота для которых составляет не менее, чем n наблюдений.
1 SET MPRINT=no.
2 *////////////////////.
3 DEFINE !chart2 (minnb=!TOKENS(1) /cats=!CMDEND)
4 /* minnb = минимальная частота */.
5 /* cats = имена категориальных переменных, для которых нужны диаграммы */.
6 COMPUTE dummy=1.
7 !DO !cat !IN (!cats)
8 FILTER OFF.
9 * Сортировка необходима для команд Aggregate и Match Files.
10 SORT CASES BY !cat.
11 !LET !fname=!QUOTE(!CONCAT('C:\temp\',!cat,'.SAV'))
12 AGGREGATE
13 /OUTFILE=!fname
14 /PRESORTED
15 /BREAK=!cat
16 /nb = N(dummy).
17 MATCH FILES /FILE=*
18 /TABLE=!fname
19 /BY !cat.
20 FREQUENCY VARIABLES=!cat.
21 LIST.
22 COMPUTE flag=(nb>=!minnb).
23 FILTER BY flag.
24 GRAPH
25 /BAR(SIMPLE)=COUNT BY !cat
26 /MISSING=REPORT.
27 * Удаляем переменную nb.
28 MATCH FILES FILE=* /DROP=nb.
29 !DOEND
30 * Удаляем переменную dummy.
31 MATCH FILES FILE=* /DROP=dummy.
32 !ENDDEFINE.
33 *///////////////////
34 SET MPRINT=yes.
35 !chart2 minnb=5 cats= age prog year.
Определение макроса начинается на 3 строке и заканчивается на 32. Макрос вызывается в 35 строке. Номера строк включены лишь для удобства ссылок на них. Если хотите, чтобы макрос работал, номера строк следует удалить. Надо проследить, что все команды начинаются с первой колонки, а все подкоманды начинаются с последующих колонок. Это необходимо для вызова макроса с помощью инструкции INCLUDE из другого файла синтаксиса.
| Комментарии к каждой строке |
|



