-
Notifications
You must be signed in to change notification settings - Fork 0
/
desc_sampling.qmd
412 lines (326 loc) · 17 KB
/
desc_sampling.qmd
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
```{r}
#| include: false
source("_common.R")
```
# 표본추출방법
거의 모든 통계적 방법은 암묵적 무작위성 개념에 기초하고 있다. 만약 데이터가 모집단으로부터 무작위 구조 아래에서 수집되지 않는다면, 통계적 방법 -- 추정값과 추정값과 연관된 오차 -- 은 신뢰할 수 없다. 여기서 통계에서 가장 기본이 되는 4가지 무작위 표본 추출 기법(단순 표집, 층화 표집, 군집 표집, 다단계 표집)을 살펴보자.
## 단순 임의 표본 추출
**단순 임의 표본 추출**은 무작위로 표본을 선정하는 가장 기본적인 방법이다. 예를 들어, 344마리의 펭귄으로 이루어진 팔머 펭귄 데이터셋에서 120마리의 펭귄을 뽑아 몸무게를 조사하고 싶다고 가정해 보자.
이때, 제비뽑기함에 344마리 펭귄의 이름을 모두 적어 넣고, 120마리가 뽑힐 때까지 무작위로 이름을 뽑는 것이 단순 임의 표본 추출 방식이다. 이 방법은 모집단 내 모든 펭귄이 표본으로 선택될 확률이 동일하다는 특징이 있다.
또한, 어떤 펭귄이 표본에 포함되더라도 다른 펭귄이 표본에 포함될 확률에 영향을 주지 않는다. 이처럼 모집단의 모든 사례가 동일한 확률로 표본에 포함되고, 특정 사례의 선택이 다른 사례의 선택에 영향을 미치지 않을 때 이를 "단순 무작위 표본"이라고 한다.
```{r}
#| label: fig-simple-random-sampling
#| fig-cap: '단순 무작위 추출을 사용해 사례 10개를 무작위로 선택하여 빨간색으로 표시.'
#| fig-width: 10.0
#| echo: false
source("code/helper-sampling.R") # source helper
build_srs(n = 10, N = 100) # build figure
```
## 층화 표본 추출
**층화 표본 추출**은 모집단을 유사한 특성을 가진 하위 집단인 층으로 나누고, 각 층에서 무작위로 표본을 추출하는 방식이다. 이는 분할 정복 전략을 활용한 표본 추출 기법 중 하나이다.
예를 들어, 팔머 펭귄 데이터셋에서 펭귄의 종은 서로 다른 특성을 가지고 있으므로 층을 대표할 수 있다. 따라서 종별로 40마리씩 무작위 추출하여 총 120마리의 표본을 얻을 수 있다.
층화 표본 추출은 각 층 내부의 사례들이 연구하고자 하는 결과에 대해 매우 비슷한 특성을 보일 때 특히 유용하다. 하지만 층화 표본 데이터를 분석하는 것은 단순 무작위 표본 데이터를 다루는 것보다 더 복잡할 수 있다는 단점이 있다.
```{r}
#| label: fig-stratified-sampling
#| fig-cap: "층화 추출로 사례를 먼저 층으로 나눠 그룹화한 다음, 각 층에서 3개의 사례를 무작위로 선택하는 단순 무작위 추출을 적용."
#| fig-width: 10.0
#| echo: false
source("code/helper-sampling.R") # source helper
build_stratified(N = 100) # build figure
```
## 군집 표본 추출
**군집 표본 추출**은 모집단을 여러 개의 군집으로 분할하고, 그 중 일부 군집을 무작위로 선택하여 해당 군집 내 모든 관측점을 표본에 포함하는 방식이다. 이 방법은 군집 간 차이는 크지 않지만, 군집 내 사례들 간의 변동성이 클 때 효과적이다. 예를 들어, 섬을 군집으로 설정하고 섬 내 개체군의 다양성이 클 경우 군집 표본 추출이 적합하다. 이 방법은 다른 표본 추출 기법에 비해 경제적일 수 있다는 장점이 있지만, 일반적으로 더 복잡한 분석 기법을 요구한다는 단점이 있다.
```{r}
#| label: fig-clustering-sampling
#| fig-cap: "군집 표본 추출로 전체 모집단을 9개 군집으로 나누고, 군집 3개를 표본으로 선택하고 나서, 선택된 세 군집 내의 모든 관측치가 표본에 포함."
#| fig-width: 10.0
#| echo: false
source("code/helper-sampling.R") # source helper
build_cluster() # build figure
```
## 다단계 표본 추출
**다단계 표본 추출**은 군집 표본 추출과 유사하게 모집단을 여러 개의 군집으로 분할한다. 그러나 선택된 군집 내에서 다시 무작위로 표본을 추출하는 점에서 군집 표본 추출과 차이가 있다. 이 방법 역시 군집 간 차이는 크지 않지만, 군집 내 사례들 간의 변동성이 클 때 효과적이다. 다단계 표본 추출은 군집 표본 추출과 마찬가지로 경제적일 수 있지만, 더 복잡한 분석 기법을 필요로 한다. 하지만 기존의 분석 방법을 확장함으로써 이러한 데이터를 처리할 수 있다.
```{r}
#| label: fig-multistage-sampling
#| fig-cap: "다단계 표본 추출로 전체 모집단을 9개 군집으로 나누고, 군집 3개를 표본으로 선택하고 나서, 선택된 세 군집 내의 모든 관측치가 표집하는 대신 일부만 표집."
#| fig-width: 10.0
#| echo: false
source("code/helper-sampling.R") # source helper
build_multistage() # build figure
```
## R 코드
4가지 표본 추출 방법을 팔머펭귄 데이터셋에 적용해보자.
### 단순 무작위 표본 추출
단순 무작위 표본추출방법(Simple Random Sampling)은 모집단이 비교적 동질적이고 하위 그룹에 대한 정보가 필요하지 않을 때 적합하다.
모든 펭귄이 표본에 선택될 동등한 기회를 가지며, 이론적으로 모집단을 가장 잘 대표하는 표본을 얻을 수 있다. 단순 무작위 표본 추출은 표본 추출 방법 중 가장 간단하고 효율적인 방법이다.하지만, 특정 그룹이 과소 또는 과대 표현될 수 있고, 큰 데이터셋에서는 비용이 많이 들 수 있다는 단점이 있다. `dplyr` 패키지의 `slice_sample()` 함수를 사용하여 단순 무작위 표본 추출을 수행할 수 있다. `n = 50`을 지정하여 50개의 표본을 추출할 수도 있고, `p = 0.1`을 지정하여 10%의 표본을 추출할 수도 있다.
```{webr-r}
#| label: lst-simple-random-sampling
# 단순 무작위 표본 추출
download.file("https://raw.githubusercontent.com/bit2r/bitData/main/data-raw/penguins.csv", "k_penguins.csv")
k_penguins_tbl <- readr::read_csv("k_penguins.csv")
srs_penguins <- k_penguins_tbl |>
slice_sample(n = 50)
srs_penguins
```
### 층화 표본 추출
층화 표본 추출(Stratified Sampling)은 모집단을 여러 층(stratum)으로 나눈 후 각 층에서 단순 무작위 표본 추출을 수행하는 방법으로 모집단이 이질적이고 하위 그룹에 대한 정보가 중요할 때 적합하다.
모집단의 하위 그룹을 고려하여 표본을 추출하므로 모집단을 잘 대표할 수 있고 하위 그룹별 분석이 가능하다는 장점이 있는 반면, 층을 나누기 위한 정보가 필요하고, 층별로 별도의 표본 추출이 이루어지므로 경우에 따라서는 비용이 더 들 수도 있다.
`group_by()` 함수를 사용하여 종을 기준으로 층화시킨 후 `slice_sample()` 함수로 단순 무작위 표본 추출 작업을 수행한다.
```{webr-r}
#| label: lst-stratified-sampling
# 종을 기준으로 층화 표본 추출
stratified_penguins <- k_penguins_tbl %>%
group_by(종명칭) %>%
slice_sample(n = 2)
stratified_penguins
```
### 군집 표본 추출
군집 표본 추출(Cluster Sampling)은 모집단을 여러 군집(cluster)으로 나눈 후 몇 개의 군집을 무작위로 선택한 후 선택된 군집에서 모든 개체를 표본으로 추출하는 방법이다. 군집 표본 추출은 모집단이 지리적으로 넓게 분포되어 있을 때 효율적이다. 모집단이 자연스럽게 군집을 이루고 있고, 군집 간 차이가 크지 않을 때 적합하다. 군집 내 유사성으로 인해 편향된 결과를 얻을 수 있으며, 표본 크기가 클 수 있다는 단점이 있다. `sample()` 함수를 사용하여 군집을 무작위로 선택한 후 `filter()` 함수로 선택된 군집에 속하는 표본을 추출한다. 펭귄이 서식하는 섬(비스코, 드림, 토르거센)을 기준으로 무작위로 섬을 하나 선택하고 해당 섬에 서식하는 펭귄을 모두 추출한다.
```{webr-r}
#| label: lst-cluster-sampling
# 서식지를 기준으로 군집 표본 추출
unique_islands <- unique(k_penguins_tbl$섬이름)
selected_islands <- sample(unique_islands, 1)
selected_islands
cluster_penguins <- k_penguins_tbl |>
filter(섬이름 %in% selected_islands)
cluster_penguins
```
### 다단계 표본 추출
다단계 표본 추출(Multistage Sampling)은 두 단계 이상으로 표본을 추출하는 방법으로 모집단이 계층적 구조를 가지고 있을 때 적합하다. 다단계 표본 추출은 복잡한 설계를 필요로 하며, 설계 효과(design effect)를 고려해야 한다. `sample()` 함수를 사용하여 서식지를 기준으로 1차 추출한 후 `slice_sample()` 함수로 펭귄을 2차 추출한다.
```{webr-r}
#| label: lst-multistage-sampling
# 서식지를 기준으로 1차 추출, 그 후 펭귄을 2차 추출
unique_islands <- unique(k_penguins_tbl$섬이름)
selected_islands <- sample(unique_islands, 2)
selected_islands
multistage_penguins <- k_penguins_tbl |>
filter(섬이름 %in% selected_islands) |>
group_by(섬이름) %>%
slice_sample(n = 2)
multistage_penguins
```
## shiny 앱
```{shinylive-r}
#| label: shinylive-four-sampling
#| viewerHeight: 600
#| standalone: true
library(shiny)
library(openintro)
data(COL)
# _____ Simple Random _____ #
build_srs <- function(n, N) {
colSamp <- COL[4]
PCH <- rep(c(1, 3, 20)[3], 3)
col <- rep(COL[1], N)
pch <- PCH[match(col, COL)]
plot(0, xlim = c(0,2), ylim = 0:1, type = 'n', axes = FALSE, xlab = "", ylab = "")
box()
x <- runif(N, 0, 2)
y <- runif(N)
inc <- n
points(x, y, col = col, pch = pch)
these <- sample(N, n)
points(x[these], y[these], pch = 20, cex = 0.8, col = colSamp)
points(x[these], y[these], cex = 1.4, col = colSamp)
}
# _____ Stratified _____ #
build_stratified <- function(N, numStrata, sampleSizePerStratum) {
colSamp <- COL[4]
col <- rep(COL[1], N)
PCH <- rep(c(1, 3, 20)[3], 3)
plot(0, xlim = c(0, 2), ylim = 0:1 + 0.01,
type = 'n', axes = FALSE, xlab = "", ylab = "")
box()
X <- seq(0.1, 1.9, length.out = numStrata)
Y <- rep(0.5, numStrata)
# 각 계층의 크기를 무작위로 생성
strataSizes <- sample(ceiling(N/numStrata) * 0.5 + c(-1, 1) * ceiling(N/numStrata) * 0.25, numStrata, replace = TRUE)
strataSizes <- round(strataSizes / sum(strataSizes) * N)
R <- sqrt(strataSizes / 500)
above <- rep(1, numStrata)
currentIndex <- 1
for (i in 1:numStrata) {
hold <- seq(0, 2 * pi, length.out = 99)
x <- X[i] + (R[i] + 0.01) * cos(hold)
y <- Y[i] + (R[i] + 0.01) * sin(hold)
polygon(x, y, border = COL[5, 4])
x <- rep(NA, strataSizes[i])
y <- rep(NA, strataSizes[i])
for (j in 1:strataSizes[i]) {
inside <- FALSE
while (!inside) {
xx <- runif(1, -R[i], R[i])
yy <- runif(1, -R[i], R[i])
if (sqrt(xx^2 + yy^2) < R[i]) {
inside <- TRUE
x[j] <- xx
y[j] <- yy
}
}
}
type <- sample(1, strataSizes[i], TRUE)
pch <- PCH[type]
col <- COL[type]
x <- X[i] + x
y <- Y[i] + y
points(x, y, pch = pch, col = col)
these <- sample(strataSizes[i], min(sampleSizePerStratum, strataSizes[i]))
points(x[these], y[these],
pch = 20, cex = 0.8, col = colSamp)
points(x[these], y[these], cex = 1.4, col = colSamp)
currentIndex <- currentIndex + strataSizes[i]
}
text(X, Y + above * (R),
paste("계층", 1:numStrata),
pos = 2 + above,
cex = 1.3)
}
# _____ Cluster _____ #
build_cluster <- function(numClusters, clusterSizes, selectedClusters) {
colSamp <- COL[4]
PCH <- rep(c(1, 3, 20)[3], 3)
plot(0, xlim = c(0, 2), ylim = c(0.01, 1.04), type = 'n', axes = FALSE, xlab = "", ylab = "")
box()
X <- seq(0.1, 1.9, length.out = numClusters)
Y <- runif(numClusters, 0.2, 0.8)
R <- sqrt(clusterSizes / 500)
above <- ifelse(Y > 0.5, 1, -1)
for (i in 1:numClusters) {
hold <- seq(0, 2 * pi, length.out = 99)
x <- X[i] + (R[i] + 0.02) * cos(hold)
y <- Y[i] + (R[i] + 0.02) * sin(hold)
polygon(x, y, border = COL[5, 4])
if (i %in% selectedClusters) {
polygon(x, y, border = COL[4], lty = 2, lwd = 1.5)
}
x <- rep(NA, clusterSizes[i])
y <- rep(NA, clusterSizes[i])
for (j in 1:clusterSizes[i]) {
inside <- FALSE
while (!inside) {
xx <- runif(1, -R[i], R[i])
yy <- runif(1, -R[i], R[i])
if (sqrt(xx^2 + yy^2) < R[i]) {
inside <- TRUE
x[j] <- xx
y[j] <- yy
}
}
}
type <- sample(1, clusterSizes[i], TRUE)
pch <- PCH[type]
col <- COL[type]
x <- X[i] + x
y <- Y[i] + y
points(x, y, pch = pch, col = col)
if (i %in% selectedClusters) {
points(x, y, pch = 20, cex = 0.8, col = colSamp)
points(x, y, cex = 1.4, col = colSamp)
}
}
text(X, Y + above * (R + 0.01),
paste("군집", 1:numClusters),
pos = 2 + above,
cex = 1.3)
}
# _____ Multistage Sampling _____ #
build_multistage <- function(numClusters, sampleSizePerCluster, clusterSizes) {
colSamp <- COL[4]
PCH <- rep(c(1, 3, 20)[3], 3)
plot(0, xlim = c(0, 2), ylim = c(0.01, 1.04), type = 'n', axes = FALSE, xlab = "", ylab = "")
box()
X <- seq(0.1, 1.9, length.out = numClusters)
Y <- runif(numClusters, 0.2, 0.8)
R <- sqrt(clusterSizes / 500)
above <- ifelse(Y > 0.5, 1, -1)
for (i in 1:numClusters) {
hold <- seq(0, 2 * pi, length.out = 99)
x <- X[i] + (R[i] + 0.02) * cos(hold)
y <- Y[i] + (R[i] + 0.02) * sin(hold)
polygon(x, y, border = COL[5, 4])
x <- rep(NA, clusterSizes[i])
y <- rep(NA, clusterSizes[i])
for (j in 1:clusterSizes[i]) {
inside <- FALSE
while (!inside) {
xx <- runif(1, -R[i], R[i])
yy <- runif(1, -R[i], R[i])
if (sqrt(xx^2 + yy^2) < R[i]) {
inside <- TRUE
x[j] <- xx
y[j] <- yy
}
}
}
type <- sample(1, clusterSizes[i], TRUE)
pch <- PCH[type]
col <- COL[type]
x <- X[i] + x
y <- Y[i] + y
points(x, y, pch = pch, col = col)
these <- sample(clusterSizes[i], min(sampleSizePerCluster, clusterSizes[i]))
points(x[these], y[these], pch = 20, cex = 0.8, col = colSamp)
points(x[these], y[these], cex = 1.4, col = colSamp)
}
text(X, Y + above * (R + 0.01),
paste("군집", 1:numClusters),
pos = 2 + above, cex = 1.3)
}
# ui -----
ui <- fluidPage(
titlePanel("표본 추출 방법 시각화"),
sidebarLayout(
sidebarPanel(
radioButtons("method", "표본 추출 방법 선택:",
c("단순 무작위 표본 추출" = "srs",
"층화 표본 추출" = "stratified",
"군집 표본 추출" = "cluster",
"다단계 표본 추출" = "multistage"),
inline = TRUE),
conditionalPanel(
condition = "input.method == 'srs'",
sliderInput("sampleSize", "표본 크기:", min = 1, max = 100, value = 10)
),
conditionalPanel(
condition = "input.method == 'stratified'",
sliderInput("numStrata", "층(Stratum) 수:", min = 1, max = 5, value = 3),
sliderInput("sampleSizePerStratum", "층 내부 표본 크기:", min = 1, max = 10, value = 3)
),
conditionalPanel(
condition = "input.method == 'cluster'",
sliderInput("numClusters", "군집 수:", min = 1, max = 9, value = 3)
),
conditionalPanel(
condition = "input.method == 'multistage'",
sliderInput("numClustersMultistage", "군집 수:", min = 1, max = 9, value = 3),
sliderInput("sampleSizePerClusterMultistage", "군집 내부 표본 크기:", min = 1, max = 10, value = 3)
)
),
mainPanel(
plotOutput("samplingPlot")
)
)
)
server <- function(input, output) {
output$samplingPlot <- renderPlot({
if (input$method == "srs") {
build_srs(n = input$sampleSize, N = 100)
} else if (input$method == "stratified") {
build_stratified(N = 100, numStrata = input$numStrata, sampleSizePerStratum = input$sampleSizePerStratum)
} else if (input$method == "cluster") {
clusterSizeMin <- sample(5:30, 1)
clusterSizeMax <- sample((clusterSizeMin+5):50, 1)
clusterSizes <- sample(clusterSizeMin:clusterSizeMax, input$numClusters, replace = TRUE)
selectedClusters <- sample(1:input$numClusters, round(input$numClusters/3))
build_cluster(numClusters = input$numClusters, clusterSizes = clusterSizes, selectedClusters = selectedClusters)
} else if (input$method == "multistage") {
clusterSizeMin <- sample(5:30, 1)
clusterSizeMax <- sample((clusterSizeMin+5):50, 1)
clusterSizes <- sample(clusterSizeMin:clusterSizeMax, input$numClustersMultistage, replace = TRUE)
build_multistage(numClusters = input$numClustersMultistage, sampleSizePerCluster = input$sampleSizePerClusterMultistage, clusterSizes = clusterSizes)
}
})
}
shinyApp(ui, server)
```