如何在R中对一个扁平化列联表进行子集操作而不丢失行和列名称?

10

我使用ftable创建平面列联表。然而,当我对列联表进行子集操作时,R会删除行和列的名称。有没有办法对表进行子集操作,使得子集的表中仍保留行和列的名称?这是一个示例:

# Create fake data
Group1 = sample(LETTERS[1:3], 20, replace=TRUE)
Group2 = sample(letters[1:3], 20, replace=TRUE)
Year = sample(c("2010","2011","2012"), 20, replace=TRUE)
df1 = data.frame(Group1, Group2, Year)

# Create flat contingency table with column margin
table1 = ftable(addmargins(table(df1$Group1, df1$Group2, df1$Year), margin=3))

# Select rows with sum greater than 2
table2 = table1[table1[ ,4] > 2, ]

> table1
     2010 2011 2012 Sum

A a     0    1    2   3
  b     2    1    0   3
  c     0    0    0   0
B a     0    1    1   2
  b     2    0    0   2
  c     1    0    1   2
C a     0    1    0   1
  b     1    0    2   3
  c     3    0    1   4

> table2
     [,1] [,2] [,3] [,4]
[1,]    0    1    2    3
[2,]    2    1    0    3
[3,]    1    0    2    3
[4,]    3    0    1    4

请注意,R已经将子集表格转换为矩阵,剥离了列名和两个层级的行名。我如何保留子集表格的ftable结构?

3个回答

4
结果不再是一个 ftable 对象, 因为一些组合缺失。
但是您可以使用具有行和列名称的矩阵。
ftable_names <- function(x, which="row.vars") {
  # Only tested in dimensions 1 and 2
  rows <- as.vector(Reduce( 
    function(u,v) t(outer(as.vector(u),as.vector(v),paste)), 
    attr(x, which), 
    "" 
  ))
}
i <- table1[ ,4] > 2
table2 <- table1[i,]
rownames(table2) <- ftable_names(table1, "row.vars")[i]
colnames(table2) <- ftable_names(table1, "col.vars")
table2

#      2010  2011  2012  Sum
# A a     1     2     0    3
# A c     0     0     3    3
# B c     0     3     0    3
# C a     3     1     1    5

4
考虑使用频率数据框架进行工作,这是一种更好的数据结构,尤其是如果您要对其进行筛选。以下是使用reshape包构建频率数据框架的方法。
# cast the data into a data.frame
library(reshape)
df1$Freq <- 1
df2 <- cast(df1, Group1 + Group2 ~ Year, fun = sum, value = "Freq")
df2
#   Group1 Group2 2010 2011 2012
# 1      A      a    0    0    1
# 2      A      b    1    1    3
# 3      A      c    0    0    1
# 4      B      a    1    2    0
# 5      B      b    1    1    0
# 6      B      c    0    0    1
# 7      C      a    2    0    1
# 8      C      b    2    0    0
# 9      C      c    0    0    2

# add a column for the `Sum` of frequencies over the years
df2 <- within(df2, Sum <- `2010` + `2011` + `2012`)
df2
#   Group1 Group2 2010 2011 2012 Sum
# 1      A      a    0    0    1   1
# 2      A      b    1    1    3   5
# 3      A      c    0    0    1   1
# 4      B      a    1    2    0   3
# 5      B      b    1    1    0   2
# 6      B      c    0    0    1   1
# 7      C      a    2    0    1   3
# 8      C      b    2    0    0   2
# 9      C      c    0    0    2   2

df2[df2$Sum > 2, ]
#   Group1 Group2 2010 2011 2012 Sum
# 2      A      b    1    1    3   5
# 4      B      a    1    2    0   3
# 7      C      a    2    0    1   3

3

ftable 创建“平坦”的列联表,通过将数据重新排列为[2D]矩阵。因此,在子集化之前,只需使用as.matrix将数据转换为矩阵(如果直接使用as.table,则数据返回到其更高维度结构)。

# Create flat contingency table with column margin and variable names
table1 <- ftable(addmargins(table(Group1 = df1$Group1, 
                                 Group2 = df1$Group2, 
                                 Year = df1$Year), margin=3))

# Convert to matrix
mat1 <- as.matrix(table1)
mat2 <- mat1[mat1[ ,4] > 2, ]
mat2

> mat2
             Year
Group1_Group2 2010 2011 2012 Sum
          A_b    3    0    0   3
          A_c    0    2    3   5
          B_b    2    0    1   3

如果你真的不喜欢下划线 "_", 那么可以使用 gsub 进行替换。
dimnames(mat2) <- rapply(dimnames(mat2), gsub, pattern = "_", replacement = " ", how = "replace")

编辑

或者使用 dplyrtidyr 包来增强代码的灵活性和可读性:

library(dplyr)
library(tidyr)

df1 %>% 
  group_by(Group1, Group2, Year) %>%
  tally() %>%
  spread(Year, n, fill = 0) %>%
  ungroup() %>% 
  mutate(Sum = rowSums(.[-(1:2)])) %>%
  filter(Sum > 2) %>%
  unite(Name, c(Group1, Group2), sep = " ")

Source: local data frame [5 x 5]

   Name  2010  2011  2012   Sum
  (chr) (dbl) (dbl) (dbl) (dbl)
1   A a     2     1     0     3
2   A b     1     1     1     3
3   B b     2     0     2     4
4   B c     1     2     0     3
5   C a     1     2     0     3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接