You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

对称tibble重排序:如何用tidyverse对齐首列值与列名顺序

问题描述

我希望将输出结果的首列值(本质为行名)与其余列的列名顺序保持一致,此前找到的两种解决方案在自定义函数中均无法生效,请问是否有对应的tidyverse方案可以解决该问题?

原有代码

foo <- function(data, study_id, ...){

   study_id <- rlang::ensym(study_id)
   cat_mod <- rlang::ensyms(...)
   purrr::map(cat_mod,  ~ {

   studies_cats <- 
     data %>%
     dplyr::group_by(!!study_id, !!.x) %>%
     dplyr::summarise(effects = n(), .groups = 'drop')
     nm1 <- rlang::as_string(.x)
     cat_names <- paste0(nm1, c(".x", ".y"))
    studies_cats <- 
      studies_cats %>%
      dplyr::inner_join(studies_cats, by = rlang::as_string(study_id)) %>%
      dplyr::group_by(!!!rlang::syms(cat_names)) %>%
      dplyr::summarise(
        studies = n(),
        effects = sum(effects.x), .groups = 'drop') %>% 
      dplyr::mutate(n = paste0(studies, " (", effects, ")") )

    studies_cats %>%
      dplyr::select(-studies, -effects) %>%
      tidyr::pivot_wider(names_from = cat_names[2], values_from = n) %>%
      dplyr::rename_with(~nm1,  cat_names[1]) })}

# 使用示例(可以看到列名顺序为`0,1,10,2,3`,但首列值顺序为`0,1,2,3,10`,二者不一致)
d <- read.csv("https://raw.githubusercontent.com/rnorouzian/s/main/w7_smd_raw.csv")
foo(d, study, error.type)

# 原输出结果:
#  error.type `0`      `1`      `10`   `2`    `3`   
#  <fct>      <chr>    <chr>    <chr>  <chr>  <chr> 
#1 0          27 (189) 1 (6)    1 (2)  NA     NA    
#2 1          1 (18)   16 (118) 2 (10) 2 (6)  2 (6) 
#3 2          NA       2 (6)    NA     6 (33) 2 (6) 
#4 3          NA       2 (6)    NA     2 (6)  5 (27)
#5 10         1 (2)    2 (22)   6 (48) NA     NA   
解决方案

出现顺序不一致的核心原因是列名和首列值默认按字符规则排序,数值10的字符排序会排在2之前,只需要在原函数末尾新增3行代码,统一列和行的排序规则即可,修改后的完整函数如下:

foo <- function(data, study_id, ...){

   study_id <- rlang::ensym(study_id)
   cat_mod <- rlang::ensyms(...)
   purrr::map(cat_mod,  ~ {

   studies_cats <- 
     data %>%
     dplyr::group_by(!!study_id, !!.x) %>%
     dplyr::summarise(effects = n(), .groups = 'drop')
     nm1 <- rlang::as_string(.x)
     cat_names <- paste0(nm1, c(".x", ".y"))
    studies_cats <- 
      studies_cats %>%
      dplyr::inner_join(studies_cats, by = rlang::as_string(study_id)) %>%
      dplyr::group_by(!!!rlang::syms(cat_names)) %>%
      dplyr::summarise(
        studies = n(),
        effects = sum(effects.x), .groups = 'drop') %>% 
      dplyr::mutate(n = paste0(studies, " (", effects, ")") )

    studies_cats %>%
      dplyr::select(-studies, -effects) %>%
      tidyr::pivot_wider(names_from = cat_names[2], values_from = n) %>%
      dplyr::rename_with(~nm1,  cat_names[1]) %>%
      # 按数值顺序调整列的排列顺序
      dplyr::relocate(!!nm1, all_of(sort(as.numeric(colnames(.)[-1])))) %>%
      # 将首列转换为有序因子,层级和列名顺序保持一致
      dplyr::mutate(!!nm1 := factor(!!rlang::sym(nm1), levels = sort(as.numeric(colnames(.)[-1])))) %>%
      # 按首列顺序排序行
      dplyr::arrange(!!rlang::sym(nm1))
   })
}

测试效果

运行测试代码后输出结果如下,列顺序和首列值顺序均为0,1,2,3,10,符合预期:

#  error.type `0`      `1`      `2`    `3`    `10`   
#  <fct>      <chr>    <chr>    <chr>  <chr>  <chr> 
#1 0          27 (189) 1 (6)    NA     NA     1 (2)    
#2 1          1 (18)   16 (118) 2 (6)  2 (6)  2 (10) 
#3 2          NA       2 (6)    6 (33) 2 (6)  NA
#4 3          NA       2 (6)    2 (6)  5 (27) NA
#5 10         1 (2)    2 (22)   NA     NA     6 (48) 

内容的提问来源于stack exchange,提问作者rnorouzian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 04:00:04