我将几次调查的结果作为数据框给出,问题是列,答案是行。也就是说,数据框具有以下形式:
Q1 Q2 Q3 ... Qn
1 5 4 5 ... 2
2 5 5 NA ... 3
3 2 4 1 ... 2
4 3 3 3 ... 3
5 5 3 5 ... 1
...
问题(=列)的数量因调查而异(通常非常大),但如果答案总是在1到5之间的整数,或者如果没有给出答案则为NA。
我需要将此数据转换为(长格式)数据框,表示每个问题的给定答案的频率计数,即:
question value freq
Q1 1 12
Q1 2 41
Q1 3 123
Q1 4 231
Q1 5 401
Q2 1 11
Q2 2 32
Q2 3 122
Q2 4 321
Q2 5 173
...
然而,我无法想出实现这一目标的解决方案。我知道data.frame(table(survey$Q1))
种产生了我正在寻找的频率计数,但只针对一个问题。结合所有这些数据框"手工"对于每一个大量问题都是不可行的。在可能的情况下,我也在寻找一种相当普遍的解决方案,可以在我的不同调查中处理可变数量的问题。
在此先感谢,感谢任何帮助。
用于生成样本数据的代码段:
Q1 = c(5, 5, 2, 3, 5, 4, 3, 5, 2, 3)
Q2 = c(4, 5, 4, 3, 3, 5, 3, 5, 4, 3)
Q3 = c(5, NA, 1, 3, 5, 5, 2, 3, 5, 5)
Qn = c(2, 3, 2, 3, 1, NA, 3, 2, 3, 1)
survey <- data.frame(Q1,Q2,Q3,Qn)
答案 0 :(得分:4)
我们可以尝试将'wide'格式转换为'long'格式与melt
,转换为data.table(setDT
),得到nrows(.N
)分组'价值','变量'
library(reshape2)
library(data.table)
melt(setDT(survey), na.rm=TRUE)[, .N, by = list(variable,value)]
或base R
方法
subset(as.data.frame(table(stack(survey))), Freq!=0)
答案 1 :(得分:1)
您可以使用tidyr包创建长数据集,然后使用dplyr包创建子组计数:
library(tidyr)
library(dplyr)
long <- gather(survey, question, value, na.rm = TRUE)
long %>%
group_by(question, value) %>%
tally() %>% # populate the counts
arrange(question, value) # sort the results
答案 2 :(得分:1)
tabulate
在这里是一个很好的候选人。将其与lapply
和stack
结合使用,并使用cbind
添加1到5的指示符来表示您要查找的值。这是@ akrun的table
+ stack
方法的一个细微变化,如果你有很多行和很多列,这应该会更有效:
cbind(Val = 1:5, stack(lapply(survey, tabulate, nbins = 5)))
# Val values ind
# 1 1 0 Q1
# 2 2 2 Q1
# 3 3 3 Q1
# 4 4 1 Q1
# 5 5 4 Q1
# 6 1 0 Q2
# 7 2 0 Q2
# 8 3 4 Q2
# 9 4 3 Q2
# 10 5 3 Q2
# 11 1 1 Q3
# 12 2 1 Q3
# 13 3 2 Q3
# 14 4 0 Q3
# 15 5 5 Q3
# 16 1 2 Qn
# 17 2 3 Qn
# 18 3 4 Qn
# 19 4 0 Qn
# 20 5 0 Qn
您可以动态重命名列&#34;&#34;与setNames
:
cbind(Value = 1:5,
setNames(stack(lapply(survey, tabulate, nbins = 5)),
c("Freq", "Question")))
以下是基础比较的方法:
f1 <- function() cbind(Val = 1:5, stack(lapply(survey, tabulate, nbins = 5)))
f2 <- function() as.data.frame(table(stack(survey)))
f3 <- function() melt(as.data.table(survey), na.rm=TRUE)[, .N, by = list(variable,value)]
f4 <- function() {
long <- gather(survey, question, value, na.rm = TRUE)
long %>%
group_by(question, value) %>%
tally() %>% # populate the counts
arrange(question, value) # sort the results
}
library(tidyr)
library(dplyr)
library(data.table)
library(microbenchmark)
## A bigger dataset
set.seed(1)
survey <- data.frame(do.call(cbind, replicate(100, list(sample(c(1:5, NA), 10000, TRUE)))))
system.time(f2())
# user system elapsed
# 0.801 0.000 0.802
system.time(f4())
# user system elapsed
# 0.261 0.000 0.268
microbenchmark(f1(), f3()) # The warnings are from `melt`
# Unit: milliseconds
# expr min lq mean median uq max neval
# f1() 2.96567 3.772974 5.157065 4.16065 4.793876 13.51471 100
# f3() 23.79500 77.893235 91.029498 87.22616 102.263556 147.69982 100
# There were 50 or more warnings (use warnings() to see the first 50)