1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
* Пропорциональный отбор без возвращения.
* Городские кварталы имеют разное число жителей. Требуется реализовать случайную
выборку кварталов, причём вероятность отбора должна быть пропорциональна населённости квартала. 

* (фактически, отбор реализуется с возвращением, но квартал попадает в выборку, если он отобран в первый раз).

*Следующие 3 файла 
draw file1.sav 
draw file2.sav
draw file3.sav
содержат промежуточные результаты. Их назначение - понять и проверить действия синтаксиса..
* Автор: Raynald Levesque raynald@spsstools.net .

*************************************************************.
* Для примера сгенерируем файл с 1000 наблюдений.
*************************************************************.
NEW file.
input program.
loop block=1 to 1000.
leave block.
compute pop=RND(uniform(10000)).
FORMATS block pop (F8.0).
end case.
end loop.
end file.
end input program.
execute.

SET MPRINT=ON.


*/////////////////////////// НАЧАЛО МАКРОСА //////////////////////////////.

DEFINE !SAMPLE (draw=!TOKENS(1) /keep=!TOKENS(1))

COMPUTE case# =$casenum.
CREATE t_weight=CSUM(pop).
SORT CASES BY case#(D).
CREATE c_weight= CSUM(pop).
SORT CASES BY case#.
IF $casenum=1 #tot_pop=c_weight.

VECTOR rva rvb (!draw F8.0).
!DO !cnt = 1 !TO !draw
	DO IF $casenum=1.
		COMPUTE !CONCAT(rva,!cnt)=UNIFORM(#tot_pop).				
		LEAVE !CONCAT(rva,!cnt).
		COMPUTE !CONCAT(rvb,!cnt)=!CONCAT(rva,!cnt)<t_weight.
	ELSE.
		COMPUTE !CONCAT(rvb,!cnt)=(!CONCAT(rva,!cnt)<t_weight) AND (!CONCAT(rva,!cnt)>lag(t_weight)).
	END IF.
!DOEND

COMPUTE flag=MAX(rvb1 TO !CONCAT('rvb',!draw)).
SAVE OUTFILE='draw file1.sav' /COMPRESSED.
SELECT IF (flag=1).
EXECUTE.
SAVE OUTFILE='draw file2.sav' /COMPRESSED.

VECTOR rvb=rvb1 TO !CONCAT(rvb,!draw).

* Квартал считается отобранным, если в одной из переменных rvb в его строке стоит 1. 
* Таким образом, один и тот же квартал может быть отобран более 1 раза. Это не значит, что
его строка повторяется более 1 раза. Это значит, что в переменных rvb единицы в его строке 
встречаются более 1 раза - А.Б.
*Следующая задача - сохранить лишь первый отбор квартала.
COMPUTE done=0.
LOOP cnt=1 TO !draw.
	DO IF rvb(cnt)=1 AND done=0.
	XSAVE OUTFILE='draw file3.sav' /KEEP block cnt.
	COMPUTE done=1.
	END IF.
END LOOP.
EXECUTE.

GET
  FILE='draw file3.sav'.
SORT CASES BY cnt.
SELECT IF ($casenum<=!keep).
EXECUTE.

!ENDDEFINE.
*/////////////////////////// КОНЕЦ МАКРОСА //////////////////////////////.


* Например, нам требуется отобрать 120 кварталов. 
Сначала мы отбираем 150 кварталов (с возможными повторами), повторяющиеся кварталы отсеиваем.
Затем полученные кварталы перемешиваем и отбираем первые 120.

!SAMPLE draw=150 keep=120.

*Примеч.: при недостаточном числе отборов с повторами требуемого числа keep (без повторов)
может и не набраться. Например, если есть множество мелких и несколько крупных кварталов.
В таких случаях можно пробовать увеличивать число draw относительно числа keep,
причём не обязательно ограничивать draw размером выборки.- А.Б.