在R语言中如何按行内排名将数据框的治疗天数转为顺序标签?
在R语言中按行内治疗天数排名替换为顺序标签
问题描述
现有一个包含样本列和多列治疗天数的数据框,治疗列中未接受治疗的值为NA(字符型)。需要将每行的治疗天数按从小到大排序,把最小值替换为First,次小值替换为Second,第三小值替换为Third,NA保持不变。
示例输入
df = data.frame(samples = LETTERS[1:5], Treatment_A = c(NA, "3", NA, "10", "12"), Treatment_B = c("12", NA, NA, "15", "5"), Treatment_C = c(NA, NA, "5", "8", NA))
期望输出
df_output = data.frame(samples = LETTERS[1:5], Treatment_A = c(NA, "First", NA, "Second","Second"), Treatment_B = c("First", NA, NA, "Third","First"), Treatment_C = c(NA, NA, "First", "First", NA))
解决方案
首先注意输入的治疗列是字符型,需要先转换为数值型才能进行排名计算,以下提供两种可行方法:
方法1:使用tidyverse工具链(dplyr)
library(dplyr) # 定义排名到标签的映射向量 rank_labels <- c("First", "Second", "Third") df_output <- df %>% # 将治疗列转换为数值型 mutate(across(starts_with("Treatment_"), as.numeric)) %>% # 按行处理每一条样本数据 rowwise() %>% mutate( # 提取当前行的治疗天数,计算排名(最小天数对应排名1) row_ranks = list(rank(c_across(starts_with("Treatment_")), na.last = NA, ties.method = "min")), # 将每个治疗列的排名映射为对应标签,NA保持不变 across(starts_with("Treatment_"), ~ ifelse(is.na(.), NA, rank_labels[.x])) ) %>% # 移除临时生成的row_ranks列 select(-row_ranks) %>% ungroup() # 查看最终结果 df_output
方法2:使用Base R的apply函数
# 提取治疗列并转换为数值矩阵 treat_mat <- as.matrix(df[, -1]) mode(treat_mat) <- "numeric" # 按行计算每个治疗天数的排名,忽略NA值 row_ranks <- apply(treat_mat, 1, function(x) { rank(x, na.last = NA, ties.method = "min") }) # 定义排名对应的标签 rank_labels <- c("First", "Second", "Third") # 将排名替换为对应标签,保留原始NA treat_labels <- apply(row_ranks, 2, function(x) { ifelse(is.na(x), NA, rank_labels[x]) }) # 组合样本列和处理后的治疗标签列,得到最终数据框 df_output_base <- cbind(df[, 1], as.data.frame(treat_labels)) colnames(df_output_base) <- colnames(df) # 查看最终结果 df_output_base
关键说明
ties.method = "min":确保相同天数的治疗会被赋予同一排名(即相同天数对应同一个标签)na.last = NA:计算排名时忽略NA值,原始NA会保持不变
内容的提问来源于stack exchange,提问作者DWFotos
相关产品推荐
相关产品推荐

