Я хочу смоделировать некоторые несбалансированные кластеризованные данные. Количество кластеров равно 20, а среднее количество наблюдений равно 30. Однако я хотел бы создать несбалансированные кластеризованные данные для каждого кластера, где наблюдений на 10% больше, чем указано (т. е. 33, а не 30). Затем я хочу случайным образом исключить соответствующее количество наблюдений (т. е. 60), чтобы получить указанное среднее количество наблюдений на кластер (т. е. 30). Вероятность исключения наблюдения в каждом кластере была неравномерной (т. е. в некоторых кластерах не было удалено случаев, а в других было исключено больше). Таким образом, в итоге у меня осталось 600 наблюдений. Кто-нибудь знает, как реализовать это в R? Вот меньший пример набора данных. Однако количество наблюдений на кластер не соответствует условию, указанному выше, я просто использовал это, чтобы передать свою идею.
> y <- rnorm(20)
> x <- rnorm(20)
> z <- rep(1:5, 4)
> w <- rep(1:4, each=5)
> df <- data.frame(id=z,cluster=w,x=x,y=y) #this is a balanced dataset
> df
id cluster x y
1 1 1 0.30003855 0.65325768
2 2 1 -1.00563626 -0.12270866
3 3 1 0.01925927 -0.41367651
4 4 1 -1.07742065 -2.64314895
5 5 1 0.71270333 -0.09294102
6 1 2 1.08477509 0.43028470
7 2 2 -2.22498770 0.53539884
8 3 2 1.23569346 -0.55527835
9 4 2 -1.24104450 1.77950291
10 5 2 0.45476927 0.28642442
11 1 3 0.65990264 0.12631586
12 2 3 -0.19988983 1.27226678
13 3 3 -0.64511396 -0.71846622
14 4 3 0.16532102 -0.45033862
15 5 3 0.43881870 2.39745248
16 1 4 0.88330282 0.01112919
17 2 4 -2.05233698 1.63356842
18 3 4 -1.63637927 -1.43850664
19 4 4 1.43040234 -0.19051680
20 5 4 1.04662885 0.37842390
После случайного добавления и удаления некоторых данных несбалансированные данные становятся такими:
id cluster x y
1 1 1 0.895 -0.659
2 2 1 -0.160 -0.366
3 1 2 -0.528 -0.294
4 2 2 -0.919 0.362
5 3 2 -0.901 -0.467
6 1 3 0.275 0.134
7 2 3 0.423 0.534
8 3 3 0.929 -0.953
9 4 3 1.67 0.668
10 5 3 0.286 0.0872
11 1 4 -0.373 -0.109
12 2 4 0.289 0.299
13 3 4 -1.43 -0.677
14 4 4 -0.884 1.70
15 5 4 1.12 0.386
16 1 5 -0.723 0.247
17 2 5 0.463 -2.59
18 3 5 0.234 0.893
19 4 5 -0.313 -1.96
20 5 5 0.848 -0.0613
РЕДАКТИРОВАТЬ
Эта часть проблемы решена (спасибо jay.sf). Затем я хочу повторить этот процесс 1000 раз и выполнить регрессию для каждого сгенерированного набора данных. Однако я не хочу запускать регрессию для всего набора данных, а скорее для некоторых выбранных кластеров, причем кластеры выбираются случайным образом (можно использовать эту функцию: df[unlist(cluster[sample.int(k, k, replace = TRUE)], use.names = TRUE), ]
. В конце концов, я хотел бы получить доверительные интервалы из этих 1000 регрессий. Как действовать?
Пусть ncl
будет желаемым количеством кластеров. Мы можем сгенерировать пространство выборки S
, которое представляет собой последовательность толерантности tol
вокруг среднего значения наблюдений на кластер mnobs
. Из этого мы берем repeat
еже случайную выборку размера 1, чтобы получить список кластеров CL
. Если сумма кластера lengths
соответствует ncl*mnobs
, мы break
цикл, добавляем случайные данные в кластеры и rbind
результат.
FUN <- function(ncl=20, mnobs=30, tol=.1) {
S <- do.call(seq.int, as.list(mnobs*(1 + tol*c(-1, 1))))
repeat({
CL <- lapply(1:ncl, function(x) rep(x, sample(S, 1, replace=T)))
if (sum(lengths(CL)) == ncl*mnobs) break
})
L <- lapply(seq.int(CL), function(i) {
id <- seq.int(CL[[i]])
cbind(id, cluster=i,
matrix(rnorm(max(id)*2),,2, dimnames=list(NULL, c("x", "y"))))
})
do.call(rbind.data.frame, L)
}
Применение
set.seed(42)
res <- FUN() ## using defined `arg` defaults
dim(res)
# [1] 600 4
(res.tab <- table(res$cluster))
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# 29 29 31 31 30 32 31 30 32 28 28 27 28 31 32 33 31 30 27 30
table(res.tab)
# 27 28 29 30 31 32 33
# 2 3 2 4 5 3 1
sapply(c("mean", "sd"), function(x) do.call(x, list(res.tab)))
# mean sd
# 30.000000 1.747178
Отображаемый пример
set.seed(42)
FUN(4, 5, tol=.3) ## tol needs to be adjusted for smaller samples
# id cluster x y
# 1 1 1 1.51152200 -0.0627141
# 2 2 1 -0.09465904 1.3048697
# 3 3 1 2.01842371 2.2866454
# 4 1 2 -1.38886070 -2.4404669
# 5 2 2 -0.27878877 1.3201133
# 6 3 2 -0.13332134 -0.3066386
# 7 4 2 0.63595040 -1.7813084
# 8 5 2 -0.28425292 -0.1719174
# 9 6 2 -2.65645542 1.2146747
# 10 1 3 1.89519346 -0.6399949
# 11 2 3 -0.43046913 0.4554501
# 12 3 3 -0.25726938 0.7048373
# 13 4 3 -1.76316309 1.0351035
# 14 5 3 0.46009735 -0.6089264
# 15 1 4 0.50495512 0.2059986
# 16 2 4 -1.71700868 -0.3610573
# 17 3 4 -0.78445901 0.7581632
# 18 4 4 -0.85090759 -0.7267048
# 19 5 4 -2.41420765 -1.3682810
# 20 6 4 0.03612261 0.4328180
@cliu Конечно, мы можем найти специальные пакеты с функциями практически для любой конкретной проблемы. Однако научиться делать что-то с нуля может быть более устойчивым, и это предотвращает зависимость :)
Привет @jay.sf. Извините, что я снова прошу вашей помощи, но я только что отредактировал свой вопрос с обновленной задачей запуска регрессии на сгенерированных кластеризованных данных. Не могли бы вы поделиться кодом реализации? Основываясь на вашем ответе на другой вопрос, я написал это, но функция кажется исправленной и не изменится, когда я позже replicate
это: BetaClus <- function() { clsamp.reg <- df[unlist(cluster[sample.int(k, k, replace = TRUE)], use.names = TRUE), ] x <- unlist(clsamp.reg["x"]) y <- unlist(clsamp.reg["y"]) clusmod <- lm(y ~ x) confint(clusmod, "x", level = 0.95)}
. Спасибо!
@cliu, можешь опубликовать свое решение в качестве ответа?
@BenBolker Конечно
По запросу Бена Болкера я публикую свое решение, но см. jay.sf для получения более обобщенного ответа.
#First create an oversampled dataset:
y <- rnorm(24)
x <- rnorm(24)
z <- rep(1:6, 4)
w <- rep(1:4, each=6)
df <- data.frame(id=z,cluster=w,x=x,y=y)
#Then just slice_sample to arrive at the sample size as desired
df %>% slice_sample(n = 20) %>%
arrange(cluster)
#Or just use base R
a <- df[sample(nrow(df), 20), ]
df2 <- a[order(a$cluster), ]
Спасибо за подробный ответ @jay.sf, как всегда! На самом деле я нашел «кажущийся» быстрый ответ на вопрос: сначала просто передискретизировать, а затем
slice_sample
получить желаемый размер выборки.