R 计算不同因素组合的行数
考虑到一个数据集,比如经典的R 计算不同因素组合的行数,r,dplyr,R,Dplyr,考虑到一个数据集,比如经典的mtcars,我想知道不同因素水平下的观察值(=行)的数量,将它们分别和一起考虑 例如,下面的代码将生成一个列N,其中包含每级气缸和档位的观察次数,但不包含单独的气缸和档位的观察次数 mtcars %>% dplyr::group_by(cyl, gear) %>% dplyr::summarise(N = n()) 我知道,对于cyl和gear,可以通过类似的方式获得单独数量的观测值,创建单独的数据帧,并将它们合并在一起。以下内容将产生预期输出: d
mtcars
,我想知道不同因素水平下的观察值(=行)的数量,将它们分别和一起考虑
例如,下面的代码将生成一个列N,其中包含每级气缸和档位的观察次数,但不包含单独的气缸和档位的观察次数
mtcars %>% dplyr::group_by(cyl, gear) %>% dplyr::summarise(N = n())
我知道,对于cyl和gear,可以通过类似的方式获得单独数量的观测值,创建单独的数据帧,并将它们合并在一起。以下内容将产生预期输出:
df <- mtcars %>% dplyr::group_by(cyl, gear) %>% dplyr::summarise(N = n())
df_gear <- mtcars %>% dplyr::group_by(gear) %>% dplyr::summarise(Ngear = n())
df_cyl <- mtcars %>% dplyr::group_by(cyl) %>% dplyr::summarise(Ncyl = n())
df %>% dplyr::left_join(df_cyl) %>% dplyr::left_join(df_gear)
df%dplyr::分组依据(气缸,档位)%>%dplyr::汇总(N=N())
df_齿轮%dplyr::分组依据(齿轮)%>%dplyr::汇总(Ngear=n())
df_cyl%dplyr::分组依据(cyl)%>%dplyr::摘要(Ncyl=n())
df%>%dplyr::左联(df\U cyl)%>%dplyr::左联(df\U齿轮)
但我想知道是否有更干净的方法来生成此数据集,希望不需要生成中间数据集。带有mutate
mtcars %>%
group_by(cyl, gear) %>%
mutate(N = n()) %>%
group_by(gear) %>%
mutate(Ngear = n()) %>%
group_by(cyl) %>%
mutate(Ncyl = n()) %>%
select(cyl, gear, N, Ngear, Ncyl) %>%
distinct()
下面是一种使用组合的方法,然后循环,获取计数,最后递归合并:
# get all combinations of columns
x1 <- c("cyl", "gear")
x2 <- do.call(c, lapply(seq_along(x1), combn, x = x1, simplify = FALSE))
# group by all combos get count, then merge list of dataframes using reduce
res <- purrr::reduce(
lapply(x2, function(i) mtcars %>%
group_by_at(i) %>%
mutate(N = n()) %>%
select_at(c(x1, "N")) %>%
unique()),
left_join, by = x1)
# prettify the columns
myNames <- paste0("N_", sapply(x2, paste, collapse = "_"))
colnames(res)[ -c(1:(ncol(res) - length(myNames))) ] <- myNames
res
# # A tibble: 8 x 5
# # Groups: cyl [3]
# cyl gear N_cyl N_gear N_cyl_gear
# <dbl> <dbl> <int> <int> <int>
# 1 6 4 7 12 4
# 2 4 4 11 12 8
# 3 6 3 7 15 2
# 4 8 3 14 15 12
# 5 4 3 11 15 1
# 6 4 5 11 5 2
# 7 8 5 14 5 2
# 8 6 5 7 5 1
#获取所有列的组合
x1%
在(c(x1,“N”))%>%
唯一(),
左_连接,通过=x1)
#美化柱子
myNames这里有一种方法可以实现这一点,依靠mutate()
和ave()
而不是groupby()
和summary()
实现紧凑性:
library(dplyr)
mtcars %>%
mutate(n = ave(cyl, cyl, gear, FUN = length),
n_cyl = ave(cyl, cyl, FUN = length),
n_gear = ave(gear, gear, FUN = length)) %>%
select(gear, cyl, n, n_cyl, n_gear) %>%
distinct()
gear cyl n n_cyl n_gear
1 4 6 4 7 12
2 4 4 8 11 12
3 3 6 2 7 15
4 3 8 12 14 15
5 3 4 1 11 15
6 5 4 2 11 5
7 5 8 2 14 5
8 5 6 1 7 5
严格来说,这不是一种tidyverse
方法,但您也可以这样做:
mtcars %>%
mutate(Ncyl = with(stack(table(cyl)), values[match(cyl, ind)]),
Ngear = with(stack(table(gear)), values[match(gear, ind)])) %>%
group_by(cyl, gear) %>%
summarise(N = n(),
Ncyl = first(Ncyl),
Ngear = first(Ngear))
cyl gear N Ncyl Ngear
<dbl> <dbl> <int> <int> <int>
1 4 3 1 11 15
2 4 4 8 11 12
3 4 5 2 11 5
4 6 3 2 7 15
5 6 4 4 7 12
6 6 5 1 7 5
7 8 3 12 14 15
8 8 5 2 14 5
mtcars%>%
变异(Ncyl=with(stack(table(cyl)),值[匹配(cyl,ind)]),
Ngear=具有(堆栈(表(档位)),值[匹配(档位,档位)])%>%
组别(气缸,档位)%>%
总结(N=N(),
Ncyl=第一个(Ncyl),
Ngear=第一(Ngear))
气缸齿轮N Ncyl Ngear
1 4 3 1 11 15
2 4 4 8 11 12
3 4 5 2 11 5
4 6 3 2 7 15
5 6 4 4 7 12
6 6 5 1 7 5
7 8 3 12 14 15
8 8 5 2 14 5
有点像黑客,但没有任何中间结构
mtcars %>%
mutate(cylgear = paste(cyl, gear)) %>%
group_by(cylgear, cyl, gear) %>%
summarise(combination = length(cylgear), Ngear = length(gear), Ncyl = length(cyl))
#> Joining, by = "cyl"
#> Joining, by = "gear"
#> # A tibble: 8 x 5
#> # Groups: cyl [3]
#> cyl gear N Ncyl Ngear
#> <dbl> <dbl> <int> <int> <int>
#> 1 4 3 1 11 15
#> 2 4 4 8 11 12
#> 3 4 5 2 11 5
#> 4 6 3 2 7 15
#> 5 6 4 4 7 12
#> 6 6 5 1 7 5
#> 7 8 3 12 14 15
#> 8 8 5 2 14 5
mtcars%>%
变异(cylgear=粘贴(cyl,齿轮))%>%
分组依据(气缸齿轮,气缸,齿轮)%>%
总结(组合=长度(圆柱齿轮),Ngear=长度(齿轮),Ncyl=长度(圆柱齿轮))
#>加入,由=“cyl”
#>连接,通过=“齿轮”
#>#A tibble:8 x 5
#>#组别:共青团[3]
#>气缸齿轮N Ncyl Ngear
#>
#> 1 4 3 1 11 15
#> 2 4 4 8 11 12
#> 3 4 5 2 11 5
#> 4 6 3 2 7 15
#> 5 6 4 4 7 12
#> 6 6 5 1 7 5
#> 7 8 3 12 14 15
#> 8 8 5 2 14 5
另一种使用NSE并创建与组长度相等的数据帧列表的方法
library(dplyr)
#Columns can be created programatically as well if needed all the combination
cols <- list('cyl', 'gear', c('cyl', 'gear'))
purrr::map(cols, ~count(mtcars, !!!syms(.x),
name = paste0('n_', paste0(.x, collapse = ''))))
#[[1]]
# A tibble: 3 x 2
# cyl n_cyl
# <dbl> <int>
#1 4 11
#2 6 7
#3 8 14
#[[2]]
# A tibble: 3 x 2
# gear n_gear
# <dbl> <int>
#1 3 15
#2 4 12
#3 5 5
#[[3]]
# A tibble: 8 x 3
# cyl gear n_cylgear
# <dbl> <dbl> <int>
#1 4 3 1
#2 4 4 8
#3 4 5 2
#4 6 3 2
#5 6 4 4
#6 6 5 1
#7 8 3 12
#8 8 5 2
库(dplyr)
#如果需要,也可以通过编程方式创建列
科尔斯:很抱歉,我不能接受这个答案,因为我期待着更干净的东西。事实上,这会调用mtcars
三次,与我发布的代码没有什么不同。你可以从df
而不是mtcars
获得df\u gear%dplyr::group\u by(gear)%%>%dplyr::summary(Ngear=sum(N))中获得df\u gear
和df\u-cyl
复制和粘贴上述代码不会复制解决方案,甚至不会复制列的名称!