【问题标题】:Summary of values across rows and columns in RR中跨行和列的值摘要
【发布时间】:2016-12-08 14:48:43
【问题描述】:

我有一个如下所示的数据集:

Group   A    B    C    D
XYZ     4    Na   1    3
XYZ     Na   2    2    1
DEF     4    3    2    1
DEF     3    3    1    1
PQR     1    Na   Na   1
PQR     3    2    2    4

我想要跨行和列的该数据集的摘要,以获取每个值的计数,如下所示:

Group   4    3    2    1
XYZ     1    1    2    2
DEF     1    3    1    3
PQR     1    1    2    2

数据集中所有行和列中组 XYZ 的计数为 1,对于 2 和 1 是 2,对于 3 是 1。我可以通过创建 4 个新列 4、3、2、1 和逐行计数,然后逐列计数,但这既不高效也不可扩展。我确信有更好的方法来完成这项工作。

【问题讨论】:

    标签: r


    【解决方案1】:

    使用reshape2包我们可以melt和dcast如下,

    library(reshape2)
    dcast(na.omit(melt(df, id.vars = 'Group')), Group ~ value, fun.aggregate = length)
    #  Group 1 2 3 4
    #1   DEF 3 1 3 1
    #2   PQR 2 2 1 1
    #3   XYZ 2 2 1 1
    

    【讨论】:

      【解决方案2】:

      这不使用任何包,只有一行。这里DF$Group[row(DF[-1])] 是一个组标签向量,每个元素对应于解开的数字向量unlist(DF[-1])。

      table(DF$Group[row(DF[-1])], unlist(DF[-1]))
      

      给予:

            1 2 3 4
        DEF 3 1 3 1
        PQR 2 2 1 1
        XYZ 2 2 1 1
      

      如果问题中显示的行和列的顺序很重要,那么我们可以从两个 table 参数中的每一个创建因子,并按照所需的顺序定义因子级别。在这种情况下,我们使用以下代码行而不是上面的代码行:

      table(Group = factor(DF$Group[row(DF[-1])], unique(DF$Group)), factor(unlist(DF[-1]), 4:1))
      

      给予:

      Group 4 3 2 1
        XYZ 1 1 2 2
        DEF 1 3 1 3
        PQR 1 1 2 2
      

      上面产生了一个"table"类的对象。这是一个特别适合列表频率的类别。例如,一旦在这种形式中,ftable 可以用来轻松地重新排列它,如ftable(tab, row.vars = 2) 或ftable(tab, row.vars = 1:2) 其中tab 是上面的计算表。

      如果首选 data.frame,则将其转换为:

      cbind(Group = rownames(tab), as.data.frame.matrix(tab))
      

      输入 data.frame DF 在最后的注释 2 中可重复地定义。

      替代品

      虽然上面看起来是最直接的,但这里还有一些其他的不使用包的替代方案:

      1) by 对于具有相同Group 值的每组行,匿名函数创建一个标识组的data.frame,将除第一列之外的列转换为具有指示的因子水平并运行table 以获取计数。返回的"by" 列表重新排序为原始顺序,我们将rbind 全部重新组合在一起。

      do.call("rbind",
         by(DF, DF$Group, function(x) {
            data.frame(Group = x[1,1], 
                       as.list(table(factor(unlist(x[, -1]), levels = 4:1))), 
                       check.names = FALSE)
         })[unique(DF$Group)])
      

      给予:

          Group 4 3 2 1
      XYZ   XYZ 1 1 2 2
      DEF   DEF 1 3 1 3
      PQR   PQR 1 1 2 2
      

      1a) 这个稍微短一点的变体也可以。它返回一个使用行名标识组的矩阵。

      kount <- function(x) table(factor(unlist(x), levels = 4:1))
      m <- do.call("rbind", by(DF[, -1], DF$Group, kount)[unique(DF$Group)])
      

      给予:

      > m
          4 3 2 1
      XYZ 1 1 2 2
      DEF 1 3 1 3
      PQR 1 1 2 2
      

      2) 外层

      gps <- unique(DF$Group)
      levs <- 4:1
      kount2 <- function(g, lv) sum(subset(DF, Group == g)[-1] == lv, na.rm = TRUE)
      m <- outer(gps, levs, Vectorize(kount2))
      dimnames(m) <- list(gps, levs))
      

      给出这个矩阵:

      > m
          4 3 2 1
      XYZ 1 1 2 2
      DEF 1 3 1 3
      PQR 1 1 2 2
      

      3) 应用

      kount3 <- function(g) table(factor(unlist(DF[DF$Group == g, -1]), levels = 4:1))
      gps <- as.character(unique(DF$Group))
      do.call("rbind", sapply(gps, kount3, simplify = FALSE))
      

      给予:

          4 3 2 1
      XYZ 1 1 2 2
      DEF 1 3 1 3
      PQR 1 1 2 2
      

      4) 聚合

      aggregate(1:nrow(DF), DF["Group"],  function(ix) 
        table(factor(unlist(DF[ix, -1]), levels = 4:1)))[unique(DF$Group), ]
      

      给予:

        Group x.4 x.3 x.2 x.1
      3   XYZ   1   1   2   2
      1   DEF   1   3   1   3
      2   PQR   1   1   2   2
      

      5) 点按

      do.call("rbind", tapply(1:nrow(DF), DF$Group, function(ix)
             table(factor(unlist(DF[ix, -1]), levels = 4:1))))[unique(DF$Group), ]
      

      6) 重塑

      with(reshape(DF, dir = "long", varying = list(2:5)), 
        table(factor(Group, unique(DF$Group)), factor(A, 4:1)))
      

      给予:

          4 3 2 1
      XYZ 1 1 2 2
      DEF 1 3 1 3
      PQR 1 1 2 2
      

      注 1: (1a)、(2)、(3)、(5) 和 (6) 生成以组为行名的矩阵或表格结果。如果您更喜欢以 Groups 为列的数据框,那么假设 m 是矩阵,请添加以下内容:

      data.frame(Group = rownames(m), m, check.names = FALSE)
      

      注2:输入DF的可复现形式为:

      Lines <- "Group   A    B    C    D
      XYZ     4    Na   1    3
      XYZ     Na   2    2    1
      DEF     4    3    2    1
      DEF     3    3    1    1
      PQR     1    Na   Na   1
      PQR     3    2    2    4"
      DF <- read.table(text = Lines, header = TRUE, na.strings = "Na")
      

      【讨论】:

        【解决方案3】:

        我们可以使用dplyr/tidyr

        library(dplyr)
        library(tidyr)
        df1 %>% 
            mutate_each(funs(replace(., .=="Na", NA))) %>% 
            gather(Var, Val, A:D, na.rm=TRUE) %>%
            group_by(Group, Val) %>% 
            tally() %>%
            spread(Val, n)
        #    Group   `1`   `2`   `3`   `4`
        #* <chr> <int> <int> <int> <int>
        #1   DEF     3     1     3     1
        #2   PQR     2     2     1     1
        #3   XYZ     2     2     1     1
        

        【讨论】:

          猜你喜欢
          • 2015-09-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-07
          • 2015-01-21
          • 2021-12-02
          • 1970-01-01
          • 2021-07-27
          相关资源
          最近更新 更多