R语言dplyr中如何按带连字符的列正确排序数据框
你的id列是前缀-数字序号格式的字符串,dplyr::arrange()对字符串默认按字典序逐字符比对:比对到连字符后的第一位字符时,1的字符编码小于2,因此2022-10会被排在2022-2前面,属于字符串排序的正常表现,不符合自然数值排序的预期。
你之前用辅助列排序的逻辑完全正确,只是不需要额外用mutate生成永久存储的辅助列,可以直接在排序步骤内完成计算,代码更简洁,也不会产生冗余字段。
无额外依赖的base R写法
用正则直接提取连字符后的序号内容,转成数值后作为排序键,不需要加载其他扩展包,适合固定前缀-序号格式的id:library(dplyr) correct_order_df <- wrong_order_df %>% arrange(as.numeric(sub(".*-", "", id)))代码里
sub(".*-", "", id)的作用是匹配最后一个连字符及之前的所有内容,替换为空值,直接拿到连字符后的序号部分。stringr生态写法
如果你已经在tidyverse工作流里加载了stringr,可以用正则提取后缀数字,逻辑更直观:library(dplyr) library(stringr) correct_order_df <- wrong_order_df %>% arrange(as.numeric(str_extract(id, "\\d+$")))通用自然排序写法
如果id格式不固定、存在多层数字段(比如类似2022-10-3这类多级id),可以用gtools包的mixedorder()函数,自动识别字符串里的数字段按数值排序,不需要手动写提取规则:library(dplyr) library(gtools) correct_order_df <- wrong_order_df %>% arrange(mixedorder(id))
不要连续写多个arrange()步骤:后执行的arrange会完全覆盖之前的排序规则,比如你示例里的arrange(weight) %>% arrange(id),最终只会保留id的排序结果,weight的排序逻辑会失效。如果需要多字段排序(比如先按weight排序,相同weight的行再按id自然序排列),把所有排序条件写到同一个arrange()里即可:
# 先按weight升序,同weight下按id自然序排列 multi_sort_df <- df %>% arrange( weight, as.numeric(sub(".*-", "", id)) )
内容的提问来源于stack exchange,提问作者TKH_9

