Я хочу сгенерировать 5 блоков псевдослучайных двоичных последовательностей (для хранения в фрейме данных) со следующими условиями для каждого блока:
150 0 с
25 1с
Последовательность не может начинаться или заканчиваться цифрой 1.
1 должны быть разделены минимум одним 0 и максимум 12 0.
Это моя текущая (неудачная) попытка. Проблема здесь в том, что в нескольких случаях я получаю более 12 последовательных нулей, и это обычно происходит в конце блока. Меня не слишком беспокоит распределение, а только количество нулей, разделяющих единицы.
library(plyr)
library(EnvStats)
#>
#> Attaching package: 'EnvStats'
#> The following objects are masked from 'package:stats':
#>
#> predict, predict.lm
# variables
lure <- 1
target <- 0
nBlock <- 5
ntrialBlock <- 175
nTrial <- nBlock * ntrialBlock
nLureTrials <- 125
nTargets <- nTrial - nLureTrials
distMean <- 6.23
distSD <- 2.55
distLower <- 1
distUpper <- 12
# create trials and block numbers
block <- rep(1:nBlock, each=ntrialBlock)
trial <- 1:nTrial
# store in data frame for trial matrix
trialMatrix <- data.frame(block, trial)
# pseudorandomisation
nLureTrialsBlock <- nLureTrials/nBlock
lureMatrix <- ddply(trialMatrix, .(block), function(trialMatrix) {
lureMatrix <- data.frame()
blockSum <- 0
blockSet <- data.frame(x = numeric())
blockTotal <- 0
blockAg <- blockSum + (ntrialBlock*(trialMatrix[1,1]-1))
while ((nrow(blockSet) != nLureTrialsBlock) & (blockSum < (ntrialBlock-distUpper))) {
rand_draw <- round(rnorm(1, mean = distMean, sd = distSD))
# Append to array
blockSet[nrow(blockSet) + 1,] <- rand_draw
# Get number of congruent trials in this block
blockSum <- sum(blockSet)
# Get trial numbers which are congruent trials
# Take cumulative sum (keep adding prev trial)
blockTotal <- cumsum(blockSet)
blockAg <- blockSum + (ntrialBlock*(trialMatrix[1,1]-1))
}
blockSet <- cumsum(blockSet) + (ntrialBlock*(trialMatrix[1,1]-1))
lureMatrix <- rbind(lureMatrix, blockSet)
return(lureMatrix)
})
# store lures in trialMatrix
trialMatrix[lureMatrix$x, "lure"] <- 1
trialMatrix[is.na(trialMatrix)] <- 0
Created on 2024-06-19 with репрекс v2.1.0
Вы можете попробовать подход «грубой силы», который не займет много времени, чтобы добиться успеха. Функцию rle
можно использовать для определения длины последовательных значений.
data <- data.frame(block=rep(1:5, each=175), trial=seq(1, 175*5))
f <- function(n0, n1) {
x <- c(0,
sample(c(rep(0,148), rep(1,25)), size=173, replace=FALSE),
0) # initial guess
while(any(rle(x)$lengths[which(rle(x)$values==0)] > n0) ||
any(rle(x)$lengths[which(rle(x)$values==1)] > n1)) {
x <- c(0,
sample(c(rep(0,148), rep(1,25)), size=173, replace=FALSE),
0)
}
x
}
data <- dplyr::mutate(data, lure=f(n0=12, n1=1), .by=block)
Поскольку вы не указываете, сколько может быть ведущих или конечных нулей (их может быть больше 12), вы можете рассматривать проблему как случайную последовательность из 24 групп единиц, за которыми следуют от 1 до 12 нулей, затем единица, затем случайная ведущие и конечные нули до заполнения 75
Для одного столбца:
while (sum(x <- sample(2:13, 24, T)) > 175 - 3) {}
middle <- c(rep(rep(c(1,0), 24),t(cbind(1, x - 1))), 1)
leading <- rep(0, sample(175 - length(middle), 1))
trailing <- rep(0, 175 - length(middle) - length(leading))
c(leading, middle, trailing)
Вывод для столбца:
00100000001001000000010000100000000
10000000000100001000000100000100100
00001010001000100001000000000100100
00000000100000100001000010000000000
01000001000000000100000000000000000
затем цикл для каждого столбца.
ПД: я использовал set.seed(23921)
в начале программы
Вероятно, вы можете использовать rmultinom
, чтобы сделать это
n0s <- 150
n1s <- 25
max0len <- 12
repeat {
d <- rmultinom(1, n0s - 2 - (n1s + 1), rep(1, n1s + 1)) + 1 # distribution of `0`s (separated by `1`s, where total number of `0` is `n0s - 2` (excluding head and tail of the sequence), while guaranteeing one `0` at least
if (max(d) <= max0len) break # the max run length of `0`s shouldn't be greater than `12`
}
s <- rep(rep(c(0, 1), length.out = 2 * n1s + 1), c(d[1], rbind(1, d[-1])))
и вы можете получить такую последовательность s
например
> s
[1] 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0
[38] 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
[75] 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0
[112] 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1
[149] 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
@Эдвард, ага, спасибо за напоминание, я упустил из виду это условие. Смотрите мое обновление
А как насчет других критериев, согласно которым «1 должны быть разделены как минимум одним 0»?