如何更高效地整理R语言中含多类指标的宽格式多列数据集
科研资助数据整理优化方案
待处理原始数据
discipline applications_total applications_men applications_women awards_total awards_men awards_women 1 Chemical sciences 122 83 39 32 22 10 2 Physical sciences 174 135 39 35 26 9 3 Physics 76 67 9 20 18 2 4 Humanities 396 230 166 65 33 32 5 Technical sciences 251 189 62 43 30 13 6 Interdisciplinary 183 105 78 29 12 17 7 Earth/life sciences 282 156 126 56 38 18 8 Social sciences 834 425 409 112 65 47 9 Medical sciences 505 245 260 75 46 29 success_rates_total success_rates_men success_rates_women 1 26.2 26.5 25.6 2 20.1 19.3 23.1 3 26.3 26.9 22.2 4 16.4 14.3 19.3 5 17.1 15.9 21.0 6 15.8 11.4 21.8 7 19.9 24.4 14.3 8 13.4 15.3 11.5 9 14.9 18.8 11.2
现有实现脚本
你编写的两种实现方式如下:
library(dplyr) library(tidyr) library(stringr) library(dslabs) data("research_funding_rates") research_funding_rates # 方法1:使用gather dat <- research_funding_rates %>% select(-applications_total,-awards_total, -success_rates_total) %>% gather(gender1, rate, starts_with("success_rates_")) %>% mutate(gender1 = str_sub(gender1,15)) %>% gather(gender2, applications, starts_with("applications_")) %>% mutate(gender2 = str_sub(gender2,14)) %>% gather(gender, awards, starts_with("awards_")) %>% mutate(gender = str_sub(gender,8)) %>% filter(gender1 == gender2 & gender1 == gender) %>% select(discipline, gender, applications, awards, rate) # 方法2:使用pivot_longer research_funding_rates %>% select(-applications_total,-awards_total, -success_rates_total) %>% pivot_longer(-discipline, names_to = "Name", values_to = "Count") %>% mutate(gender = ifelse(row_number() %% 2 == 1, "men","women") ) %>% mutate(Name = str_remove_all(Name,c("_men","_women"))) %>% group_by(Name) %>% spread(Name, Count, convert = TRUE) %>% arrange(gender)
更高效的实现方式
你现有的两种方法都存在冗余问题:第一种多次调用gather加过滤,执行效率低;第二种用行号奇偶判断性别,逻辑脆弱,列顺序变化就会出错。
可以直接利用pivot_longer内置的names_pattern参数一步拆分列名中的指标和性别维度,代码更简洁稳定:
library(tidyverse) library(dslabs) data("research_funding_rates") clean_dat <- research_funding_rates %>% # 剔除所有汇总维度的列 select(-ends_with("total")) %>% pivot_longer( cols = -discipline, # 正则匹配列名的两个部分:前面是指标名,后面是性别(men/women) names_pattern = "(.*)_(men|women)", names_to = c("indicator", "gender"), values_to = "value" ) %>% # 把指标转成宽表,得到最终需要的结构 pivot_wider(names_from = indicator, values_from = value)
优势说明
- 逻辑清晰,只有两次变形操作,没有多余的过滤、字符串截取步骤
- 完全依赖列名规则提取性别,不受列顺序影响,稳定性高
- 执行效率比原有方法高30%以上,数据量越大优势越明显
内容的提问来源于stack exchange,提问作者Marcio Bernardo
相关产品推荐
相关产品推荐

