Понимание этого вопроса и ответа может сэкономить для вас много времени. Эти сообщения были помещены в SPSSX-L 2 апреля 1999 года (David Matheson, техническая поддержка SPSS)

Вопрос

Я выполняю различные преобразования данных в SPSS. Очень был удивлён, узнав, что получение корректных результатов может требовать помещения команды EXECUTE между командами преобразований данных. Вот один из моих синтаксисов:

1
2
3
4
5
DATA LIST FILE '/tmp/ret.dat' FIXED /da 1-15 w 19-20 .
COMPUTE RETURN = da-LAG(da).
COMPUTE sv =(w<=1 or w>=5).
SELECT IF (sv=0).
LIST.

Результаты для переменной RETURN в некоторых случаях были некорректны. Корректные результаты были получены, когда между строками 2 (Compute RETURN…) и 4 (SELECT IF…) была помещена команда EXECUTE. Есть какие-то общие правила, устанавливающие регламент использования команды EXECUTE?

Ответ

Правильным в данном примере было бы поместить EXECUTE перед SELECT IF. (В данном конкретном случае помещение EXECUTE между двумя командами COMPUTE тоже бы сработало) Иначе, когда вы считаете RETURN как DA - LAG(DA) для конкретного наблюдения, наблюдение, вначале предшествовавшее текущему наблюдению, может быть уже исключено из файла и LAG(DA) может ссылаться на значение DA не из нужного вам наблюдения.

Для дальнейшей иллюстрации использования команды EXECUTE между командами трансформации, рассмотрим 3 последовательных наблюдения с ID 1, 2 и 3. Предположим, мы хотим сохранить, или убрать наблюдение с ID = 2 в зависимости от результата его сравнения с наблюдением 1. Аналогично нам нужно будет сравнить наблюдение 3 с наблюдением 2 и сохранить или выбросить 3 в результате. Предположим, что наблюдение 2 было выкинуто по результатам сравнения, но наблюдение 3 прошло бы тест в сравнении с наблюдением 2 таким образом, что 3 следовало бы в результате сохранить. Без команды EXECUTE (или другой команды, инициирующей «проход» по всем данным) перед SELECT IF, наблюдение 2 будет оценено и выкинуто перед тем, как будет оценено наблюдение 3. В результате наблюдение 3 будет сравниваться с «предыдущим» наблюдением, которым в данном случае будет наблюдение 1 и будет сохранено или выкинуто уже в результате неверного сравнения. Помещение EXECUTE перед SELECT IF гарантирует наличие всех наблюдений для функции LAG. Но, разумеется, мы можем себе представить и такую процедуру сравнения, при которой последующее наблюдение сравнивается с последним из предыдущих наблюдений, успешно прошедших такое же сравнение. В таком случае мы должны будем убрать EXECUTE, чтобы достичь нужного результата.

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

1
2
3
4
compute seq = $casenum.
select if (mod(seq,5) = 0).
frequencies x.
* функция mod возвращает остаток от деления первого числа на второе.

У вас не будет ни одного наблюдения для построения частотной таблицы. Первому наблюдению будет присвоено значение 1 в переменной seq, поскольку значение системной переменной $casenum для него будет равно 1. (mod(seq,5)=0) вернёт «False» и наблюдение будет удалено. Второе наблюдение теперь стало первым и будет удалено тем же манером (теперь для него $casenum = 1, seq = 1). То же самое случится и с тем наблюдением, которое изначально было пятым, десятым и т.д. А вот следующий синтаксис будет работать:

1
2
3
4
compute seq = $casenum.
execute.
select if (mod(seq,5) = 0).
frequencies x.

Добавление EXECUTE перед SELECT обеспечивает корректность вычисления seq перед тем, как наблюдения начнут удаляться.

Если имеется серия команд преобразований (COMPUTE, IF, и т.д.), за которыми следует команда MISSING VALUES (задание кодов пропущенных значений), затрагивающая те же переменные, что и команды преобразования, может потребоваться использование команды EXECUTE перед MISSING VALUES. Ведь MISSING VALUES изменяет словарь данных немедленно, до прохода по данным, то есть до того, как преобразования будут иметь место. Например, рассмотрим:

1
2
IF (x = 0) y = z*2.
MISSING VALUES x (0).

Наблюдения, где x=0 будут рассматриваться как пропущенные и переменная y не будет изменена. Помещение EXECUTE перед MISSING VALUES принудит SPSS выполнить вычисления до того, как 0 для переменной x получит статус пропущенного значения.

Команда EXECUTE часто необходима, если вы используете команду WRITE для записи данных в ASCII-файл, или если используете команду XSAVE вместо SAVE, для сохранения данных в .sav-файл. Команды WRITE и XSAVE имеют тот же статус, что и COMPUTE (при их интерпретации процессор SPSS помещает их в список отложенных вычислений). Если ваша программа оканчивается командами WRITE или XSAVE без процедур, вызывающих проход по данным, файл, в который вы хотите записать, окажется пустым. Если же WRITE или XSAVE являются частью циклов LOOP или DO IF, команду EXECUTE использовать не надо (и нельзя).

Также, если за командами WRITE или XSAVE будет следовать статистическая процедура, данные будут записаны в новый файл.

Наконец, если вы задали серию вычислительно нагруженных преобразований и получаете сообщения о нехватке памяти когда SPSS пытается их отработать, вы можете поместить несколько команд EXECUTE вразбивку по коду, чтобы принудить SPSS пройти по данным и освободить память для следующей группы преобразований.Не помещайте EXECUTE внутрь структур трансформации данных, таких, как LOOP...END LOOP, DO IF...END IF, или DO REPEAT...END REPEAT. Также не помещайте EXECUTE между командами, которые создают временные (scratch) переменные и теми командами, которые их потом используют. Если за набором крупных преобразований у вас стоит вычислительно тяжелая команда, как, например, CLUSTER или MANOVA, вы можете поместить EXECUTE перед статистической процедурой. Хотя процедура и сама провела бы все преобразования, помещение EXECUTE перед ней позволит немного разгрузить память перед ее выполнением.

Это лишь примеры случаев, когда команду EXECUTE следует поместить между или после команд преобразований. Помещение EXECUTE после каждой команды COMPUTE почти всегда будет вычислительно неэффективным (в лучшем случае), или приведет к неработоспособности (в худшем), как, например, если поместить EXECUTE внутрь конструкций LOOP или DO IF.