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

Статистика в 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

Сцепление цифр из разных переменных в одну строку.SPS

Сцепить значения 22 переменных через тире.SPS

Перевести первую букву каждого слова в верхний регистр.SPS

Создать ключ, используя имя и дату рождения.SPS

"Нормализовать" первые буквы.sps

"Нормализовать" строки.SPS

Убрать инициалы из имени.SPS

Убрать точку из строки.SPS

Преобразовать имена.SPS

Преобразовать коды ASCII в символы.SPS

Сделать побитовое разложение целого числа.SPS 

Извлечь часть строки.SPS

Извлечь часть строки, начинающуюся с цифры.SPS

Извлечь индекс из поля адреса.SPS

Извлечь 2 числа из строки.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

Закавычивание строк.SPS

 

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

 


В избранное