R中行和列的值汇总

时间:2016-12-08 14:48:43

标签: r

我有一个看起来像的数据集:

> Combine_data <- smartbind(1st,2nd,3rd)

Error in `[<-.data.frame`(`*tmp*`, , value = list(ID = c(1001, 1001,  : 
  replacement element 1 has 143460 rows, need 143462

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

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

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

3 个答案:

答案 0 :(得分:4)

使用reshape2个包,我们可以meltdcast,如下所示,

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

答案 1 :(得分:4)

这不使用包,只是一行。这里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)sapply

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)tapply

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")

答案 2 :(得分: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