Рассылка закрыта
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Статистика в SPSS: за пределами кнопочного интерфейса. Выпуск 10
Статистика в SPSS: за пределами кнопочного интерфейса. Выпуск 10
В рассылке используются материалы веб-сайта www.spsstools.ru
Содержание выпуска
Пример разбора текстовой строки
Новое на сайте www.spsstools.ru
Здравствуйте, уважаемые подписчики!
Во-первых, искренние поздравления подписчицам, если можно так выразиться, с прошедшим женским праздником! Вас, изучающих премудрости пакета SPSS, немного среди нас (около 30%, по данным Subscribe.Ru), и оттого вы нам только дороже! :)
А синтаксис мы сегодня посмотрим хоть и не праздничный, но интересный.
Пример разбора текстовой строки
За основу сегодняшнего выпуска мы возьмём файл синтаксиса Извлечь часть строки, начинающуюся с цифры.SPS. Суть данной программы состоит в следующем. Имеется текстовая переменная, в которой "слеплены" имя и адрес клиента, например: "Bloggs J 10 Smith St" (т.е. некий J. Bloggs, проживающий (работающий) по адресу ул. Smith, д. 10). Требуется для каждого подобного значения переменной расщепить имя клиента и его адрес и разнести по 2-м разным переменным. Предполагается, что адрес завсегда начинается с цифры, т.е. программа "догадается" о начале адресной части строки как только в ней встретится первая цифра.
Нельзя сказать, что описанная ситуация является очень распространённой на практике, да и характер преобразований сложно назвать типичным для статистической программы (обычно это делается на предварительных этапах подготовки данных - во время запросов к базам данных, обработки где-нибудь в Excel и т.д.). Но для нас этот пример ценен тем, что в нём используются разнообразные функции преобразования и проверки данных, временные переменные, рассмотрены два варианта решения поставленной задачи, а также демонстрируются особенности работы цикла LOOP.
Автор синтаксиса, Raynald Levesque, разместил его в списке рассылки SPSSX-L 25 июля 2002 года.
Начнём мы, как всегда, с определения примера данных:
DATA LIST FIXED /str1 1-25 (A).
BEGIN DATA
Bloggs J 10 Smith St
Bloggs John 12 Smith St
END DATA.
LIST.
Данные определяются в фиксированном формате, т.е. первые 25 символов каждой строки между командами BEGIN DATA - END DATA записываются в переменную str1, имеющую строковый формат (на это указывает символ A в скобках в конце команды DATA LIST). Если строка короче, чем 25 символов, последние несколько символов автоматически заполняются пробелами (хотя в режиме редактирования вы их и не отыщите). Если длиннее - строка обрезается. Результирующая переменная str1 будет иметь формат A25.
В данном случае мы определили всего 2 значения переменной str1. Ясно, что практическая польза от синтаксиса появится при достаточно большом числе наблюдений, подлежащих преобразованию. Команда LIST отображает содержимое переменной str1 в окне результатов.
Далее даётся разбор первого метода решения задачи.
Во-первых, мы должны узнать, символы с какими порядковыми номерами являются числами. Создадим вектор из 25 (по длине строковой переменной) числовых переменных формата F2 (два знака, целое число).
VECTOR nb(25F2).
В результате выполнения следующего цикла LOOP в каждой из компонент вектора nb(cnt), где cnt=1,...,25, окажется либо 0 (в случае, если cnt-й символ не является цифрой, либо cnt, если cnt-й символ - цифра). В качестве индекса цикла мы определяем вспомогательную переменную cnt. Тело цикла состоит из единственной команды COMPUTE с несколькими вложенными функциями. Мы видим, что с правой стороны от знака равенства индексная переменная умножается на некоторое выражение. Данное выражение будет равно единице, в случае, если символ с номером cnt является цифрой, и нулём в противоположном случае (в том числе и тогда, когда этого символа нет вовсе, а точнее, когда строка короче, чем cnt и символ с номером cnt является одним из замыкающих пробелов).
LOOP cnt=1 TO 25.
COMPUTE nb(cnt)=cnt*(1-NMISS(NUMBER(SUBSTR(str1,cnt,1),F1))).
END LOOP.
Рассмотрим подробнее те функции, которые формируют множитель для переменной cnt в цикле, приведённом выше. Наиболее глубокий уровень вложенности имеет функция SUBSTR(str1, cnt,1). Фактически, она возвращает подстроку из текстового значения переменной str1, состоящую из единственного символа с номером cnt. Первый аргумент данной функции - исходная строка, второй - символ, с которого начинается выделение подстроки, а третий - количество отбираемых символов. Так, при cnt=9 для первой строки файла данных примера результат этой функции будет состоять из одного пробела, а для второй строки - из буквы "o". Затем функция NUMBER пытается преобразовать считанное функцией SUBSTR текстовое значение в числовое значение формата F1 (целое число длины 1). F1 - второй аргумент функции NUMBER. Первым является функция SUBSTR. Если анализируемый символ является числом, результат функции NUMBER будет равен этому числу, если же нет - пропущенному значению. Далее в действие вступает функция NMISS, которая считает количество аргументов, имеющих статус пропущенных значений. Обычно аргументами функции NMISS являются несколько переменных. Данное использование этой функции - своего рода исключение. Функция анализирует результат попытки преобразования в число очередного символа строки из переменной str1. Ясно, что в случае, если символ с номером cnt был цифрой, функция NMISS будет возвращать 0, в случае, если чем-то иным, то NMISS будет равна 1, т.к. результат функции NUMBER является её единственным аргументом. В заключение мы вычитаем из единицы результат функции NMISS. Ноль становится единицей и наоборот. Этот результат домножается на cnt и помещается в переменную-вектор nb(cnt). Таким образом, для первой строки nb1=0, а nb10=10, т.е. 10*1.
Обратите внимание, что всякий раз, когда функция NUMBER будет пытаться обращать в число символ, не являющийся цифрой, будет возникать соответствующее предупреждение (Warning) с выводом в окно результатов. В данном случае это является нормальным. Предупреждения не нарушат ход выполнения синтаксиса и не отразятся на конечном результате.
Следующий цикл имеет целью лишь замену нулей на пропущенные значения. Для этого мы прибегаем к условным вычислениям (команда IF) и системной константе $SYSMIS, равной пропущенному значению.
LOOP cnt=1 TO 25.
IF nb(cnt)=0 nb(cnt)=$SYSMIS.
END LOOP.
Кстати, команду IF ... можно было бы вставить и в предыдущий цикл, без создания отдельного.
Доведите при пошаговом исполнении синтаксиса вычисления до этой точки и станет ясно, какой вид имеет редактор данных к настоящему моменту. (Чтобы увидеть результаты вычислений потребуется дополнительно выполнить инструкцию EXECUTE, поскольку она ещё ни разу не встречалась)
Далее можно вычислить переменную pos...
COMPUTE pos=MIN(nb1 TO nb25).
которая будет (посредством функции MIN) содержать номер символа для каждой строки, где в ней первый раз встретилась цифра. Заметьте, если бы мы не заменили командой раньше нули на пропуски, значения переменной pos наверняка были бы нулями.
Теперь осталось подготовить переменную addr, куда мы будем записывать адрес. И вычислить значение этой переменной.
STRING addr(A25).
COMPUTE addr=SUBSTR(str1,pos).
Команда STRING создаёт строковую переменную с указанным именем и указанного формата.
Следующей командой посредством функции SUBSTR с неполным набором аргументов мы запрашиваем подстроку из значения переменной str1, начиная с символа pos. Поскольку третий аргумент (длина подстроки) не указан, программа выделяет подстроку до окончания исходной строки.
Заключительной командой
ADD FILES FILE=* /DROP=pos nb1 TO nb25 cnt.
мы не добавляем никаких файлов, как это можно было бы заключить из названия команды, а просто пользуемся возможностью данной команды по отбрасыванию ненужных более переменных, а именно pos, nb1-nb25 и cnt. Их мы указываем в подкоманде DROP.
В качестве задания для самостоятельной работы можно предложить уважаемым подписчикам сделать следующие операции с помощью изменения исходного синтаксиса:
1. Поместить в отдельную переменную имя клиента (в данном случае мы отделили лишь адрес);
3. Попробовать заменить ненужные нули не с использованием цикла, а с помощью RECODE, например;
2. Попробовать выполнить первый цикл, используя не комбинацию "1-NMISS...", а, возможно, более простое выражение на основе, например, функции MISSING. Кстати, это позволит избежать последующей замены нулей;
3. Удалить лишние переменные в конце не с помощью команды ADD FILES, а с помощью DELETE VARIABLES (это потребует использования дополнительной инструкции EXECUTE), т.к. ADD FILES обладает свойством запускать отложенные вычисления, а DELETE VARIABLES - нет;
4. Проконтролируйте корректность выполнения синтаксиса на других данных. Что, если в строке вовсе не встретится адрес (цифра), или там будет стоять только адрес? Постарайтесь доработать синтаксис, если будут обнаружены какие-то неточности. В последнем случае, как, в общем-то, и всегда, буду признателен за отклики.
А мы продолжим и разберём второй вариант решения задачи, который находится в этом же синтаксисе.
Разумеется, сначала восстановим исходные данные. Здесь всё полностью совпадает с первым вариантом.
DATA LIST FIXED /str1 1-25 (A).
BEGIN DATA
Bloggs J 10 Smith St
Bloggs John 12 Smith St
END DATA.
LIST.
Далее следует исполнение пустого цикла с условным выходом из него. Особенности выполнения циклов в синтаксисе SPSS позволяют значительно сократить объём команд и вычислений. Смотрите, в качестве индекса цикла мы используем переменную cnt, но на этот раз не в явном виде, а временную, невидимую переменную (с префиксом #). Тем не менее, она обладает почти теми же свойствами, что и обычная переменная. Вся цель нашего цикла состоит в том, чтобы прогнать значения индекса от 1 с шагом 1 в сторону увеличения максимум до 25, но пока не будет выполнено дополнительное условие выхода из цикла LOOP: #cnt*(1-NMISS(NUMBER(SUBSTR(str1,#cnt),F1)))>0. Обратите внимание, формула очень похожа на ту, что использовалась в первом варианте. В данном случае лишь опущен третий аргумент у функции SUBSTR, но это не важно. В самом деле, не важно, какой длины будет подстрока - в один символ, или до конца строки, но начиная с символа с номером #cnt - всё равно функция NUMBER затем будет анализировать лишь первый символ, т.к. задан формат F1.
Поскольку указанные цикл выполняется отдельно для каждого наблюдения и индексная переменная остаётся "жить" (не исчезает) как и любая другая переменная в SPSS, то после выполнения данного цикла для каждого наблюдения переменная #cnt "застынет" на том значении, при котором впервые было выполнено условие выхода из цикла. Для каждого наблюдения это значение будет своим.
LOOP #cnt=1 TO 25.
END LOOP IF #cnt*(1-NMISS(NUMBER(SUBSTR(str1,#cnt),F1)))>0.
Остальное - дело техники. Используя переменную #cnt для каждого наблюдения мы можем вычислить подстроку адреса. Эти команды нам знакомы по первому методу.
STRING addr(A25).
COMPUTE addr=SUBSTR(str1,#cnt).
EXECUTE.
Творческих успехов и связанного с ними хорошего настроения!
Ведущий рассылки,
Балабанов Антон
Новое на сайте www.spsstools.ru
Переведены и добавлены примеры синтаксиса:
Автоматически рассчитать веса для данных.SPS
Преобразование Бокса-Кокса.SPS
Вычислить z = x / max(y), где max(y) - максимум по всем наблюдениям.SPS
Особенность функции CONCAT.SPS
Объединение строковой и числовой переменных.SPS
Объединение данных с одним и тем же идентификатором.SPS
Сцепление цифр из разных переменных в одну строку.SPS
Сцепить значения 22 переменных через тире.SPS
Перевести первую букву каждого слова в верхний регистр.SPS
Создать ключ, используя имя и дату рождения.SPS
"Нормализовать" первые буквы.sps
Преобразовать коды ASCII в символы.SPS
Сделать побитовое разложение целого числа.SPS
Извлечь часть строки, начинающуюся с цифры.SPS
Извлечь индекс из поля адреса.SPS
Пометить, если последние символы в строке - 'Esq'.SPS
Разбить строку на значения односимвольных переменных.SPS
Выделить в строке числа, разделённые запятыми.SPS
Разнести по разным переменным данные, разделённые символом "/".SPS
Извлечь доменное имя из адреса электронной почты.SPS
Разложить значения, разделённые запятыми, по разным переменным и закодировать результат.SPS
Разбор строк, имеющих в себе символы возврата строки и перевода каретки.SPS
Убрать букву в конце строки и конвертировать остаток в числовую переменную.SPS
Разбить строку на имена истца и ответчика.SPS
Разбор строки со значениями, разделёнными символом "/".SPS
Отсеять буквы из строки и преобразовать остаток в число.SPS
Переведены и добавлены макросы:
Добавить результаты регрессии по наблюдениям в файл данных.SPS
Вызывать макрос с аргументами, равными по очереди каждому значению из переменной.SPS
Заставить макропеременную принимать значения из переменной файла данных.SPS
Как перемножить две макропеременные.SPS
Попарное использование переменных из аргумента макроса.SPS
Включение нескольких статистик по файлу данных в макрос.SPS
Включение статистики по файлу данных в синтаксис.SPS
Группировка результатов по типам объектов (школа 1, школа 2 и т.д.).SPS
Генерация переменного числа команд синтаксиса.SPS
Вызов макроса из другого макроса.SPS
Листинг (распечатка значений) в цикле.SPS
Определяем пути к файлам с помощью макроса.SPS
Выполнить макрос для каждого уникального значения переменной.SPS
Выполнение макроса при пустом файле данных (определение данных через матрицы).SPS
Печать сообщений в окне результатов.SPS
Анализ для заданных поднаборов значений переменной.SPS
Запуск макроса с разными наборами параметров из файла данных.SPS
Запуск макроса с разными наборами параметров... (пример 2).SPS
© См. www.spsstools.ru, 2005-2006
В избранное | ||