我所拥有的:

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

关键是传递给count()的变量(在本例中为cylgear)不是固定的,而且变量的数量可以从1向上变化.它们将作为参数传递给更广泛的函数.因此,我正在寻找一个解决方案,将工作很好的curly-curly或类似.变量的名称没有遵循任何模式.

我曾考虑过使用多个调用tidyr::pivot_longer(),但我不能计算出这将如何工作与不同数量的变量.

我认为一个更好的方法可能是在使用dplyr::cur_column()的同时使用dplyr::across().类似于下面的伪代码:

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的解决方案,但所有的建议都是最受欢迎的.谢谢大家!

推荐答案

正如你已经猜到的,我会go acrosscur_column和一些更名.第一步,我创建categoryvariable列,然后删除原始列.之后,我用rename_withstring::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

UPDATE,感谢@lotus的 comments ,我们可以使函数更简洁,使用.keep="unused".before=1go 掉select,并通过在across()中重命名go 掉rename_with:

var_count <- function(.data, ...) {
  .data |>
    count(...) |>
    mutate(
      across(-n, list(
        variable = ~ cur_column(),
        category = ~.x
      ),
      .names = "{.fn}{(seq_along(.col) + 1) %/% 2}"
      ),
      .keep = "unused",
      .before = 1
    )
}

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

R相关问答推荐

使用scale_x_continuous复制ggplot 2中的离散x轴

如何使用stat_extract_all正确提取我的目标值?

从开始时间和结束时间导出时间

当两个图层映射到相同的美学时,隐藏一个图层的图例值

使用geom_segment()对y轴排序

未识别时区

R中的哈密顿滤波

您是否可以折叠R中的重复行,同时保留基于所选列的值?

仅 Select 超过9行的CSV文件

从圆到R中的多边形的标绘雷达图

为什么在BASE R中绘制线条时会看到线上的点?

将标识符赋给事件序列,避免错误观察

R中Gamma回归模型均方误差的两种计算方法不一致

计算Mean by分组和绑定到R中的数据集

使用ifElse语句在ggploy中设置aes y值

我正在try 创建一个接近cos(X)的值的While循环,以便它在-或+1-E10范围内

R try Catch in the loop-跳过缺少的值并创建一个DF,显示跳过的内容

如果满足条件,则替换列的前一个值和后续值

如何在R中创建这些列?

按顺序将地块添加到列表