使用 R 中的 for 循环确定来自 Qualtrics 的随机集中项目的顺序

Determining order of item in randomized set from Qualtrics using a for loop in R

在我的一项 Qualtrics 调查中,每位参与者都会收到一组随机排列的问题。

我现在想确定一个问题(参见 table 中的 "Question" 变量)在参与者的随机问题顺序中的位置。缩短示例中的问题编号为 I1、I2 或 I3。

现在对数据进行组织,以便有与顺序相对应的列(在下面的简短示例中,"B1"、"B2" 和 "B3")。也就是说,B1 列中的问题首先出现在该参与者身上。

这是一个数据文件 (https://drive.google.com/open?id=1h18SlQ-gmRUZh93M5Y5T3TuE22yxSJbU),这是在 R 中打印出来的样子:

> head(testd)
  Question B1 B2 B3
1       I1 I1 I2 I3
2       I1 I3 I2 I1
3       I2 I2 I3 I1
4       I2 I3 I1 I2
5       I3 I2 I1 I3
6       I3 I1 I3 I2

我现在想写一个 for 循环来在数据框 testd 中创建一个新变量 "RandomizedOrder",它会告诉我 "Question" 列(例如 I1)中的问题是否针对参与者第一个 (B1)、第二个 (B2) 或第三个 (B3)。例如,在上面的示例中,第 1 行的 RandomizedOrder 应该是 B1,因为列 "Question" 中的值是 I1,而列 "B1" 中的值是 I1。

为此,我首先将值 "B1"、"B2" 和 "B3" 连接在 "BSet" 中。

testd <- read.csv("TestData.csv")
BSet <- c("B1", "B2", "B3")
testd[BSet]

然后我写了下面的for循环。我的目标:对于每一行 i,如果三个 BSet 列之一中的某个值与问题列中的值相同,则该行的变量 RandomizedOrder 应采用其中一个值的列名B设置与问题列中的值相同的列。

例如,如果第 1 行中的 testd$B1 = I1,并且第 1 行中的 testd$Question = I1,则此 for 循环应使 testd$RandomizedOrder 等于 B1。

for (i in nrow(testd)) {
  for (j in 1:3) {
    if (testd[i,BSet][[j]] == testd$Question[i]) {
      testd$RandomizedOrder[i] <- colnames(testd[i,BSet][j])
    }
  }
}

这就是 R 输出的样子。

> head(testd$RandomizedOrder)
[1] NA   NA   NA   NA   NA   "B2"

我不确定为什么它会为除第 6 项以外的所有内容生成 NA 值。

这是我希望 for 循环执行的操作:创建一个名为 "RandomizedOrder" 的新变量,该变量指示每一行的哪一列包含在 "Question" 列中找到的值。

      Question B1 B2 B3 RandomizedOrder
    1       I1 I1 I2 I3 B1
    2       I1 I3 I2 I1 B3
    3       I2 I2 I3 I1 B2
    4       I2 I3 I1 I2 B3
    5       I3 I2 I1 I3 B3
    6       I3 I1 I3 I2 B2

我查看了代码以确保各个部分都能正常工作。

这里的代码结果为真(等号两边都产生值 I1):

testd[1,BSet][[1]] == testd$Question[1] [1] TRUE

我也可以手动告诉 R 用列名替换 testd$RandomizedOrder 中的值。

> testd$RandomizedOrder[1] <- colnames(testd[1,BSet][1])
> head(testd$RandomizedOrder)
[1] "B1" NA   NA   NA   NA   "B2"

有人可以帮我确定为什么 for 循环不起作用吗?

提前致谢。

(请注意,对于具有 6 个观察值的数据集,这似乎可以很容易地手动完成,但这是我的真实数据集的简化示例。我的实际数据集有 48 个问题(即 I1 到 I48) , 以及数百个观察结果。因此,我使用字母 j 对 BSet 表示的列数进行了索引。)

考虑 lapply 跨数据框列名称进行匹配,然后是 Reduce 进行 coalesce method 以将所有列减少为一个 RandomizedOrder作业。

txt = "Question B1 B2 B3
1       I1 I1 I2 I3
2       I1 I3 I2 I1
3       I2 I2 I3 I1
4       I2 I3 I1 I2
5       I3 I2 I1 I3
6       I3 I1 I3 I2"

testd <- read.table(text=txt, header=TRUE)

colList <-  lapply(names(testd)[-1], function(i)
  ifelse(testd$Question == testd[[i]], i, NA))

testd$RandomizedOrder <- Reduce(function(x, y) {
  x[which(is.na(x))] <- y[which(is.na(x))]
  x}, colList)

testd    
#   Question B1 B2 B3 RandomizedOrder
# 1       I1 I1 I2 I3              B1
# 2       I1 I3 I2 I1              B3
# 3       I2 I2 I3 I1              B1
# 4       I2 I3 I1 I2              B3
# 5       I3 I2 I1 I3              B3
# 6       I3 I1 I3 I2              B2