计算不同因素组合的行数

时间:2020-01-31 12:02:31

标签: r dplyr

考虑到像经典mtcars这样的数据集,我想知道按不同水平的因素将观察数(=行数)分开或同时考虑的情况。

例如,以下代码将生成N列,其中包含每级气缸和齿轮的观测值数量,而不是分别针对气缸和齿轮的观测值数量。

mtcars %>% dplyr::group_by(cyl, gear) %>% dplyr::summarise(N = n()) 

我知道可以以类似的方式获得圆柱体和齿轮的单独观察值,创建单独的数据框,并将它们合并在一起。以下将产生预期的输出:

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)

但是我想知道是否有一种更干净的方法来生成此数据集,希望无需生成中间数据集。

6 个答案:

答案 0 :(得分:5)

这里是您可能会采用的一种方法,它依靠mutate()ave()而不是group_by()summarise()来实现紧凑性:

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

答案 1 :(得分:3)

有点黑,但没有任何中间结构。

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

答案 2 :(得分:2)

这是一种使用组合的方法,然后循环遍历,获取计数并最终递归合并:

# 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

答案 3 :(得分:1)

严格来讲,不是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

答案 4 :(得分:1)

使用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

答案 5 :(得分:0)

带有变异

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()

相关问题