我正在研究一个项目,并且输入的表格中的一种还不太适合分析,因此我试图对其进行重组。当前,每一行都是考生,每一列都是他们错误回答的问题,以升序输入。因此,对于第一行,条目可以分别读取第一,第二和第三列的“ Q1”,“ Q3”,“ Q9”等。总共有25个问题。
我的目标是重组数据,以便每个问题都有一列。如果考生正确回答了该问题,则相应列的条目为1,否则为0。
似乎有一种蛮力的方法。可以分别更改每列并检查每列中的每个值。但是,这里有25个问题,所有这些键入似乎效率都很低,所以我怀疑必须有更好的方法。
蛮力代码类似于:
df %>%
mutate(Q3 == ifelse(col1 == "Q3" | col2 == "Q3" | col3 == "Q3", 0, 1))
这里,col1,col2,col3都是可能包含Q3的所有列,这可能是测试者弄错了的问题。如果其中有一个,我们输入0。否则,我们输入1。
有25个问题,代码变得太长。
编辑:数据框的示例如下所示。
sample <- "ID Col1 Col2 Col3 Col4
1 100 Q1
2 101 Q3 Q4
3 102 Q2 Q3 Q4
4 103
5 104 Q4
6 105 Q1 Q2 Q3 Q4 "
所需的输出如下:
sample <- "ID Q1 Q2 Q3 Q4
1 100 0 1 1 1
2 101 1 1 0 0
3 102 1 0 0 0
4 103 1 1 1 1
5 104 1 1 1 0
6 105 0 0 0 0 "
答案 0 :(得分:3)
这是我的解决方案-将数据从宽变长然后再返回
s <- reshape2::melt(sample, id.vars = "ID", value.name = "Q")
s$variable <- 1
s <- subset(s, complete.cases(s))
s <- reshape(s, idvar = "ID", timevar = "Q", direction = "wide")
s <- apply(s, 2, function(x) ifelse(is.na(x), 0, x))
答案 1 :(得分:2)
1)假设DF
如注释中的可重复显示,请使用sapply
创建指标矩阵,然后cbind
移至ID
列。最后,使名称更好。不使用任何软件包。
ques <- function(i) paste0("Q", 1:25) %in% unlist(DF[i, -1])
DFout <- cbind(DF[1], +t(sapply(1:nrow(DF), ques)))
names(DFout)[-1] <- paste0("Q", names(DFout[-1]))
前5列是:
> DFout[1:5]
ID Q1 Q2 Q3 Q4
1 100 1 0 0 0
2 101 0 0 1 1
3 102 0 1 1 1
4 103 0 0 0 0
5 104 0 0 0 1
6 105 1 1 1 1
2)另一种可能性是将输入转换为长格式,然后使用xtabs
从中创建表。
library(dplyr)
library(tidyr)
tab <- DF %>%
gather(key, Question, -ID) %>%
filter(nzchar(Question)) %>%
mutate(Question = factor(Question, paste0("Q", 1:25))) %>%
xtabs(~ ID + Question, .)
提供此表。我们显示前5列:
> tab[, 1:5]
Question
ID Q1 Q2 Q3 Q4
100 1 0 0 0
101 0 0 1 1
102 0 1 1 1
104 0 0 0 1
105 1 1 1 1
如果将结果作为数据框非常重要,则添加:
library(tibble)
tab %>%
as.data.frame.matrix %>%
rownames_to_column(var = "ID")
sample <- "rows ID Col1 Col2 Col3 Col4
1 100 Q1
2 101 Q3 Q4
3 102 Q2 Q3 Q4
4 103
5 104 Q4
6 105 Q1 Q2 Q3 Q4"
DF <- read.table(text = sample, header = TRUE, fill = TRUE, as.is = TRUE,
strip.white = TRUE)[-1]
答案 2 :(得分:2)
@ G.Grothendieck提供了一个非常好的解决方案。这是该答案的一种变体,即使每个学生都正确回答了该问题,它也会为测试中的每个问题产生价值。诚然,它不那么优雅。另外请注意,我使用缺失值而不是空字符串来构造数据,因此过滤器略有不同
x y
0 A NaN
1 A NaN
2 A NaN
3 B 5.0
4 B NaN
5 B NaN
6 B NaN
7 C 10.0
8 C NaN
9 C NaN
10 C NaN
答案 3 :(得分:2)
这是一种与其他方法类似的转换为长优先方法,但使用data.table
library(data.table)
setDT(df)
dcast(melt(df, 'ID'), ID ~ value, fun.aggregate = length)[, V1 := NULL][]
# ID Q1 Q2 Q3 Q4
# 1: 100 1 0 0 0
# 2: 101 0 0 1 1
# 3: 102 0 1 1 1
# 4: 104 0 0 0 1
# 5: 105 1 1 1 1
答案 4 :(得分:0)
这是一种使用简单的for循环的方法。
让我们从上方获取这些数据:
sample <- "rows ID Col1 Col2 Col3 Col4
1 100 Q1
2 101 Q3 Q4
3 102 Q2 Q3 Q4
4 103
5 104 Q4
6 105 Q1 Q2 Q3 Q4"
DF <- read.table(text = sample, header = TRUE, fill = TRUE, as.is = TRUE,
strip.white = TRUE)[-1]
这是方法。它将填充现有数据框,以再次检查重新编码是否顺利:
vars <- paste0("Q", 1:4)
for (i in vars){
DF[i] = rowSums(ifelse(DF[, grep( "Col", names(DF))]==i, 1, 0))
}
随后可以删除不需要的列:
DF <- DF[, -grep( "Col", names(DF))]