我有:
library("dplyr")
mtcars %>% count(cyl, gear)
#> cyl gear n
#> 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
我需要什么:
#> variable1 category1 variable2 category2 n
#> 1 cyl 4 gear 3 1
#> 2 cyl 4 gear 4 8
#> 3 cyl 4 gear 5 2
#> 4 cyl 6 gear 3 2
#> 5 cyl 6 gear 4 4
#> 6 cyl 6 gear 5 1
#> 7 cyl 8 gear 3 12
#> 8 cyl 8 gear 5 2
问题是传递给
cyl
的变量(本例中为 gear
和 count()
)不是固定的,而且变量的数量可以从 1 到 1 不等。它们将作为参数传递给更广泛的函数。因此,我正在寻找一种可以与 curly-curly
或类似的解决方案很好地配合的解决方案。变量的名称没有任何模式。
我已经考虑过多次调用
tidyr::pivot_longer()
,但我无法弄清楚这如何处理不同数量的变量。
我认为更好的方法可能是将
dplyr::across()
与 dplyr::cur_column()
一起使用。类似于下面的伪代码:
var_count <- function(cnt_var) {
mtcars %>%
count(across({{ cnt_var }})) %>% # this works as intended
mutate(across({{ cnt_var }}, \(col) cur_column(), .names = "category")) %>% # an attempt to create the 'variable' names. doesn't work when length(cnt_var) > 1
rename_with(.cols = {{ cnt_var }}, .fn = "category") # a thought about how to create the 'category' columns
}
var_count(cnt_var = c(cyl)) # this ideally should produce one name-value pair: variable1 and category1
var_count(cnt_var = c(cyl, gear)) # this should produce two pairs: variable1, category1, variable2, category2
var_count(cnt_var = c(cyl, gear, vs)) # this should produce three pairs, etc
我理想地想要一个
tidyverse
解决方案,但欢迎所有建议。谢谢各位!
正如您已经猜到的那样,我会选择
across
、cur_column
和一些重命名。第一步,我创建 category
和 variable
列,然后删除原始列。之后我使用 rename_with
和 string::str_replace
将列名后缀替换为数字后缀:
library(dplyr, warn = FALSE)
library(stringr)
mtcars %>%
count(cyl, gear) |>
mutate(
across(-n, list(
variable = ~ cur_column(),
category = ~.x
),
.names = "{.fn}_{.col}"
)
) |>
select(matches("^(category|variable)"), n) |>
rename_with(
~ stringr::str_replace(.x, "_.*$", \(x) as.numeric(factor(x))),
.cols = -n
)
#> variable1 category1 variable2 category2 n
#> 1 cyl 4 gear 3 1
#> 2 cyl 4 gear 4 8
#> 3 cyl 4 gear 5 2
#> 4 cyl 6 gear 3 2
#> 5 cyl 6 gear 4 4
#> 6 cyl 6 gear 5 1
#> 7 cyl 8 gear 3 12
#> 8 cyl 8 gear 5 2
var_count <- function(.data, ...) {
.data |>
count(...) |>
mutate(
across(-n, list(
variable = ~ cur_column(),
category = ~.x
),
.names = "{.fn}_{.col}"
)
) |>
select(matches("^(category|variable)"), n) |>
rename_with(
~ stringr::str_replace(.x, "_.*$", \(x) as.numeric(factor(x))),
.cols = -n
)
}
var_count(mtcars, cyl)
#> variable1 category1 n
#> 1 cyl 4 11
#> 2 cyl 6 7
#> 3 cyl 8 14
var_count(mtcars, cyl, gear)
#> variable1 category1 variable2 category2 n
#> 1 cyl 4 gear 3 1
#> 2 cyl 4 gear 4 8
#> 3 cyl 4 gear 5 2
#> 4 cyl 6 gear 3 2
#> 5 cyl 6 gear 4 4
#> 6 cyl 6 gear 5 1
#> 7 cyl 8 gear 3 12
#> 8 cyl 8 gear 5 2
var_count(mtcars, cyl, gear, vs)
#> variable1 category1 variable2 category2 variable3 category3 n
#> 1 cyl 4 gear 3 vs 1 1
#> 2 cyl 4 gear 4 vs 1 8
#> 3 cyl 4 gear 5 vs 0 1
#> 4 cyl 4 gear 5 vs 1 1
#> 5 cyl 6 gear 3 vs 1 2
#> 6 cyl 6 gear 4 vs 0 2
#> 7 cyl 6 gear 4 vs 1 2
#> 8 cyl 6 gear 5 vs 0 1
#> 9 cyl 8 gear 3 vs 0 12
#> 10 cyl 8 gear 5 vs 0 2