R中的双向列联表

R中的双向列联表,r,two-way,contingency,R,Two Way,Contingency,我有一个dataframe,我想从两列中输出一个双向列联表。他们都有“太少”、“差不多正确”或“太多”的价值观 我在打字 df %>% filter(!is.na(col1)) %>% group_by(col1) %>% summarise(count = n()) 分别为这两种类型,并获得如下内容: col1 count <fctr> <int> Too Little 19259 Abou

我有一个dataframe,我想从两列中输出一个双向列联表。他们都有“太少”、“差不多正确”或“太多”的价值观

我在打字

df %>%
  filter(!is.na(col1)) %>%
  group_by(col1) %>%
  summarise(count = n())
分别为这两种类型,并获得如下内容:

col1        count
<fctr>      <int>
Too Little  19259           
About Right 9539            
Too Much    2816    
我一直在尝试使用table函数

addmargins(table(df$col1, df$col2))
但结果不是我想要的

              Too Little About Right Too Much   Sum
  Too Little       13770        4424      740 18934
  About Right       4901        3706      700  9307
  Too Much          1250         800      679  2729
  Sum              19921        8930     2119 30970

我会给出<代码>表格>代码>一个尝试,这是<代码>表< /代码>的基础(参见<代码>表制表< /代码>)。举个例子

set.seed(123)
vals <- LETTERS[1:3]
df <- as.data.frame(replicate(3, sample(vals, 5, T)))
df <- data.frame(lapply(df, "levels<-", vals))

我会给出<代码>表格>代码>一个尝试,这是<代码>表< /代码>的基础(参见<代码>表制表< /代码>)。举个例子

set.seed(123)
vals <- LETTERS[1:3]
df <- as.data.frame(replicate(3, sample(vals, 5, T)))
df <- data.frame(lapply(df, "levels<-", vals))

我们可以在循环中使用table,然后使用rbind:

# Using dummy data from @lukeA's answer

addmargins(do.call(rbind, lapply(df1, table)))
#     A B C Sum
# V1  1 1 3   5
# V2  1 3 1   5
# V3  1 2 2   5
# Sum 3 6 6  15

基准测试

# bigger data
set.seed(123)
vals <- LETTERS[1:20]
df1 <- as.data.frame(replicate(20, sample(vals, 100000, T)))
df1 <- data.frame(lapply(df1, "levels<-", vals))


microbenchmark::microbenchmark(
  lukeA = {
    m1 <- t(sapply(df1, tabulate, nbins = length(vals)))
    colnames(m1) <- vals
    m1 <- addmargins(m1)
  },
  # as vals only used for luke's solution, keep it in.
  lukeA_1 = {
    vals <- LETTERS[1:20]
    m2 <- t(sapply(df1, tabulate, nbins = length(vals)))
    colnames(m2) <- vals
    m2 <- addmargins(m2)
  },
  thelatemail = {m3 <- addmargins(t(sapply(df1, table)))}, 
  zx8754 = {m4 <- addmargins(do.call(rbind, lapply(df1, table)))}
)
# Unit: milliseconds
#        expr       min        lq      mean    median        uq        max neval
#       lukeA  2.349969  2.371922  2.518447  2.473839  2.558653   3.363738   100
#     lukeA_1  2.351680  2.377196  2.523473  2.473839  2.542831   3.459242   100
# thelatemail 38.316506 42.054136 43.785777 42.674912 44.234193  90.287809   100
#      zx8754 38.695101 41.979728 44.933602 42.762006 44.244314 110.834292   100
#更大的数据
种子集(123)

VAL我们可以在循环中使用表,然后使用rbind:

# Using dummy data from @lukeA's answer

addmargins(do.call(rbind, lapply(df1, table)))
#     A B C Sum
# V1  1 1 3   5
# V2  1 3 1   5
# V3  1 2 2   5
# Sum 3 6 6  15

基准测试

# bigger data
set.seed(123)
vals <- LETTERS[1:20]
df1 <- as.data.frame(replicate(20, sample(vals, 100000, T)))
df1 <- data.frame(lapply(df1, "levels<-", vals))


microbenchmark::microbenchmark(
  lukeA = {
    m1 <- t(sapply(df1, tabulate, nbins = length(vals)))
    colnames(m1) <- vals
    m1 <- addmargins(m1)
  },
  # as vals only used for luke's solution, keep it in.
  lukeA_1 = {
    vals <- LETTERS[1:20]
    m2 <- t(sapply(df1, tabulate, nbins = length(vals)))
    colnames(m2) <- vals
    m2 <- addmargins(m2)
  },
  thelatemail = {m3 <- addmargins(t(sapply(df1, table)))}, 
  zx8754 = {m4 <- addmargins(do.call(rbind, lapply(df1, table)))}
)
# Unit: milliseconds
#        expr       min        lq      mean    median        uq        max neval
#       lukeA  2.349969  2.371922  2.518447  2.473839  2.558653   3.363738   100
#     lukeA_1  2.351680  2.377196  2.523473  2.473839  2.542831   3.459242   100
# thelatemail 38.316506 42.054136 43.785777 42.674912 44.234193  90.287809   100
#      zx8754 38.695101 41.979728 44.933602 42.762006 44.244314 110.834292   100
#更大的数据
种子集(123)

那么你希望得到什么呢?欢迎来到这里,以一种形式提问是很重要的。此外,请始终尝试包含一些示例数据(目前没有人,但您可以看到
df
),也许只有几行就足以作为一个最小的示例。因此,您希望得到什么样的结果?欢迎使用,因此,以表格形式提问很重要。另外,请始终尝试包含一些示例数据(目前没有人,但您可以看到
df
),可能仅几行就足以作为一个最小的示例。我不知道您为什么需要特别的
制表。只需
addmargins(t(sapply(df,table))
就可以了,并且会保留名称。@最后一封邮件是真的,谢谢。我添加了这个。(虽然它可能与zx8754的解决方案太相似了,但现在…)不,做
sapply
比查找列表更简单。@LateMail在我的文章中添加了基准测试,lukeA的解决方案取得了成功,速度快了20倍。我不知道你为什么特别需要
tablate
。只需
addmargins(t(sapply(df,table))
就可以了,并且可以保留名称。@LateMail是真的,谢谢。我添加了这个。(虽然它可能与zx8754的解决方案太相似了,但现在…)不,做
sapply
比rbind一个列表更简单。@最近的邮件在我的帖子中添加了基准测试,lukeA的解决方案比这快了20倍。无论如何它肯定更快,但你的基准测试忽略了一个事实,
vals
并不总是提前知道的(或者至少不应该被认为是已知的)。所以你必须抛弃一个
vals@thelatemail True,也许它甚至应该是
vals,不管怎样它肯定更快,但是你的基准测试忽略了一个事实,
vals
并不总是提前知道(或者至少不应该被认为是已知的)所以你必须扔掉一个
vals@thelatemail True,也许它甚至应该是
vals