如何基于指定行的列值重新排列R语言数据框的多列?
按数据框最后一行数值排序列(含dplyr实现方案)
问题描述
需要重新排列数据框的列:保留id列在前,其余字母命名的数值型列按最后一行的数值排序。示例数据如下:
df <- data.frame(id = c("q", "w", "e", "t", "d", "r"), A=c(22, 25, 29, 13, 22, -8), B=c(12, 10, 6, 6, 8, 11), C=c(NA, 15, 15, 18, 22, 13), D=c(90, 4, 3, 6, -6, -6))
理想输出列顺序为:id、A、D、B、C。但尝试以下代码时得到了错误的列顺序D、A、B、C、id:
neworder <- order(unlist(df[nrow(df),])) df[, neworder]
补充要求:仅对最后一行值为数值型的字母命名列排序,排除字符型的id列。
问题原因
原代码的问题在于:
- 把
id列也纳入了排序范围,字符型的r在排序时会被默认排在所有数值之后; - 最后一行中
A的值是-8,D的值是-6,升序排序时A本应在D前,你得到的反转结果可能是误操作(比如用了降序order(..., decreasing = TRUE)),但核心问题是未排除非目标列。
解决方案
1. Base R 实现
# 筛选出需要排序的数值型列(排除id) cols_to_sort <- names(df)[sapply(df[nrow(df), ], is.numeric)] # 提取最后一行的对应值并排序列名 sorted_cols <- cols_to_sort[order(unlist(df[nrow(df), cols_to_sort]))] # 重新排列数据框 df_sorted <- df[, c("id", sorted_cols)]
2. dplyr 实现
无需转置数据框,直接通过select结合列名排序即可:
library(dplyr) df_sorted <- df %>% # 先保留id列,再按最后一行数值排序其余数值型列 select( id, all_of( # 获取除id外的数值型列名 names(.) %>% setdiff("id") %>% # 按最后一行的对应值排序列名 .[order(slice(., n()) %>% select(all_of(.)) %>% pull())] ) )
执行后得到的df_sorted列顺序为id、A、D、B、C,符合需求。
内容的提问来源于stack exchange,提问作者bee
相关产品推荐
相关产品推荐

