[英]Summary of values across rows and columns in R
我有一個看起來像這樣的數據集:
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並獲取計數來完成此操作行方式然后列方式,但這不是有效和可擴展的。 我相信有更好的方法來完成這項工作。
使用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
這不使用包,只是一行。 這里DF$Group[row(DF[-1])]
是一個Group標簽向量,這樣每個元素對應於unlist(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
值的每組行,匿名函數創建一個標識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")
我們可以使用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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.