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
复制和粘贴上述代码不会复制解决方案,甚至不会复制列的名称!