如何将调查数据行转换为(长格式)频率计数?

时间:2015-03-25 19:09:04

标签: r

我将几次调查的结果作为数据框给出,问题是列,答案是行。也就是说,数据框具有以下形式:

  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)

3 个答案:

答案 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在这里是一个很好的候选人。将其与lapplystack结合使用,并使用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)