如何将区间随机划分为不重叠、间隔相等的区间
How to randomly divide interval into non overlapping, spaced bins of equal length
我有一个间隔,例如从 1 到 671。我想将它分成 5 个随机的非重叠 bin,长度为 50,但间隔最小为 51。
interval <- 1:671 (example, it does not need to be 671)
结果(这是一个例子,因为 bins 应该是随机的,但在间隔内,等长和间隔如定义):
bin1 <- 3:52
bin2 <- 103:152
bin3 <- 209:258
bin4 <- 425:474
bin5 <- 610:659
我希望输出是数据帧(bin、startOfbin、endOfbin),但其他类型如列表也可以。
我目前正在用 R 编写一个函数,它将在大量间隔中使用此采样,但我无法提出合理的解决方案。提前谢谢你。
我不知道这是否具有所需的随机性:
interval <- 1:671
set.seed(42)
repeat { #rejection sampling
int <- list(interval)
s <- integer(5) * NA
for (i in 1:5) {
#sample an interval from the list
sel <- sample(length(int), 1)
isel <- int[[sel]]
#sample start value
s[[i]] <- sample(head(isel,-49), 1)
#remove sampled values from interval
sp <-
split(isel, findInterval(isel, c(0, s[[i]], s[[i]] + 50, Inf)))
if (s[[i]] > isel[1] &&
s[[i]] < length(isel) - 49)
sp <- sp[-2]
else
if (s[[i]] == isel[1])
sp <- sp[-1]
else
if (s[[i]] == length(isel) - 49)
sp <- head(sp,-1)
sp <- sp[lengths(sp) >= 50]
int <- c(sp, int[-sel])
#break out of for loop
#if not enough intervals of sufficient length left
if (length(int) < 1) break
}
if (!anyNA(s)) break
}
s
#[1] 321 74 245 170 441
library(ggplot2)
ggplot(data.frame(s = s, e = s + 49), aes(x = s, xend = e, y = 0, yend = 0)) +
geom_segment(size = 3) +
theme_minimal() +
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
panel.grid.major.y = element_blank()) +
xlab("") + ylab("")
如果我对您的问题的理解正确,您需要间隔的 5 个部分,长度为 50,最小距离为 51。
所以你的随机性在于每个距离比 51 大多少。
这意味着您要计算 space 实际需要分配的数量。
intervalLength <- 671
nBins <- 5
binWidth <- 50
binMinDistance <- 51
spaceToDistribute <- intervalLength - (nBins * binWidth + (nBins - 1) * binMinDistance)
计算这个值的随机拆分
distances <- diff(floor(c(0, sort(runif(nBins))) * spaceToDistribute))
并构建您想要的 data.frame
startOfBin <- cumsum(distances) + (0:(nBins-1)) * 101
result <- data.frame(bin = 1:nBins, startOfBin = startOfBin, endOfBin = startOfBin + 49)
类似这样的方法可行:
set.seed(111)
n_bins <- 5
bl <- 50
spacing <- 51
start <- 1
end <- 671
end_int <- end - n_bins*bl - (n_bins-1)*spacing
first_bin_start <- sample(start:end_int, 1)
first_bin_end <- first_bin_start + bl
avail_spacing <- end - first_bin_end - (n_bins-1)*bl - (n_bins-1)*spacing
sp <- c()
for (i in 1:(n_bins-1)){
end <- sample(1:avail_spacing, 1)
sp <- c(sp, end)
avail_spacing <- avail_spacing - end
}
bin_start <- c(first_bin_start, first_bin_start + cumsum(spacing + bl + sp))
bin_end <- bin_start + bl
df <- data.frame(bin = 1:n_bins,
bin_start = bin_start,
bin_end = bin_end)
df
我有一个间隔,例如从 1 到 671。我想将它分成 5 个随机的非重叠 bin,长度为 50,但间隔最小为 51。
interval <- 1:671 (example, it does not need to be 671)
结果(这是一个例子,因为 bins 应该是随机的,但在间隔内,等长和间隔如定义):
bin1 <- 3:52
bin2 <- 103:152
bin3 <- 209:258
bin4 <- 425:474
bin5 <- 610:659
我希望输出是数据帧(bin、startOfbin、endOfbin),但其他类型如列表也可以。
我目前正在用 R 编写一个函数,它将在大量间隔中使用此采样,但我无法提出合理的解决方案。提前谢谢你。
我不知道这是否具有所需的随机性:
interval <- 1:671
set.seed(42)
repeat { #rejection sampling
int <- list(interval)
s <- integer(5) * NA
for (i in 1:5) {
#sample an interval from the list
sel <- sample(length(int), 1)
isel <- int[[sel]]
#sample start value
s[[i]] <- sample(head(isel,-49), 1)
#remove sampled values from interval
sp <-
split(isel, findInterval(isel, c(0, s[[i]], s[[i]] + 50, Inf)))
if (s[[i]] > isel[1] &&
s[[i]] < length(isel) - 49)
sp <- sp[-2]
else
if (s[[i]] == isel[1])
sp <- sp[-1]
else
if (s[[i]] == length(isel) - 49)
sp <- head(sp,-1)
sp <- sp[lengths(sp) >= 50]
int <- c(sp, int[-sel])
#break out of for loop
#if not enough intervals of sufficient length left
if (length(int) < 1) break
}
if (!anyNA(s)) break
}
s
#[1] 321 74 245 170 441
library(ggplot2)
ggplot(data.frame(s = s, e = s + 49), aes(x = s, xend = e, y = 0, yend = 0)) +
geom_segment(size = 3) +
theme_minimal() +
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
panel.grid.major.y = element_blank()) +
xlab("") + ylab("")
如果我对您的问题的理解正确,您需要间隔的 5 个部分,长度为 50,最小距离为 51。
所以你的随机性在于每个距离比 51 大多少。
这意味着您要计算 space 实际需要分配的数量。
intervalLength <- 671
nBins <- 5
binWidth <- 50
binMinDistance <- 51
spaceToDistribute <- intervalLength - (nBins * binWidth + (nBins - 1) * binMinDistance)
计算这个值的随机拆分
distances <- diff(floor(c(0, sort(runif(nBins))) * spaceToDistribute))
并构建您想要的 data.frame
startOfBin <- cumsum(distances) + (0:(nBins-1)) * 101
result <- data.frame(bin = 1:nBins, startOfBin = startOfBin, endOfBin = startOfBin + 49)
类似这样的方法可行:
set.seed(111)
n_bins <- 5
bl <- 50
spacing <- 51
start <- 1
end <- 671
end_int <- end - n_bins*bl - (n_bins-1)*spacing
first_bin_start <- sample(start:end_int, 1)
first_bin_end <- first_bin_start + bl
avail_spacing <- end - first_bin_end - (n_bins-1)*bl - (n_bins-1)*spacing
sp <- c()
for (i in 1:(n_bins-1)){
end <- sample(1:avail_spacing, 1)
sp <- c(sp, end)
avail_spacing <- avail_spacing - end
}
bin_start <- c(first_bin_start, first_bin_start + cumsum(spacing + bl + sp))
bin_end <- bin_start + bl
df <- data.frame(bin = 1:n_bins,
bin_start = bin_start,
bin_end = bin_end)
df