如何按字符长度对数据框行内值排序?含日期二次排序需求
R数据框按行列字符长度排序(含日期排序)
示例数据
df1 <- structure(list(V1 = c("00094", "00002", "00005", "00006", "00009", "00010", "00012", "00013", "00015", "00017"), V2 = c(NA, NA, NA, "2021-05-03", "2021-04-28", "Mentioned in T4 CRF", NA, "2022-10-10", "Mentioned in B1 CRF", "2022-07-14 w/ PCR-test"), V3 = c(NA, NA, NA, NA, "2022-07-12", "Antigen test, T4 CRF", NA, NA, NA, NA), V4 = c(NA, NA, NA, NA, "2022-06-15", "2022-02-28", NA, NA, NA, NA), V5 = c(NA, NA, NA, NA, NA, "Mentioned in B0 CRF", NA, NA, NA, NA), V6 = rep(NA_character_, 10), V7 = rep(NA_character_, 10)), row.names = c(NA, 10L), class = "data.frame")
解决方案
可以通过自定义逐行处理函数,实现保持V1列在首位,其余列按行内字符长度升序排序,同时对长度为10的日期字符串按时间从旧到新排序。
1. 定义排序函数
sort_row_cols <- function(row) { # 保留V1列值 v1_val <- row["V1"] # 提取除V1外的其他列 rest_cols <- row[-which(names(row) == "V1")] # 筛选非NA值对应的列 non_na_cols <- rest_cols[!is.na(rest_cols)] if (length(non_na_cols) == 0) { return(row) } # 计算字符长度 char_lengths <- nchar(non_na_cols) # 转换长度为10的字符串为日期(非法格式返回NA) date_vals <- ifelse(char_lengths == 10, as.Date(non_na_cols), NA) # 构建排序依据:长度升序 → 日期升序 → 列名升序 sort_df <- data.frame( col_name = names(non_na_cols), length = char_lengths, date = date_vals, stringsAsFactors = FALSE ) sort_df <- sort_df[order(sort_df$length, sort_df$date, sort_df$col_name), ] # 生成最终列顺序:V1 + 排序后的非NA列 + 剩余NA列 sorted_col_order <- c("V1", sort_df$col_name, setdiff(names(rest_cols), sort_df$col_name)) return(row[sorted_col_order]) }
2. 应用函数到整个数据框
# 逐行处理后转置,转为字符型数据框 sorted_df <- as.data.frame(t(apply(df1, 1, sort_row_cols)), stringsAsFactors = FALSE)
3. 验证结果
查看第6行(V1为00010)的排序结果:
sorted_df[6, ]
输出符合预期:V1在首位,接着是V4(长度10,日期最早),然后是V2、V5(长度19),最后是V3(长度20),剩余NA列排在末尾。
注意事项
- 该方案默认长度为10的字符串是合法的
YYYY-MM-DD格式日期,若存在非法格式,会被排在同长度日期的后面 - 同长度非日期列按列名升序排序,可根据需求调整
order函数内的排序依据 - 超大型数据框可改用
data.table的逐行处理逻辑提升效率
内容的提问来源于stack exchange,提问作者Debbie Oomen
相关产品推荐
相关产品推荐

