SPSS AnswerNet Код решения: 100000760 ПО: SPSS Base Версия: ОС: Тип вопроса: Синтакс/пакетный режим/Скрипты Подтип вопроса: Преобразования данных Заголовок: Сложная выборка "с близнецами" без возвращения. Описание: Вопрос. В файле данных есть записи о трёх типах испытуемых. Первый тип представляет для меня особый интерес в моём исследовании. Второй испытуемых - это члены семьи первых. Третий тип - люди, которые не связаны родственными отношениями с первыми двумя типами. Мне требуется сопоставить записи первого типа с записями первых двух типов так, чтобы они подходили друг другу по полу и возрасту. При этом нужно гарантировать, что ни в какой паре не окажутся люди из одной и той же семьи. А кроме того - что ни один человек не попадёт в выборку дважды. Просто не знаю, в каком направлении начать поиски. Ответ. Задача нетривиальная, но способ есть. Идея решения - для начала сопоставить каждому ID человека все ID других людей, которые подходят по комбинации пол/возраст. Затем пары ID из таких перечней случайным образом отбираются в выборку, после чего соответствующие ID исключаются из рассмотрения. Найденные пары записываются в файл 'YOKED.SAV'. Те, для кого пары не нашлось, записываются в файл 'UNPAIRED.SAV'. Следующая программа может быть изменена таким образом, чтобы допускать более, чем 20 записей в каждой различимой комбинации пол/возраст. data list FREE/ FAMILY AGE GENDER Z PRIMARY. BEGIN DATA 1 1 1 2 1 1 2 1 4 2 2 3 2 2 1 2 4 2 3 2 3 3 2 3 1 3 2 1 2 2 4 4 2 3 1 4 3 2 1 2 5 1 1 3 1 5 2 2 2 2 6 3 1 2 1 6 4 1 2 2 7 2 2 2 1 7 3 2 1 2 8 2 1 2 1 8 3 2 1 2 9 1 1 1 1 9 2 2 3 2 10 3 2 9 1 10 2 1 1 2 11 2 1 2 1 11 2 1 2 2 12 3 1 2 1 12 3 2 1 2 13 1 1 3 1 14 2 2 1 1 15 1 2 2 1 16 2 1 5 1 17 4 2 2 1 18 3 2 1 1 19 4 1 5 1 20 4 1 1 1 21 1 2 5 1 22 3 2 4 1 23 4 1 5 1 24 2 2 8 1 25 4 1 2 1 26 3 2 1 1 27 2 1 5 1 28 4 1 1 1 29 3 2 3 1 30 2 2 6 1 31 4 1 4 1 32 3 1 2 1 33 1 2 2 1 34 3 1 1 1 35 4 2 1 1 36 2 1 4 1 END DATA . COMPUTE OLDSEQ=$CASENUM. SAVE OUTFILE 'RAWDATA.SAV' . * Сделаем так, чтобы записи первого типа содержали информацию об объекте второго типа из той же семьи *. * Создадим для этого дополнительную переменную *. SORT CASES BY FAMILY (A) PRIMARY (D). IF FAMILY=LAG(FAMILY) TWIN=LAG(OLDSEQ). * Пересчитаем все записи внутри каждой страты ВОЗРАСТ/ПОЛ (AGE/GENDER) *. SORT CASES BY AGE GENDER . IF (MISSING(LAG(OLDSEQ))) STCNT=1. IF (AGE=LAG(AGE) AND GENDER=LAG(GENDER)) STCNT=LAG(STCNT) +1. IF (MISSING(STCNT)) STCNT=1. * Распределим информацию об ID-номерах всех кандидатов на "спаривание" по всем наблюдениям в пределах категории пол/возраст *. * Оставим только записи первого типа *. VECTOR ID_(20). COMPUTE ID_(STCNT)=OLDSEQ. AGGREGATE OUTFILE 'C:\\TEMP\\TMP.SAV' / PRESORTED/ BREAK=AGE GENDER / TWIN=FIRST(TWIN) / ID_X01 TO ID_X20 = MAX(ID_1 TO ID_20). SELECT IF PRIMARY=1. MATCH FILES FILE=* / TABLE='C:\\TEMP\\TMP.SAV' / BY AGE GENDER. * Проверяем, находится ли текущая запись в той же страте, что и предыдущая *. * Если так, эта запись "наследует" перечень ID-номеров кандидатов на "спаривание" *. * (IMHO, проверка и копирование лишние - предыдущая команда MATCH FILES уже размножила нужные ID - А.Б.) COUNT MAXVALID=ID_X01 TO ID_X20 (LO THRU HI). DO IF AGE=LAG(AGE) AND GENDER=LAG(GENDER) . + DO REPEAT ID=ID_X01 TO ID_X20 . + COMPUTE ID = LAG(ID) . + END REPEAT. END IF. * Зададим вектор с ID возможных кандидатов *. VECTOR ID_X=ID_X01 TO ID_X20 . * Важно не сопоставить запись самой себе! *. DO IF NOT MISSING (ID_X(STCNT) ). * Обнулим флаги состояния *. + DO REPEAT INIT=TAKEN FOUND NTRYS . + COMPUTE INIT=0. + END REPEAT. * Ведём случайный отбор пар ID в векторе, копируем в YOKE и уничтожаем оригинал *. + LOOP. + COMPUTE WHICH=TRUNC(UNIFORM(MAXVALID))+1. + IF WHICH <> STCNT YOKE=ID_X(WHICH). + DO IF (NOT (ANY(YOKE,TWIN,OLDSEQ,$SYSMIS))) . + COMPUTE ID_X(WHICH)=$SYSMIS . + COMPUTE ID_X(STCNT)=$SYSMIS . + COMPUTE FOUND=1. + END IF . + END LOOP IF FOUND. ELSE. COMPUTE TAKEN=1. END IF. * Разделим все записи на нашедшие пару и ненашедшие. Оставим информацию об их ID * . TEMPORARY . SELECT IF (MISSING (YOKE) AND NOT(TAKEN) ). SAVE OUTFILE 'UNPAIRED.SAV' . SELECT IF (NOT (TAKEN) AND NOT MISSING (YOKE) ). SAVE OUTFILE 'TMP' / KEEP OLDSEQ YOKE. GET FILE 'TMP'. COMPUTE GROUP=$CASENUM . * Преобразуем пары из одной записи в пары записей *. VECTOR V = OLDSEQ TO YOKE . LOOP X=1 TO 2. COMPUTE OLDSEQ=V(X). XSAVE OUTFILE 'TMP2' / KEEP GROUP X OLDSEQ . END LOOP. EXECUTE. * Добавим к полученным ID исходные данные, не участвовавшие в отборе * В ДАННОМ СЛУЧАЕ - ПЕРЕМЕННАЯ Z * . GET FILE 'TMP2'. SORT CASES BY OLDSEQ. MATCH FILES FILE = * / TABLE = 'RAWDATA.SAV' / BY OLDSEQ . SORT CASES BY GROUP. ******************************************************** . * Распространим значения данных на пары записей: * . * вам потребуется сделать обобщение этой процедуры на несколько переменных * . * КАК-ТО ТАК... * . * VECTOR ID(2). * . * DO REPEAT VAR = Y Z . * . * VECTOR VAR(2) . * . * COMPUTE VAR(X) = VAR . * . * END REPEAT . * . * AGGREGATE ...../ Y1 Y2 Z1 Z2 = MAX(Y1 Y2 Z1 Z2).* . ******************************************************** . VECTOR Z(2) / ID(2). COMPUTE Z(X) = Z. COMPUTE ID(X)=OLDSEQ. AGGREGATE OUTFILE * / PRESORTED / BREAK=GROUP GENDER AGE / Z1 TO Z2 = MAX(Z1 TO Z2) / ID1 TO ID2 = MAX(ID1 TO ID2). SAVE OUTFILE 'YOKED.SAV'. LIST. * Результаты! * . GROUP GENDERAGE Z1 Z2 ID1 ID2 1 1 1 2 3 1 9 2 1 1 1 3 17 25 3 2 1 2 5 27 33 4 1 2 2 4 15 48 5 1 2 2 1 21 20 6 1 2 5 4 28 2 7 1 2 5 2 39 6 8 2 2 2 2 13 10 9 2 2 1 3 26 18 10 2 2 8 6 36 42 11 1 3 2 2 11 23 12 1 3 2 1 44 46 13 2 3 2 3 3 5 14 2 3 9 3 19 41 15 2 3 1 1 30 8 16 2 3 4 1 34 38 17 1 4 5 2 31 12 18 1 4 1 5 32 35 19 1 4 2 1 37 40 20 2 4 3 1 7 47 21 2 4 2 3 29 4 Number of cases read: 21 Number of cases listed: 21