'Random' 在 R 中根据条件对心理学研究进行排序

'Random' Sorting with a condition in R for Psychology Research

我在我的心理学实验中有词刺激的价类别。

1 = 负面,2 = 中性,3 = 正面

我需要用伪随机条件对数千个刺激进行排序。

Val_Category 不能连续有超过 2 个相同的效价刺激,即连续不能超过 2 倍的负刺激。

例如 - 2, 2, 2 = 不可接受

2, 2, 1 = 好的

我无法对数据进行排序,即决定整个实验将是 1,3,2,3,1,3,2,3,2,2,1 因为我不允许有一个模式.

我尝试了 dylpr、sample、order、sort 等各种包,但到目前为止都没有解决问题。

我认为有上千种方法可以做到这一点,none 其中可能非常漂亮。我写了一个小函数来处理排序。这有点 hacky,但它似乎对我的尝试有效。

为了解释我做了什么,该函数的工作原理如下:

  1. 从中获取化合价向量和样本。
  2. 如果发现序列大于所需长度,则(对于每个这样的序列)在 "somewhere else".
  3. 位置取该序列的最后一个值
  4. 查看问题是否解决。如果是这样,return 重新排序的向量。如果不是,则返回2.

# some vector of valences
val <- rep(1:3,each=50)

pseudoRandomize <- function(x, n){

  # take an initial sample
  out <- sample(val)
  # check if the sample is "bad" (containing sequences longer than n)
  bad.seq <- any(rle(out)$lengths > n)
  # length of the whole sample
  l0 <- length(out)

  while(bad.seq){
    # get lengths of all subsequences
    l1 <- rle(out)$lengths
    # find the bad ones
    ind <- l1 > n
    # take the last value of each bad sequence, and...
    for(i in cumsum(l1)[ind]){
      # take it out of the original sample
      tmp <- out[-i]
      # pick new position at random
      pos <- sample(2:(l0-2),1)
      # put the value back into the sample at the new position
      out <- c(tmp[1:(pos-1)],out[i],tmp[pos:(l0-1)])
    }
    # check if bad sequences (still) exist
    # if TRUE, then 'while' continues; if FALSE, then it doesn't
    bad.seq <- any(rle(out)$lengths > n)
  }
  # return the reordered sequence
  out

}

示例:

该函数可用于有名称或无名称的矢量。如果矢量被命名,那么这些名称仍将出现在伪随机化矢量上。

# simple unnamed vector
val <- rep(1:3,each=5)
pseudoRandomize(val, 2)

# gives:
# [1] 1 3 2 1 2 3 3 2 1 2 1 3 3 1 2

# when names assigned to the vector
names(val) <- 1:length(val)
pseudoRandomize(val, 2)

# gives (first row shows the names):
#  1 13  9  7  3 11 15  8 10  5 12 14  6  4  2 
#  1  3  2  2  1  3  3  2  2  1  3  3  2  1  1 

这个属性可用于随机化整个数据帧。为此,"valence" 向量被从数据框中取出,并通过行索引 (1:nrow(dat)) 或行名称 (rownames(dat)) 为其分配名称。

# reorder a data.frame using a named vector
dat <- data.frame(val=rep(1:3,each=5), stim=rep(letters[1:5],3))
val <- dat$val
names(val) <- 1:nrow(dat)

new.val <- pseudoRandomize(val, 2)
new.dat <- dat[as.integer(names(new.val)),]

# gives:
#    val stim
# 5    1    e
# 2    1    b
# 9    2    d
# 6    2    a
# 3    1    c
# 15   3    e
# ...

我相信这个循环会适当地设置化合价类别。我称化合价类别为 treat。

#Generate example data
s1 = data.frame(id=c(1:10),treat=NA)

#Setting the first two rows
s1[1,"treat"] <- sample(1:3,1)
s1[2,"treat"] <- sample(1:3,1)

#Looping through the remainder of the rows
for (i in 3:length(s1$id))
{
   s1[i,"treat"] <- sample(1:3,1)

   #Check if the treat value is equal to the previous two values.
   if (s1[i,"treat"]==s1[i-1,"treat"] & s1[i-1,"treat"]==s1[i-2,"treat"])

   #If so draw one of the values not equal to that value
   {
      a = 1:3
      remove <- s1[i,"treat"]
      a=a[!a==remove]
      s1[i,"treat"]  <- sample(a,1)
   }
}

这个解决方案不是特别优雅。可能有一种更快的方法可以通过对多列或其他内容进行排序来完成此操作。