考虑到像经典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)
但是我想知道是否有一种更干净的方法来生成此数据集,希望无需生成中间数据集。
答案 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()