0

如果我有这样的数据框,可以将其视为针对不同受访者的调查的响应

Data = 
ID Q1 Q2 Q3
1  A1 B2 C3
2  A2 B1 C2
3  A1 B2 C3
...

我还有以下分数表:

Q1 <- (c("A1", 10, "A2", 20, ...))
Q2 <- (c("B1", 10, "B2", 20, ...))
Q3 <- (c("C1", 10, "C2", 20, ...))

也就是说,如果我在 Q1 中选择“A1”,我会得到 10 分,如果我在 Q2 中选择“B2”,我会多获得 20 分,如果我在 Q3 中选择“C1”,也就是 10 分,我得到的总分是:10 (A1) + 20 (B2) + 10 (C1) = 40

现在对于数据中的每一行,我需要通过根据分数表对每列的分数求和来计算总分。

谁能建议我如何使用简单的代码来做到这一点?现在我只能想到将分数表放入 Xx2 矩阵中,并使用大量的嵌套 if 和 for 循环。

4

3 回答 3

1

数据:

Data <- read.table(text = "ID Q1 Q2 Q3
1  A1 B2 C3
2  A2 B1 C2
3  A1 B2 C3", header = TRUE)

Q1 <- c("A1", 10, "A2", 20)
Q2 <- c("B1", 10, "B2", 20)
Q3 <- c("C1", 10, "C2", 20)

首先,Q创建对象列表:

Qlist <- list(Q1 = Q1, Q2 = Q2, Q3 = Q3)

现在,sapply可以使用:

cbind(Data,
      QSum = rowSums(sapply(names(Qlist),
                            function(q)
                              as.numeric(Qlist[[q]][match(Data[[q]],
                                                          Qlist[[q]]) + 1])), 
                     na.rm = TRUE))

输出:

  ID Q1 Q2 Q3 QSum
1  1 A1 B2 C3   30
2  2 A2 B1 C2   50
3  3 A1 B2 C3   30
于 2012-11-23T10:52:54.007 回答
1
df <- read.table(text="ID Q1 Q2 Q3
1  A1 B2 C3
2  A2 B1 C2
3  A1 B2 C3",header=TRUE, stringsAsFactors=FALSE)

scores <- list(
Q1 = c("A1", 10, "A2", 20, "A3", 30),
Q2 =c("B1", 30, "B2", 10, "B3", 20),
Q3 =c("C1", 10, "C2", 30, "C3", 20)
)

#lookup table
scores <- do.call("cbind",scores)

#match
m <- apply(df[,-1],2,match,table=scores)

#look up
points <- matrix(as.numeric(scores[m+1]),ncol=ncol(df)-1)

#sum for each ID
result <- cbind(df,Score=rowSums(points))

  ID Q1 Q2 Q3 Score
1  1 A1 B2 C3    40
2  2 A2 B1 C2    80
3  3 A1 B2 C3    40
于 2012-11-23T11:00:11.243 回答
1

我将使用罗兰选择的“分数”。由于您提到可以将分数表更改为 2x2 矩阵,因此我提供了以下解决方案,该解决方案与其他 2 个解决方案的不同之处在于分数的数据结构不同。

在为您提供代码之前,请允许我解释一下逻辑:

  1. 我希望逐行处理 df
  2. 对于每一行,我希望将分数用于每个问题选择的答案
  3. 我想总结一下

基于 2,我觉得需要一个关联数组,我可以根据问题编号和输入的答案对其进行索引。因此,我为分数创建了以下表示:

> scores <- list(
+                 Q1 = list(A1=10,A2=20,A3=30),
+                 Q2 = list(B1=30,B2=10,B3=20),
+                 Q3 = list(C1=10,C2=30,C3=20)
+               )

基本上,分数现在是一个列表列表。通过这样做,我可以执行以下操作:

> scores[["Q1"]][["A1"]]
[1] 10

现在我需要做的就是找出一种方法来参数化上面的“Q1”和“A1”。

数据框“df”如下:

> df
  ID Q1 Q2 Q3
1  1 A1 B2 C3
2  2 A2 B1 C2
3  3 A1 B2 C3

我关心的是没有 ID 列的每一行。所以,我只提取:

> df[1,-1]
  Q1 Q2 Q3
1 A1 B2 C3

现在你可以看到我需要选择第一个索引的列名到分数和第二个索引的行中的值。因此,如果我能得到 score[[column-M]][[row-NvalueForColumn-M]] 那么我可以总结它们。

列名很容易获得,因此:

> columnNames <- colnames(df[1,-1])
> columnNames
[1] "Q1" "Q2" "Q3"

所以你做必要逻辑的最后一段代码是这样的:

> columnNames <- colnames(df[1,-1])
> score <- c(0,0,0)
> for (i in 1:length(df[1,-1]))
+ {
+     for (j in 1:length(columnNames))
+     {
+         score[i] <- score[i] + scores[[columnNames[j]]][[df[i,-1][[columnNames[j]]]]]
+     }
+ }
> final <- cbind(df,score)
> final
  ID Q1 Q2 Q3 score
1  1 A1 B2 C3    40
2  2 A2 B1 C2    80
3  3 A1 B2 C3    40
> 

我相信上面的代码可以减少至少 5 行(使用 rowsums 等)。我确信像 Sven 这样有经验的人可以将上面的代码改进到几行。将不胜感激输入。

于 2012-11-23T16:56:37.747 回答