从docendo discimus's answer继续:
library(dplyr)
# library(tidyr)
df %>%
count(a, b) %>%
group_by(a) %>%
filter(n == max(n)) %>%
mutate(r = row_number()) %>%
tidyr::spread(r, b) %>%
select(-n)
# # A tibble: 3 x 3
# # Groups: a [3]
# a `1` `2`
# <fct> <fct> <fct>
# 1 1 A <NA>
# 2 2 B <NA>
# 3 3 A B
然后你只需要重命名列。
基础 R 变体:
reshape(do.call(rbind.data.frame, by(df, df$a, function(x) {
tb <- table(x$b)
tb <- tb[ tb == max(tb) ]
data.frame(a = x$a[1], b = names(tb), r = seq_along(tb))
})), timevar = "r", idvar = "a", direction = "wide")
# a b.1 b.2
# 1 1 A <NA>
# 2 2 B <NA>
# 3.1 3 A B
我会分解它,因为不是所有的都可能是直观的:
by 函数返回一个list(经过特殊格式化,但仍然只是一个列表)。如果我们查看a 的单个实例,让我们探索会发生什么。我会跳到a == "3",因为那是有重复的:
by(df, df$a, function(x) { browser(); 1; })
# Called from: FUN(data[x, , drop = FALSE], ...)
# Browse[1]>
debug at #1: [1] 1
# Browse[2]>
Called from: FUN(data[x, , drop = FALSE], ...)
# Browse[1]>
debug at #1: [1] 1
# Browse[2]>
Called from: FUN(data[x, , drop = FALSE], ...)
# Browse[1]>
debug at #1: [1] 1
# Browse[2]>
x
# a b
# 3 3 A
# 6 3 B
# 9 3 A
# 12 3 B
# Browse[2]>
( tb <- table(x$b) )
# A B
# 2 2
好的,所以我们现在有了每个b 的计数。意识到这里可能很容易有更多,比如说:
# A B C
# 2 2 1
所以我将把这个命名向量减少为那些具有最高值的向量:
# Browse[2]>
( tb <- tb[ tb == max(tb) ] ) # no change here, but had there been a third value in 'b' ...
# A B
# 2 2
最后,我们希望by 捕获data.frame(我们稍后可以合并)。我们保证a 是一个可能重复的值,所以a[1];我们确保names(tb) 具有所有“有趣”的值,并且r 是reshape 的助手,稍后:
# Browse[2]>
data.frame(a = x$a[1], b = names(tb), r = seq_along(tb))
# a b r
# 1 3 A 1
# 2 3 B 2
既然我们在内部进行了探索,让我们总结一下。
by(df, df$a, function(x) {
tb <- table(x$b)
tb <- tb[ tb == max(tb) ]
data.frame(a = x$a[1], b = names(tb), r = seq_along(tb))
})
# df$a: 1
# a b r
# 1 1 A 1
# ------------------------------------------------------------
# df$a: 2
# a b r
# 1 2 B 1
# ------------------------------------------------------------
# df$a: 3
# a b r
# 1 3 A 1
# 2 3 B 2
这看起来很别扭,但如果您深入了解(使用dput),您会发现它只是重新分类的list。我们现在可以将它们组合成一个框架:
do.call(rbind.data.frame, by(df, df$a, function(x) {
tb <- table(x$b)
tb <- tb[ tb == max(tb) ]
data.frame(a = x$a[1], b = names(tb), r = seq_along(tb))
}))
# a b r
# 1 1 A 1
# 2 2 B 1
# 3.1 3 A 1
# 3.2 3 B 2
顺便说一句:对于data.frame 和rbind.data.frame,这些默认情况下都会为您提供factors。如果你不想要它们,那么:
do.call(rbind.data.frame, c(by(df, df$a, function(x) {
tb <- table(x$b)
tb <- tb[ tb == max(tb) ]
data.frame(a = x$a[1], b = names(tb), r = seq_along(tb),
stringsAsFactors = FALSE)
}), stringsAsFactors=FALSE))
# a b r
# 1 1 A 1
# 2 2 B 1
# 3.1 3 A 1
# 3.2 3 B 2
然后是重塑。我承认这是其中最脆弱的部分(至少对我而言)。我不是reshape 用户,我倾向于tidyr::spread 或data.table::dcast,但这是base-R 并且现在可以使用。 reshape 的使用本身就是一个教程,所以我不会在这里详细介绍。有许多尝试提供对用户更友好的重塑工具(reshape2、tidyr、data.table 都在脑海中浮现,但不太可能是唯一的)。