使用 dplyr 对多个变量的所有可能组合进行分组
Posted
技术标签:
【中文标题】使用 dplyr 对多个变量的所有可能组合进行分组【英文标题】:Grouping Over All Possible Combinations of Several Variables With dplyr 【发布时间】:2015-05-13 13:29:11 【问题描述】:给定如下情况
library(dplyr)
myData <- tbl_df(data.frame( var1 = rnorm(100),
var2 = letters[1:3] %>%
sample(100, replace = TRUE) %>%
factor(),
var3 = LETTERS[1:3] %>%
sample(100, replace = TRUE) %>%
factor(),
var4 = month.abb[1:3] %>%
sample(100, replace = TRUE) %>%
factor()))
我想对“myData”进行分组,最终找到按 var2、var3 和 var4 的所有可能组合进行分组的汇总数据。
我可以使用
创建一个列表,其中包含所有可能的变量组合作为字符值groupNames <- names(myData)[2:4]
myGroups <- Map(combn,
list(groupNames),
seq_along(groupNames),
simplify = FALSE) %>%
unlist(recursive = FALSE)
我的计划是使用 for() 循环为每个变量组合制作单独的数据集,类似于
### This Does Not Work
for (i in 1:length(myGroups))
assign( myGroups[i]%>%
unlist() %>%
paste0(collapse = "")%>%
paste0("Data"),
myData %>%
group_by_(lapply(myGroups[[i]], as.symbol)) %>%
summarise( n = length(var1),
avgVar2 = var2 %>%
mean()))
诚然,我不太擅长列表,而且查找这个问题有点困难,因为 dpyr 更新已经改变了分组的工作方式。
如果有比单独的数据集更好的方法,我很想知道。
当我只按单个变量分组时,我得到了一个类似于上面的循环。
非常感谢任何和所有帮助!谢谢!
【问题讨论】:
我喜欢实现group_by(var1) and group_by(var2) and group_by(var1, var2)等的结果......我想把所有可能的数据分组三个变量的组合(大小为 1、2 和 3)。 对不起,这实际上很清楚,我没有仔细阅读就得出了关于您的目标的结论。 您可以使用 SAS 过程摘要轻松完成此操作。我从没想过我会打这些字。 【参考方案1】:这似乎令人费解,并且可能有一种方法可以简化或使用do
对其进行修饰,但它确实有效。使用您的myData
和myGroups
,
results = lapply(myGroups, FUN = function(x)
do.call(what = group_by_, args = c(list(myData), x)) %>%
summarise( n = length(var1),
avgVar1 = mean(var1))
)
> results[[1]]
Source: local data frame [3 x 3]
var2 n avgVar1
1 a 31 0.38929738
2 b 31 -0.07451717
3 c 38 -0.22522129
> results[[4]]
Source: local data frame [9 x 4]
Groups: var2
var2 var3 n avgVar1
1 a A 11 -0.1159160
2 a B 11 0.5663312
3 a C 9 0.7904056
4 b A 7 0.0856384
5 b B 13 0.1309756
6 b C 11 -0.4192895
7 c A 15 -0.2783099
8 c B 10 -0.1110877
9 c C 13 -0.2517602
> results[[7]]
# I won't paste them here, but it has all 27 rows, grouped by var2, var3 and var4.
我将您的 summarise
呼叫更改为平均 var1
,因为 var2
不是数字。
【讨论】:
老实说,再次感谢您。我分别计算所有这些摘要,代码变得非常长,我很难跟踪所有数据集。虽然这为我提供了解决当前问题的方法,但它确实向我展示了列表的力量,并让我意识到这是我真正的弱点。 很好的答案。我会在最后打一个do.call(plyr::rbind.fill,results)
很好的答案,另一种方法是使用 .dots
参数而不是 do.call
,例如lapply(myGroups, function(g) group_by_(myData, .dots = as.list(g)) %>% ...)
另一种选择是使用group_by_at()
与one_of()
组合,将过滤器的字符向量传递给它。见***.com/questions/21208801/…【参考方案2】:
我根据@Gregor 的回答和随后的 cmets 创建了一个函数:
library(magrittr)
myData <- tbl_df(data.frame( var1 = rnorm(100),
var2 = letters[1:3] %>%
sample(100, replace = TRUE) %>%
factor(),
var3 = LETTERS[1:3] %>%
sample(100, replace = TRUE) %>%
factor(),
var4 = month.abb[1:3] %>%
sample(100, replace = TRUE) %>%
factor()))
函数combSummarise
combSummarise <- function(data, variables=..., summarise=...)
# Get all different combinations of selected variables (credit to @Michael)
myGroups <- lapply(seq_along(variables), function(x)
combn(c(variables), x, simplify = FALSE)) %>%
unlist(recursive = FALSE)
# Group by selected variables (credit to @konvas)
df <- eval(parse(text=paste("lapply(myGroups, function(x)
dplyr::group_by_(data, .dots=x) %>%
dplyr::summarize_( \"", paste(summarise, collapse="\",\""),"\"))"))) %>%
do.call(plyr::rbind.fill,.)
groupNames <- c(myGroups[[length(myGroups)]])
newNames <- names(df)[!(names(df) %in% groupNames)]
df <- cbind(df[, groupNames], df[, newNames])
names(df) <- c(groupNames, newNames)
df
拨打combSummarise
combSummarise (myData, var=c("var2", "var3", "var4"),
summarise=c("length(var1)", "mean(var1)", "max(var1)"))
或
combSummarise (myData, var=c("var2", "var4"),
summarise=c("length(var1)", "mean(var1)", "max(var1)"))
或
combSummarise (myData, var=c("var2", "var4"),
summarise=c("length(var1)"))
等
【讨论】:
【参考方案3】:受到 Gregor 和 dimitris_ps 答案的启发,我编写了一个 dplyr 风格的函数,该函数对组变量的所有组合运行汇总。
summarise_combo <- function(data, ...)
groupVars <- group_vars(data) %>% map(as.name)
groupCombos <- map( 0:length(groupVars), ~combn(groupVars, ., simplify=FALSE) ) %>%
unlist(recursive = FALSE)
results <- groupCombos %>%
map(function(x) data %>% group_by(!!! x) %>% summarise(...) ) %>%
bind_rows()
results %>% select(!!! groupVars, everything())
例子
library(tidyverse)
mtcars %>% group_by(cyl, vs) %>% summarise_combo(cyl_n = n(), mean(mpg))
【讨论】:
【参考方案4】:使用unite新建列是最简单的方法
library(tidyverse)
df = tibble(
a = c(1,1,2,2,1,1,2,2),
b = c(3,4,3,4,3,4,3,4),
val = c(1,2,3,4,5,6,7,8)
)
print(df)#output1
df_2 = unite(df, 'combined_header', a, b, sep='_', remove=FALSE) #remove=F doesn't remove existing columns
print(df_2)#output2
df_2 %>% group_by(combined_header) %>%
summarize(avg_val=mean(val)) %>% print()#output3
#avg 1_3 = mean(1,5)=3 avg 1_4 = mean(2, 6) = 4
结果
Output:
output1
a b val
<dbl> <dbl> <dbl>
1 1 3 1
2 1 4 2
3 2 3 3
4 2 4 4
5 1 3 5
6 1 4 6
7 2 3 7
8 2 4 8
output2
combined_header a b val
<chr> <dbl> <dbl> <dbl>
1 1_3 1 3 1
2 1_4 1 4 2
3 2_3 2 3 3
4 2_4 2 4 4
5 1_3 1 3 5
6 1_4 1 4 6
7 2_3 2 3 7
8 2_4 2 4 8
output3
combined_header avg_val
<chr> <dbl>
1 1_3 3
2 1_4 4
3 2_3 5
4 2_4 6
【讨论】:
以上是关于使用 dplyr 对多个变量的所有可能组合进行分组的主要内容,如果未能解决你的问题,请参考以下文章
使用 dplyr 嵌套或分组两个变量,然后对数据执行 Cronbach 的 alpha 函数或其他统计
(更新)R语言 dplyr的group与summarise的使用
dplyr summarise :在循环中按多个变量分组并将结果添加到同一数据框中
pandas使用groupby函数基于指定分组变量对dataframe数据进行分组使用get_group函数获取指定分组变量的具体分类值下的所有样本(获取的是多个分组中的其中一个分组的内容)
pandas使用groupby函数进行分组聚合并使用agg函数将每个分组特定变量对应的多个内容组合到一起输出(merging content within a specific column of g