Резюме / Агрегировать в R без снижения уровней
Я хотел бы суммировать или агрегировать таблицы, не опуская пустых уровней. Интересно, есть ли у кого-нибудь идеи по этому поводу?
В качестве примера вот фрейм данных
df1<-data.frame(Method=c(rep("A",3),rep("B",2),rep("C",4)),
Type=c("Fast","Fast","Medium","Fast","Slow","Fast","Medium","Slow","Slow"),
Measure=c(1,1,2,1,3,1,1,2,2))
Два подхода с использованием базы и doBy
пакет.
#base
aggregate(Measure~Method+Type,data=df1,FUN=length)
require(doBy)
summaryBy(Measure~Method+Type,data=df1,FUN=length)
Они оба дают одинаковые результаты, отсортированные по-разному, но проблема в том, что я хотел бы, чтобы все комбинации метода и типа и отсутствующие меры были вставлены как NA. Или все уровни обоих моих факторов должны быть сохранены.
df1$Type
df1$Method
Может быть plyr
есть что-то, но я не знаю, как это работает.
5 ответов
Спасибо за ваши ответы. Я думаю, что все они работают, чтобы дать результат. Но комментарий Марка Хекманна с этим кодом
ddply(df1, .(Method, Type), summarise, Measure=length(Measure), .drop=F)
кажется, дает хороший чистый выходной фрейм данных с хорошим заголовком и с минимальным кодом. С другой стороны, он нуждается в дополнительном пакете.
Посмотри на tapply
:
with(df1, tapply(Measure, list(Method, Type), FUN = length))
# Fast Medium Slow
# A 2 1 NA
# B 1 NA 1
# C 1 1 2
Обновление на 2021 год
Я думаю, что теперь это можно сделать с помощью
stats::aggregate()
с использованием
drop = FALSE
. Никаких дополнительных пакетов не требуется. Результатом является обычный старый фрейм данных, в котором пустые уровни
NA
.
aggregate(Measure ~ Method + Type, data = df1, FUN = length, drop = FALSE)
Method Type Measure
1 A Fast 2
2 B Fast 1
3 C Fast 1
4 A Medium 1
5 B Medium NA
6 C Medium 1
7 A Slow NA
8 B Slow 1
9 C Slow 2
Вы могли бы попробовать by()
в базе Р. Например,
tab <- with(df1, by(df1, list(Method = Method, Type = Type), FUN = length))
Method: A
Type: Fast
[1] 2
------------------------------------------------------------
Method: B
Type: Fast
[1] 1
------------------------------------------------------------
Method: C
Type: Fast
[1] 1
------------------------------------------------------------
Method: A
Type: Medium
[1] 1
------------------------------------------------------------
Method: B
Type: Medium
[1] NA
------------------------------------------------------------
Method: C
Type: Medium
[1] 1
------------------------------------------------------------
Method: A
Type: Slow
[1] NA
------------------------------------------------------------
....
Обратите внимание, что это просто print()
метод, заставляющий это выглядеть сложным. Если мы unclass()
tab
мы видим, что в данном случае это просто многопоточная таблица:
R> unclass(tab)
Type
Method Fast Medium Slow
A 2 1 NA
B 1 NA 1
C 1 1 2
attr(,"call")
by.data.frame(data = df1, INDICES = list(Method = Method, Type = Type),
FUN = nrow)
и вы можете работать с этим, так как это просто массив (матрица). И если вы предпочитаете это в длинном формате, вы можете легко раскрутить его:
nr <- nrow(tab)
ltab <- cbind.data.frame(Method = rep(rownames(tab), times = nr),
Type = rep(colnames(tab), each = nr),
Count = c(tab))
ltab
R> ltab
Method Type Count
1 A Fast 2
2 B Fast 1
3 C Fast 1
4 A Medium 1
5 B Medium NA
6 C Medium 1
7 A Slow NA
8 B Slow 1
9 C Slow 2
В базе R, by
вернет результат для пропущенных значений.
result <- by(df1, INDICES=list(df1$Method, df1$Type), FUN=nrow)
cbind(expand.grid(attributes(result)$dimnames), as.vector(result))
# Var1 Var2 as.vector(result)
# 1 A Fast 2
# 2 B Fast 1
# 3 C Fast 1
# 4 A Medium 1
# 5 B Medium NA
# 6 C Medium 1
# 7 A Slow NA
# 8 B Slow 1
# 9 C Slow 2