我有一个看起来像的数据集:
> 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和明智地计算行数然后逐列,但这不是有效且可扩展的。我相信有更好的方法来完成这项工作。
答案 0 :(得分:4)
使用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
答案 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